Codebase list sugar-read-activity / lintian-fixes/main readdb.py
lintian-fixes/main

Tree @lintian-fixes/main (Download .tar.gz)

readdb.py @lintian-fixes/main

df433a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ac6ac17
 
aa5534a
ce69715
ac6ac17
 
c411b44
f52fc31
ac6ac17
c411b44
5093d7f
ac6ac17
 
 
 
 
09a7e07
98e358b
 
 
 
 
9d9af35
98e358b
 
 
9d9af35
98e358b
82c7e06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98e358b
 
9d9af35
98e358b
 
563347f
98e358b
60f7d7d
 
aa5534a
98e358b
 
 
 
 
 
 
 
 
 
 
09a7e07
aa5534a
 
60f7d7d
 
aa5534a
 
 
c411b44
 
60f7d7d
 
c411b44
 
 
 
 
 
 
f52fc31
c411b44
60f7d7d
09a7e07
98e358b
c411b44
c3b22d8
ce69715
98e358b
ce69715
60f7d7d
ce69715
ac6ac17
aa5534a
c411b44
aa5534a
72b4af8
851a69a
ac6ac17
 
230f691
aa5534a
 
5093d7f
be6e23e
563347f
f480766
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851a69a
c411b44
f480766
ac6ac17
 
60f7d7d
 
 
 
ac6ac17
563347f
ac6ac17
f52fc31
 
563347f
ac6ac17
 
c411b44
aa5534a
60f7d7d
 
ac6ac17
c411b44
ac6ac17
c411b44
 
 
 
 
60f7d7d
 
c411b44
 
 
 
 
60f7d7d
 
c411b44
 
 
 
60f7d7d
 
 
c411b44
 
 
ac6ac17
 
aa5534a
 
60f7d7d
 
 
ac6ac17
c076bb8
ac6ac17
c411b44
 
 
 
563347f
ac6ac17
 
 
 
 
563347f
ac6ac17
563347f
ac6ac17
 
 
c3b22d8
14ef8b3
09a7e07
14ef8b3
 
563347f
14ef8b3
 
 
09a7e07
14ef8b3
 
 
563347f
 
14ef8b3
09a7e07
14ef8b3
 
563347f
14ef8b3
 
 
09a7e07
14ef8b3
 
 
563347f
 
aa5534a
 
 
 
 
 
 
 
f480766
 
 
 
72b4af8
f480766
 
 
 
 
 
 
 
 
aa5534a
 
 
 
60f7d7d
 
 
aa5534a
 
 
 
60f7d7d
 
 
 
 
aa5534a
 
 
60f7d7d
 
 
aa5534a
 
 
 
 
 
 
# Copyright 2009 One Laptop Per Child
# Author: Sayamindu Dasgupta <sayamindu@laptop.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import logging

import os
import shutil
import sqlite3
import time
import base64
import json

from gi.repository import GObject
from sugar3 import profile

from readbookmark import Bookmark

_logger = logging.getLogger('read-activity')


def _init_db():
    dbdir = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data')
    dbpath = os.path.join(dbdir, 'read_v1.db')
    olddbpath = os.path.join(dbdir, 'read.db')

    # Situation 0: Db is existent
    if os.path.exists(dbpath):
        return dbpath

    # Situation 1: DB is non-existent at all
    if not os.path.exists(dbpath) and not os.path.exists(olddbpath):
        # in this case, sqlite3 takes care of things
        conn = sqlite3.connect(dbpath)
        conn.execute("""
        CREATE TABLE "bookmarks"(
              md5 text,
              page integer,
              content text,
              timestamp real,
              user text,
              color text,
              local integer
            );""")
        conn.commit()
        conn.close()

        return dbpath

    # Situation 2: DB is outdated
    if not os.path.exists(dbpath) and os.path.exists(olddbpath):
        shutil.copy(olddbpath, dbpath)

        conn = sqlite3.connect(dbpath)
        conn.execute(
            "CREATE TABLE  temp_bookmarks  AS SELECT md5, page, " +
            "title 'content', timestamp, user, color, local  FROM bookmarks")
        conn.execute("ALTER TABLE bookmarks RENAME TO bookmarks_old")
        conn.execute("ALTER TABLE temp_bookmarks RENAME TO bookmarks")
        conn.execute("DROP TABLE bookmarks_old")
        conn.commit()
        conn.close()

        return dbpath

    # Should not reach this point
    return None


def _init_db_highlights(conn):
    conn.execute('CREATE TABLE IF NOT EXISTS HIGHLIGHTS ' +
                 '(md5 TEXT, page INTEGER, ' +
                 'init_pos INTEGER, end_pos INTEGER)')
    conn.commit()


def _init_db_previews(conn):
    conn.execute('CREATE TABLE IF NOT EXISTS PREVIEWS ' +
                 '(md5 TEXT, page INTEGER, ' +
                 'preview)')
    conn.commit()


class BookmarkManager(GObject.GObject):

    __gsignals__ = {
        'added_bookmark': (GObject.SignalFlags.RUN_FIRST,
                           None, ([int, str])),
        'removed_bookmark': (GObject.SignalFlags.RUN_FIRST,
                             None, ([int])), }

    def __init__(self, filehash):
        GObject.GObject.__init__(self)
        self._filehash = filehash

        dbpath = _init_db()

        assert dbpath is not None

        self._conn = sqlite3.connect(dbpath)
        _init_db_highlights(self._conn)
        _init_db_previews(self._conn)

        self._conn.text_factory = lambda x: str(x, "utf-8", "ignore")

        self._bookmarks = []
        self._populate_bookmarks()
        self._highlights = {0: []}
        self._populate_highlights()

        self._user = profile.get_nick_name()
        self._color = profile.get_color().to_string()

    def update_bookmarks(self, bookmarks_list):
        need_reync = False
        for bookmark_data in bookmarks_list:
            # compare with all the bookmarks
            found = False
            for bookmark in self._bookmarks:
                if bookmark.compare_equal_to_dict(bookmark_data):
                    found = True
                    break
            if not found:
                if bookmark_data['nick'] == self._user and \
                        bookmark_data['color'] == self._color:
                    local = 1
                else:
                    local = 0
                t = (bookmark_data['md5'], bookmark_data['page_no'],
                     bookmark_data['content'], bookmark_data['timestamp'],
                     bookmark_data['nick'], bookmark_data['color'], local)
                self._conn.execute('insert into bookmarks values ' +
                                   '(?, ?, ?, ?, ?, ?, ?)', t)
                need_reync = True
                title = json.loads(bookmark_data['content'])['title']
                self.emit('added_bookmark', bookmark_data['page_no'] + 1,
                          title)

        if need_reync:
            self._resync_bookmark_cache()

    def add_bookmark(self, page, content, local=1):
        logging.debug('add_bookmark page %d', page)
        # local = 0 means that this is a bookmark originally
        # created by the person who originally shared the file
        timestamp = time.time()
        t = (self._filehash, page, content, timestamp, self._user,
             self._color, local)
        self._conn.execute('insert into bookmarks values ' +
                           '(?, ?, ?, ?, ?, ?, ?)', t)
        self._conn.commit()

        self._resync_bookmark_cache()
        title = json.loads(content)['title']
        self.emit('added_bookmark', page + 1, title)

    def del_bookmark(self, page):
        # We delete only the locally made bookmark
        logging.debug('del_bookmark page %d', page)
        t = (self._filehash, page, self._user)
        self._conn.execute('delete from bookmarks ' +
                           'where md5=? and page=? and user=?', t)
        self._conn.commit()
        self._del_bookmark_preview(page)
        self._resync_bookmark_cache()
        self.emit('removed_bookmark', page + 1)

    def add_bookmark_preview(self, page, preview):
        logging.debug('add_bookmark_preview page %d', page)
        t = (self._filehash, page, base64.b64encode(preview))
        self._conn.execute('insert into previews values ' +
                           '(?, ?, ?)', t)
        self._conn.commit()

    def _del_bookmark_preview(self, page):
        logging.debug('del_bookmark_preview page %d', page)
        t = (self._filehash, page)
        self._conn.execute('delete from previews ' +
                           'where md5=? and page=?', t)
        self._conn.commit()

    def get_bookmark_preview(self, page):
        logging.debug('get_bookmark page %d', page)
        rows = self._conn.execute('select preview from previews ' +
                                  'where md5=? and page=?',
                                  (self._filehash, page))
        for row in rows:
            return base64.b64decode(row[0])
        return None

    def _populate_bookmarks(self):
        # TODO: Figure out if caching the entire set of bookmarks
        # is a good idea or not
        rows = self._conn.execute('select * from bookmarks ' +
                                  'where md5=? order by page',
                                  (self._filehash, ))

        for row in rows:
            self._bookmarks.append(Bookmark(row))
        logging.debug('loading %d bookmarks', len(self._bookmarks))

    def get_bookmarks(self):
        return self._bookmarks

    def get_bookmarks_for_page(self, page):
        bookmarks = []
        for bookmark in self._bookmarks:
            if bookmark.belongstopage(page):
                bookmarks.append(bookmark)

        return bookmarks

    def _resync_bookmark_cache(self):
        # To be called when a new bookmark has been added/removed
        self._bookmarks = []
        self._populate_bookmarks()

    def get_prev_bookmark_for_page(self, page, wrap=True):
        if not len(self._bookmarks):
            return None

        if page <= self._bookmarks[0].page_no and wrap:
            return self._bookmarks[-1]
        else:
            for i in range(page - 1, -1, -1):
                for bookmark in self._bookmarks:
                    if bookmark.belongstopage(i):
                        return bookmark

        return None

    def get_next_bookmark_for_page(self, page, wrap=True):
        if not len(self._bookmarks):
            return None

        if page >= self._bookmarks[-1].page_no and wrap:
            return self._bookmarks[0]
        else:
            for i in range(page + 1, self._bookmarks[-1].page_no + 1):
                for bookmark in self._bookmarks:
                    if bookmark.belongstopage(i):
                        return bookmark

        return None

    def get_highlights(self, page):
        try:
            return self._highlights[page]
        except KeyError:
            self._highlights[page] = []
            return self._highlights[page]

    def get_all_highlights(self):
        return self._highlights

    def update_highlights(self, highlights_dict):
        for page in list(highlights_dict.keys()):
            # json store the keys as strings
            # but the page is used as a int in all the code
            highlights_in_page = highlights_dict[page]
            page = int(page)
            highlights_stored = self.get_highlights(page)
            for highlight_tuple in highlights_in_page:
                if highlight_tuple not in highlights_stored:
                    self.add_highlight(page, highlight_tuple)

    def add_highlight(self, page, highlight_tuple):
        logging.error('Adding hg page %d %s' % (page, highlight_tuple))
        self.get_highlights(page).append(highlight_tuple)

        t = (self._filehash, page, highlight_tuple[0], highlight_tuple[1])
        self._conn.execute('insert into highlights values ' +
                           '(?, ?, ?, ?)', t)
        self._conn.commit()

    def del_highlight(self, page, highlight_tuple):
        self._highlights[page].remove(highlight_tuple)
        t = (self._filehash, page, highlight_tuple[0],
             highlight_tuple[1])
        self._conn.execute(
            'delete from highlights ' +
            'where md5=? and page=? and init_pos=? and end_pos=?', t)
        self._conn.commit()

    def _populate_highlights(self):
        rows = self._conn.execute('select * from highlights ' +
                                  'where md5=? order by page',
                                  (self._filehash, ))
        for row in rows:
            # md5 = row[0]
            page = row[1]
            init_pos = row[2]
            end_pos = row[3]
            highlight_tuple = [init_pos, end_pos]
            self.get_highlights(page).append(highlight_tuple)