Example #1
0
    def test_db_session(self):
        '''
        Test getting session for SQLite DB which passively creates a new
        DB (new .sqlite file) if it isn't present yet.
        '''

        from frostmark import user_data
        from frostmark import db_base
        from frostmark.db import get_session
        from sqlalchemy.orm.session import Session

        folder = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(folder))

        # two sessions to check whether SQLA raises an Exception
        # e.g. if a table already exists and create_all() is called
        ses_one = get_session()
        self.assertIsInstance(ses_one, Session)

        ses_two = get_session()
        self.assertIsInstance(ses_two, Session)

        ses_one.close()
        ses_two.close()

        self.assertIn(db_base.DB_NAME, listdir(folder))
        remove(join(folder, db_base.DB_NAME))
Example #2
0
    def test_edit_parent_folder_missingparent(self):
        '''
        Test editing parent to a non-existing Folder.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Folder
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        item = {'id': 321, 'folder_name': 'child'}
        session = get_session()
        try:
            session.add(Folder(**item))
            session.commit()
        finally:
            session.close()

        with self.assertRaises(Exception):
            Editor.change_parent_folder(folder_id=item['id'], parent_id=2**31)

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #3
0
    def test_edit_parent_bookmark_missingchild(self):
        '''
        Test editing parent of a non-existing Bookmark.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Bookmark
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        item = {
            'id': 321,
            'title': 'child',
            'url': '<url>',
            'icon': b'<bytes>'
        }
        session = get_session()
        try:
            session.add(Bookmark(**item))
            session.commit()
        finally:
            session.close()

        with self.assertRaises(Exception):
            Editor.change_parent_bookmark(bookmark_id=2**31,
                                          parent_id=item['id'])

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #4
0
    def change_parent_bookmark(bookmark_id: int, parent_id: int):
        '''
        Change bookmark's parent if both the parent and the child exist
        and if the new parent isn't the child itself.
        '''

        if bookmark_id == parent_id:
            raise Exception('Bookmark can not be its own parent')

        session = get_session()
        try:
            child = session.query(Bookmark).filter(
                Bookmark.id == bookmark_id).first()

            parent = session.query(Folder).filter(
                Folder.id == parent_id).first()
            if not child or not parent:
                raise Exception(
                    f'Child: {child} or parent: {parent} does not exist')

            child.folder_id = parent.id
            session.commit()

        finally:
            session.close()
Example #5
0
    def test_edit_parent_folder(self):
        '''
        Test editing a parent folder of a Folder.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Folder
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        items = [{
            'id': 321,
            'folder_name': 'old parent'
        }, {
            'id': 666,
            'folder_name': 'child',
            'parent_folder_id': 321
        }, {
            'id': 123,
            'folder_name': 'new parent'
        }]
        session = get_session()
        try:
            for item in items:
                session.add(Folder(**item))
            session.commit()

            for item in items:
                self.assertEqual(
                    session.query(Folder).filter(
                        Folder.folder_name == item['folder_name']).first().id,
                    item['id'])

            self.assertEqual(
                session.query(Folder).filter(
                    Folder.id == items[1]['id']).first().parent_folder_id,
                items[0]['id'])

            Editor.change_parent_folder(folder_id=items[1]['id'],
                                        parent_id=items[2]['id'])

            self.assertEqual(
                session.query(Folder).filter(
                    Folder.id == items[1]['id']).first().parent_folder_id,
                items[2]['id'])

        finally:
            session.close()

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #6
0
    def rename_bookmark(bookmark_id: int, name: str):
        '''
        Change bookmark's title.
        '''

        session = get_session()
        try:
            child = session.query(Bookmark).filter(
                Bookmark.id == bookmark_id).first()

            child.title = name
            session.commit()

        finally:
            session.close()
Example #7
0
    def rename_folder(folder_id: int, name: str):
        '''
        Change folder's name.
        '''

        session = get_session()
        try:
            child = session.query(Folder).filter(
                Folder.id == folder_id).first()

            child.folder_name = name
            session.commit()

        finally:
            session.close()
Example #8
0
    def change_bookmark_url(bookmark_id: int, url: str):
        '''
        Change bookmark's title.
        '''

        session = get_session()
        try:
            child = session.query(Bookmark).filter(
                Bookmark.id == bookmark_id).first()

            child.url = url
            session.commit()

        finally:
            session.close()
Example #9
0
    def test_change_bookmark_url(self):
        '''
        Test renaming a Bookmark item.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Bookmark
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        item = {
            'id': 321,
            'title': 'child',
            'url': '<url>',
            'icon': b'<bytes>'
        }
        session = get_session()
        try:
            session.add(Bookmark(**item))
            session.commit()

            self.assertEqual(
                session.query(Bookmark).filter(
                    Bookmark.title == item['title']).first().id, item['id'])

            self.assertEqual(
                session.query(Bookmark).filter(
                    Bookmark.id == item['id']).first().title, item['title'])

            Editor.change_bookmark_url(bookmark_id=item['id'],
                                       url=f"http://{item['url']}")

            self.assertEqual(
                session.query(Bookmark).filter(
                    Bookmark.id == item['id']).first().url,
                f"http://{item['url']}")
        finally:
            session.close()

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #10
0
def fetch_folder_tree() -> Node:
    '''
    Fetch folders only from the internal database, assemble a tree
    and return the root Node.
    '''

    session = get_session()
    folders = [vars(item) for item in session.query(Folder).all()]
    session.close()

    for folder in folders:
        if folder['id'] != 0:
            continue
        folder['parent_folder_id'] = None

    tree = assemble_folder_tree(items=folders,
                                key='parent_folder_id',
                                node_type=Folder)
    return tree
Example #11
0
    def test_rename_folder(self):
        '''
        Test renaming a Folder item.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Folder
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        item = {'id': 321, 'folder_name': 'old parent'}
        session = get_session()
        try:
            session.add(Folder(**item))
            session.commit()

            self.assertEqual(
                session.query(Folder).filter(
                    Folder.folder_name == item['folder_name']).first().id,
                item['id'])

            self.assertEqual(
                session.query(Folder).filter(
                    Folder.id == item['id']).first().folder_name,
                item['folder_name'])

            Editor.rename_folder(folder_id=item['id'],
                                 name=item['folder_name'][:3])

            self.assertEqual(
                session.query(Folder).filter(
                    Folder.id == item['id']).first().folder_name,
                item['folder_name'][:3])
        finally:
            session.close()

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #12
0
def fetch_bookmark_tree() -> Node:
    '''
    Fetch folders and bookmarks from the internal database, assemble
    a bookmark tree and return the root Node
    '''

    session = get_session()
    folders = [vars(item) for item in session.query(Folder).all()]
    bookmarks = [vars(item) for item in session.query(Bookmark).all()]
    session.close()

    for folder in folders:
        if folder['id'] != 0:
            continue
        folder['parent_folder_id'] = None

    tree = assemble_bookmark_tree(items=bookmarks,
                                  key='folder_id',
                                  folder_tree_root=assemble_folder_tree(
                                      items=folders,
                                      key='parent_folder_id',
                                      node_type=Folder),
                                  node_type=Bookmark)
    return tree
Example #13
0
    def test_edit_parent_bookmark(self):
        '''
        Test editing a parent folder of a bookmark.
        '''
        from frostmark import db_base, user_data
        from frostmark.db import get_session
        from frostmark.models import Folder, Bookmark
        from frostmark.editor import Editor

        data = dirname(abspath(user_data.__file__))
        self.assertNotIn(db_base.DB_NAME, listdir(data))

        items = [{
            'id': 321,
            'folder_name': 'old parent',
            'type': Folder
        }, {
            'id': 666,
            'title': 'child',
            'folder_id': 321,
            'type': Bookmark,
            'url': '<url>',
            'icon': b'<bytes>'
        }, {
            'id': 123,
            'folder_name': 'new parent',
            'type': Folder
        }]
        session = get_session()
        try:
            for item in items:
                item_type = item.pop('type')
                if item_type == Folder:
                    session.add(Folder(**item))
                elif item_type == Bookmark:
                    session.add(Bookmark(**item))
                item['type'] = item_type
            session.commit()

            for item in items:
                item_type = item.pop('type')
                if item_type == Folder:
                    self.assertEqual(
                        session.query(Folder).filter(
                            Folder.folder_name ==
                            item['folder_name']).first().id, item['id'])
                elif item_type == Bookmark:
                    self.assertEqual(
                        session.query(Bookmark).filter(
                            Bookmark.title == item['title']).first().id,
                        item['id'])
                item['type'] = item_type

            self.assertEqual(
                session.query(Bookmark).filter(
                    Bookmark.id == items[1]['id']).first().folder_id,
                items[0]['id'])

            Editor.change_parent_bookmark(bookmark_id=items[1]['id'],
                                          parent_id=items[2]['id'])

            self.assertEqual(
                session.query(Bookmark).filter(
                    Bookmark.id == items[1]['id']).first().folder_id,
                items[2]['id'])
        finally:
            session.close()

        self.assertIn(db_base.DB_NAME, listdir(data))
        remove(join(data, db_base.DB_NAME))
Example #14
0
    def import_from(self, path: str):
        '''
        Import bookmarks from particular path into internal storage.
        '''
        # pylint: disable=too-many-locals

        backend = self.backend

        # get the bookmarks tree from file
        if isinstance(backend, FirefoxImporter):
            source = self._path_session(path=path, base=backend.BASE)
        elif isinstance(backend, OperaImporter):
            source = path
        elif isinstance(backend, ChromeImporter):
            source = path
        tree = backend.assemble_import_tree(source)

        # open internal DB
        nodes = traverse(tree)
        folders = {node.id: node for node in nodes if node.node_type == Folder}
        bookmarks = {
            node.id: node
            for node in nodes if node.node_type == Bookmark
        }

        # sqla objects
        frost = get_session()
        sqla_folders = {}

        # add folder structure to the database
        sorted_folders = sorted(
            folders.values(),
            # parent_folder_id is None for root folder
            key=lambda item: item.parent_folder_id or 0)

        # first sort the tree by parent IDs so that there is each parent
        # available, however in case there is a kind-of circular relationship
        # between the folders e.g. the ID of a child is smaller than ID of
        # a parent which might be caused by browser importing old bookmarks
        # from database directly or from a different browser while incorrectly
        # setting IDs (or better said re-using already existing IDs when
        # possible), therefore sorting by parent ID would work, but when trying
        # to access the parent a KeyError would be raised because of parent
        # not being available yet due to higher ID than the child has
        #
        # for that reason try to sort with parent ID first and postpone
        # the relationship evaluation by using second/third/etc/... item
        # in the sorted list until there is parent ID available (or throw
        # IndexError in the end which would pretty much mean that the browser
        # DB is just broken due to missing parent / dangling children)
        idx = 0
        while sorted_folders:
            folder = sorted_folders[idx]

            kwargs = {'folder_name': folder.folder_name}
            if folder.parent_folder_id:
                # in case there is a parent, get the Folder object
                # and pull its ID after flush() (otherwise it's None)
                try:
                    real_id = sqla_folders[folder.parent_folder_id].id
                except KeyError:
                    idx += 1
                    continue

                kwargs['parent_folder_id'] = real_id

            new_folder = Folder(**kwargs)
            frost.add(new_folder)

            # flush to obtain folder ID,
            # especially necessary for nested folders
            frost.flush()

            # preserve the original ID and point to a SQLA object
            sqla_folders[folder.id] = new_folder

            # remove current folder
            idx = 0
            sorted_folders.remove(folder)

        # add bookmarks
        for key in sorted(bookmarks.keys()):
            book = bookmarks[key]
            kwargs = {
                'title': book.title,
                'url': book.url,
                'icon': b'',
                'folder_id': sqla_folders[book.folder_id].id
            }

            # no need to flush, nothing required a bookmark
            # ID to be present before final commit()
            new_book = Bookmark(**kwargs)
            frost.add(new_book)

        # write data into internal DB
        frost.commit()