Пример #1
0
def updateLink(
        db, boxPath, prevLinkName, newLink, user,
        accountDeletionInProgress=False, skipCommit=False):
    """ Update the fields of a link object on DB."""
    #
    # we check link_id is unchanged
    parentBox = getBoxFromPath(
        db,
        boxPath,
        user,
        accountDeletionInProgress=accountDeletionInProgress,
    )
    prevLink = getLinkFromParent(
        db,
        parentBox,
        prevLinkName,
        user,
        accountDeletionInProgress=accountDeletionInProgress,
    )
    if newLink.link_id != prevLink.link_id:
        raise RuntimeError('Link ID mismatch')
    else:
        if (not accountDeletionInProgress and
                not userHasPermission(db, user, parentBox.permissions, 'w')):
            raise OstracionError('User is not allowed to edit link')
        else:
            if not isNameUnderParentBox(
                    db, parentBox, newLink.name,
                    excludedIds=[('link', prevLink.link_id)]):
                newLinkItem = Link(**{
                    k: v
                    for k, v in newLink.asDict().items()
                    if k not in {
                        'dvector_name',
                        'dvector_description',
                        'dvector_title',
                    }
                })
                dbUpdateRecordOnTable(
                    db,
                    'links',
                    newLinkItem.asDict(),
                    dbTablesDesc=dbSchema,
                )
                if not skipCommit:
                    db.commit()
            else:
                raise OstracionError('Name already exists')
Пример #2
0
def getLinksFromBox(db, box):
    """ Perform a 'ls' call and return
        all links found in a given box.
    """
    return (
        Link(**linkDict)
        for linkDict in dbRetrieveRecordsByKey(
            db,
            'links',
            {'box_id': box.box_id},
            dbTablesDesc=dbSchema,
        )
    )
Пример #3
0
def makeLinkInParent(
        db, user, parentBox, date, linkName, linkTitle, linkDescription,
        linkTarget, linkOptions={}):
    """ Create a new external link object in the specified box.

        Return a dummy value (True upon success, but it is the errors
        that are raised.)
    """
    if userHasPermission(db, user, parentBox.permissions, 'w'):
        if not isNameUnderParentBox(db, parentBox, linkName):
            userName = user.username
            newLink = Link(
                box_id=parentBox.box_id,
                name=linkName,
                title=linkTitle,
                description=linkDescription,
                icon_file_id='',
                date=date,
                creator_username=userName,
                icon_file_id_username=userName,
                icon_mime_type='',
                metadata_username=userName,
                target=linkTarget,
                metadata_dict=linkOptions,
            )
            dbAddRecordToTable(
                db,
                'links',
                newLink.asDict(),
                dbTablesDesc=dbSchema,
            )
            db.commit()
        else:
            raise OstracionError('Name already exists')
    else:
        raise OstracionError('User has no write permission')
Пример #4
0
def getLinkFromParent(
        db, parentBox, linkName,
        user, accountDeletionInProgress=False):
    """ Given a box and the name of a link supposedly contained
        in it, return the link (or None).
    """
    linkDict = dbRetrieveRecordByKey(
        db,
        'links',
        {'name': linkName, 'box_id': parentBox.box_id},
        dbTablesDesc=dbSchema,
    )
    if linkDict is not None:
        return Link(**linkDict)
    else:
        return None
Пример #5
0
                         col
                         for col in dbSchema[tName]['columns'] if
                         col[0] not in {'title', 'dvector_title'}
                     ]
                 }
             },
             defaultMap={tName: dbSchema[tName]},
         )
         for prevLinkEntryDict in dbRetrieveAllRecords(
                 db,
                 tName,
                 tempSchema,
         ):
             print('<', end='')
             newLink = Link(**(recursivelyMergeDictionaries(
                 {'title': prevLinkEntryDict['name']},
                 prevLinkEntryDict,
             ))).asDict()
             print(newLink)
             dbUpdateRecordOnTable(
                 db,
                 tName,
                 newLink,
                 dbTablesDesc=dbSchema,
             )
             print('*> ', end='')
         #
         print('\n          done.')
 elif tName == 'roles':
     # we add new roles, only if they do not exist at all
     tcontents = initialDbValues.get(tName)
     print('        * Refreshing')
Пример #6
0
def fsLinkMetadataView(fsPathString=''):
    """Edit-link-metadata view, a web-form."""

    user = g.user
    db = dbGetDatabase()
    form = EditLinkForm()
    lsPath = splitPathString(fsPathString)
    boxPath, prevLinkName = lsPath[:-1], lsPath[-1]
    parentBox = getBoxFromPath(db, boxPath, user)
    request._onErrorUrl = url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:]),
    )
    link = getLinkFromParent(db, parentBox, prevLinkName, user)
    if form.validate_on_submit():
        newLink = Link(**recursivelyMergeDictionaries(
            {
                'name': form.linkname.data,
                'description': form.linkdescription.data,
                'title': form.linktitle.data,
                'target': form.linktarget.data,
                'metadata_username': user.username,
                'metadata_dict': {
                    'open_in_new_window': form.openinnewwindow.data,
                },
            },
            defaultMap={
                k: v
                for k, v in link.asDict().items() if k not in {
                    'metadata', 'dvector_description', 'dvector_name',
                    'dvector_title'
                }
            },
        ))
        updateLink(db, boxPath, prevLinkName, newLink, user)
        return redirect(url_for('lsView', lsPathString='/'.join(boxPath[1:])))
    else:
        form.linkname.data = applyDefault(form.linkname.data, link.name)
        form.linkdescription.data = applyDefault(form.linkdescription.data,
                                                 link.description)
        form.linktitle.data = applyDefault(form.linktitle.data, link.title)
        form.linktarget.data = applyDefault(form.linktarget.data, link.target)
        form.openinnewwindow.data = link.getMetadata(
            'open_in_new_window',
            True,
        )
        #
        pageFeatures = {
            'breadCrumbs':
            makeBreadCrumbs(
                boxPath,
                g,
                appendedItems=[{
                    'kind': 'external_link',
                    'target': link,
                }, {
                    'kind': 'link',
                    'target': None,
                    'name': 'Metadata',
                }],
            ),
            'pageTitle':
            'Edit link metadata (%s)' % link.name,
            'pageSubtitle':
            'Name and target are mandatory',
            'iconUrl':
            url_for(
                'linkThumbnailView',
                dummyId=link.icon_file_id + '_',
                fsPathString='/'.join(lsPath[1:]),
            ),
        }
        return render_template(
            'editlink.html',
            form=form,
            user=user,
            **pageFeatures,
        )
Пример #7
0
def _traverseForAccountDeletion(db, parentBox, username, user,
                                path, fileStorageDirectory):
    """ Traverse the tree (one call per box, recursively+iteratively)
        and collect a delete queue while updating items found in various
        ways (deletions, icon resets, metadata resets, forced renames).
    """
    fsDeleteQueue = []
    for file in getFilesFromBox(db, parentBox):
        if (file.creator_username == username or
                file.editor_username == username):
            fsDeleteQueue += deleteFile(
                db,
                parentBox,
                file,
                None,
                fileStorageDirectory=fileStorageDirectory,
                skipCommit=True,
                accountDeletionInProgress=True,
            )
        else:
            if file.icon_file_id_username == username:
                fsDeleteQueue += updateFileThumbnail(
                    db,
                    file,
                    None,
                    None,
                    user,
                    fileStorageDirectory=fileStorageDirectory,
                    accountDeletionInProgress=True,
                    skipCommit=True,
                )
                iconedFile = getFileFromParent(db, parentBox, file.name, None)
            else:
                iconedFile = file
            # "iconed" as in "icon-wise fixed"
            if iconedFile.metadata_username == username:
                newFileName = findFirstAvailableObjectNameInBox(
                    db,
                    parentBox,
                    prefix='REDACTED_FILE_',
                    suffix='',
                )
                newDescription = 'File name redacted upon account deletion'
                newFile = File(**recursivelyMergeDictionaries(
                    {
                        'name': newFileName,
                        'description': newDescription,
                        'metadata_username': '',
                    },
                    defaultMap=iconedFile.asDict(),
                ))
                updateFile(
                    db,
                    path,
                    iconedFile.name,
                    newFile,
                    None,
                    accountDeletionInProgress=True,
                    skipCommit=True,
                )
    #
    for link in getLinksFromBox(db, parentBox):
        if link.creator_username == username:
            fsDeleteQueue += deleteLink(
                db,
                parentBox,
                link,
                None,
                fileStorageDirectory=fileStorageDirectory,
                skipCommit=True,
                accountDeletionInProgress=True,
            )
        else:
            if link.icon_file_id_username == username:
                fsDeleteQueue += updateLinkThumbnail(
                    db,
                    link,
                    None,
                    None,
                    user,
                    fileStorageDirectory=fileStorageDirectory,
                    accountDeletionInProgress=True,
                    skipCommit=True,
                )
                iconedLink = getLinkFromParent(db, parentBox, link.name, None)
            else:
                iconedLink = link
            # "iconed" as in "icon-wise fixed"
            if iconedLink.metadata_username == username:
                newLinkName = findFirstAvailableObjectNameInBox(
                    db,
                    parentBox,
                    prefix='REDACTED_LINK_',
                    suffix='',
                )
                newDescription = 'Link data redacted upon account deletion'
                newLink = Link(**recursivelyMergeDictionaries(
                    {
                        'name': newLinkName,
                        'description': newDescription,
                        'target': '#',
                        'metadata_username': '',
                    },
                    defaultMap=iconedLink.asDict(),
                ))
                updateLink(
                    db,
                    path,
                    iconedLink.name,
                    newLink,
                    None,
                    accountDeletionInProgress=True,
                    skipCommit=True,
                )
    #
    for box in getBoxesFromParent(
            db, parentBox, None, accountDeletionInProgress=True):
        if box is not None and box.box_name != '':
            fsDeleteQueue += _traverseForAccountDeletion(
                db,
                box,
                username,
                user,
                path + [box.box_name],
                fileStorageDirectory=fileStorageDirectory,
            )
            if box.creator_username == username and _boxHasNoChildren(db, box):
                fsDeleteQueue += deleteBox(
                    db,
                    box,
                    parentBox,
                    None,
                    fileStorageDirectory=fileStorageDirectory,
                    accountDeletionInProgress=True,
                    skipCommit=True,
                )
            else:
                if (box.icon_file_id_username == username or
                        box.creator_username == username):
                    fsDeleteQueue += updateBoxThumbnail(
                        db,
                        box,
                        None,
                        None,
                        user,
                        fileStorageDirectory=fileStorageDirectory,
                        accountDeletionInProgress=True,
                        skipCommit=True,
                    )
                    iconedBox = getBoxFromPath(
                        db,
                        path + [box.box_name],
                        None,
                        accountDeletionInProgress=True,
                    )
                else:
                    iconedBox = box
                #
                if (iconedBox.metadata_username == username or
                        iconedBox.creator_username == username):
                    #
                    newBoxName = findFirstAvailableObjectNameInBox(
                        db,
                        parentBox,
                        prefix='REDACTED_BOX_',
                        suffix='',
                    )
                    newDescription = 'Box name redacted upon account deletion'
                    mdNewBoxContrib = {
                            'box_name': newBoxName,
                            'description': newDescription,
                            'title': newBoxName,
                            'metadata_username': '',
                    }
                    #
                    if iconedBox.creator_username == username:
                        cNewBoxContrib = {
                            'creator_username': '',
                        }
                    else:
                        cNewBoxContrib = {}
                    #
                    newBox = Box(**recursivelyMergeDictionaries(
                        recursivelyMergeDictionaries(
                            mdNewBoxContrib,
                            defaultMap=cNewBoxContrib,
                        ),
                        defaultMap=iconedBox.asDict(),
                    ))
                    updateBox(
                        db,
                        path + [box.box_name],
                        newBox,
                        None,
                        accountDeletionInProgress=True,
                        skipCommit=True,
                    )
    #
    return fsDeleteQueue
Пример #8
0
def explicitLoopSimilaritySearch(
        db,
        searchTerm,
        searchBoxes=True,
        searchFiles=True,
        searchLinks=True,
        useDescription=False):
    """ Explicit loop over files/boxes
        and use a 'similarity' logic to pick matching results.

        Same return object as 'sqliteLikeSubstringSearch'.
    """
    searchTermDVector = textToDVector(searchTerm)
    if len(searchTermDVector) > 0:
        #
        if searchFiles:
            foundFiles = [
                ffRichItem
                for ffRichItem in (
                    {
                        'item': File(**fileDict),
                        'score': _itemSimilarityMatchScore(
                            'file',
                            searchTermDVector,
                            fileDict,
                            useDescription,
                        ),
                    }
                    for fileDict in dbRetrieveAllRecords(
                        db,
                        'files',
                        dbTablesDesc=dbSchema,
                    )
                )
                if ffRichItem['score'] >= similarityScoreThreshold
            ]
        else:
            foundFiles = []
        #
        if searchBoxes:
            foundBoxes = [
                fbRichItem
                for fbRichItem in (
                    {
                        'item': Box(**boxDict),
                        'score': _itemSimilarityMatchScore(
                            'box',
                            searchTermDVector,
                            boxDict,
                            useDescription,
                        ),
                    }
                    for boxDict in dbRetrieveAllRecords(
                        db,
                        'boxes',
                        dbTablesDesc=dbSchema,
                    )
                    if boxDict['box_id'] != ''
                )
                if fbRichItem['score'] >= similarityScoreThreshold
            ]
        else:
            foundBoxes = []
        #
        if searchLinks:
            foundLinks = [
                flRichItem
                for flRichItem in (
                    {
                        'item': Link(**linkDict),
                        'score': _itemSimilarityMatchScore(
                            'link',
                            searchTermDVector,
                            linkDict,
                            useDescription,
                        ),
                    }
                    for linkDict in dbRetrieveAllRecords(
                        db,
                        'links',
                        dbTablesDesc=dbSchema,
                    )
                )
                if flRichItem['score'] >= similarityScoreThreshold
            ]
        else:
            foundLinks = []
        #
        return {
            'files': foundFiles,
            'boxes': foundBoxes,
            'links': foundLinks,
        }
    else:
        return {
            'files': [],
            'boxes': [],
            'links': [],
            'message': 'Not enough digits/letters in search term',
        }
Пример #9
0
def explicitLoopSubstringSearch(
        db,
        searchTerm,
        searchBoxes=True,
        searchFiles=True,
        searchLinks=True,
        caseSensitive=True,
        useDescription=False):
    """ Explicit loop over the files/boxes tables
        and pick the substring-matching items.
        Same return object as 'sqliteLikeSubstringSearch'.

        We explicitly browse all files and all boxes
        and apply the search with the options passed.
        Not so fast but highly extendable in the future.
    """
    #
    _strippedSearchTerm = stripToAscii(searchTerm)
    _caseAdjustedSearchTerm = (
        _strippedSearchTerm if caseSensitive else _strippedSearchTerm.lower()
    )
    searchTokens = {
        itm.strip()
        for itm in _caseAdjustedSearchTerm.split(' ')
        if itm.strip() != ''
    }
    if len(searchTokens) > 0:
        #
        tokenResLens = [
            (re.compile(re.escape(tk)), len(tk))
            for tk in searchTokens
        ]
        #
        if searchFiles:
            foundFiles = [
                ffRichItem
                for ffRichItem in (
                    {
                        'item': File(**fileDict),
                        'score': _itemSubstringMatchScore(
                            'file',
                            tokenResLens,
                            fileDict,
                            caseSensitive,
                            useDescription,
                        ),
                    }
                    for fileDict in dbRetrieveAllRecords(
                        db,
                        'files',
                        dbTablesDesc=dbSchema,
                    )
                )
                if ffRichItem['score'] > 0
            ]
        else:
            foundFiles = []
        #
        if searchBoxes:
            foundBoxes = [
                fbRichItem
                for fbRichItem in (
                    {
                        'item': Box(**boxDict),
                        'score': _itemSubstringMatchScore(
                            'box',
                            tokenResLens,
                            boxDict,
                            caseSensitive,
                            useDescription,
                        ),
                    }
                    for boxDict in dbRetrieveAllRecords(
                        db,
                        'boxes',
                        dbTablesDesc=dbSchema,
                    )
                    if boxDict['box_id'] != ''
                )
                if fbRichItem['score'] > 0
            ]
        else:
            foundBoxes = []
        #
        if searchLinks:
            foundLinks = [
                flRichItem
                for flRichItem in (
                    {
                        'item': Link(**linkDict),
                        'score': _itemSubstringMatchScore(
                            'link',
                            tokenResLens,
                            linkDict,
                            caseSensitive,
                            useDescription,
                        ),
                    }
                    for linkDict in dbRetrieveAllRecords(
                        db,
                        'links',
                        dbTablesDesc=dbSchema,
                    )
                )
                if flRichItem['score'] > 0
            ]
        else:
            foundLinks = []
        #
        return {
            'files': foundFiles,
            'boxes': foundBoxes,
            'links': foundLinks,
        }
    else:
        return {
            'files': [],
            'boxes': [],
            'links': [],
            'message': 'No search terms provided',
        }