Esempio n. 1
0
def fsMetadataView(fsPathString=''):
    """Edit-file-metadata view, a web-form."""
    user = g.user
    db = dbGetDatabase()
    form = FileDataForm()
    lsPath = splitPathString(fsPathString)
    boxPath, prevFileName = lsPath[:-1], lsPath[-1]
    parentBox = getBoxFromPath(db, boxPath, user)
    request._onErrorUrl = url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:]),
    )
    file = getFileFromParent(db, parentBox, prevFileName, user)
    if form.validate_on_submit():
        newFile = File(**recursivelyMergeDictionaries(
            {
                'name': form.filename.data,
                'description': form.filedescription.data,
                'metadata_username': user.username,
            },
            defaultMap=file.asDict(),
        ))
        updateFile(db, boxPath, prevFileName, newFile, user)
        return redirect(url_for('lsView', lsPathString='/'.join(boxPath[1:])))
    else:
        form.filename.data = applyDefault(form.filename.data, file.name)
        form.filedescription.data = applyDefault(form.filedescription.data,
                                                 file.description)
        #
        pageFeatures = {
            'breadCrumbs':
            makeBreadCrumbs(
                boxPath,
                g,
                appendedItems=[{
                    'kind': 'file',
                    'target': file,
                }, {
                    'kind': 'link',
                    'target': None,
                    'name': 'Metadata',
                }],
            ),
            'pageTitle':
            'Edit file metadata (%s)' % file.name,
            'pageSubtitle':
            'Name is mandatory',
            'iconUrl':
            url_for(
                'fileThumbnailView',
                dummyId=file.icon_file_id + '_',
                fsPathString='/'.join(lsPath[1:]),
            ),
        }
        return render_template(
            'filedataedit.html',
            form=form,
            user=user,
            **pageFeatures,
        )
def extractTopLevelTaskFromTreeDescriptor(tDesc, bgColorKey, g, overrides={}):
    """ Pick the top-level task item from a tree-descriptor
        and format it in a way fit for ls-view tasks.
    """
    rootTask = tDesc['tasks']['root']
    return recursivelyMergeDictionaries(
        overrides,
        defaultMap={
            'name':
            rootTask['title'],
            'description':
            rootTask['subtitle'],
            'url':
            url_for(
                rootTask['endpoint_name'][0],
                **rootTask['endpoint_name'][1],
            ),
            'thumbnail':
            makeSettingImageUrl(
                g,
                rootTask['image_id'][0],
                rootTask['image_id'][1],
            ),
            'bgcolor':
            g.settings['color']['task_colors'][bgColorKey]['value'],
        })
Esempio n. 3
0
def dbPunchRichTicket(db, richTicket, numPunches=1, skipCommit=False):
    """
        Punch a ticket, i.e. mark it as been used once more.

        We assume the ticket has been read during this database
        session, i.e. it reflects current DB data.
    """
    if richTicket['redeemable']:
        #
        newTicketDict = recursivelyMergeDictionaries(
            {
                'times_redeemed':
                (richTicket['ticket'].times_redeemed + numPunches),
                'last_redeemed':
                datetime.datetime.now(),
            },
            defaultMap=richTicket['ticket'].asDict(),
        )
        dbUpdateRecordOnTable(
            db,
            'tickets',
            newTicketDict,
            dbTablesDesc=dbSchema,
        )
        #
        if not skipCommit:
            db.commit()
    else:
        if richTicket['exhausted']:
            raise OstracionError('Ticket is exhausted')
        else:
            raise OstracionError('Cannot punch a non-redeemable ticket')
Esempio n. 4
0
def dbToggleBoxRolePermissionBit(db,
                                 thisBox,
                                 roleClass,
                                 roleId,
                                 bit,
                                 user,
                                 skipCommit=False):
    """ Toggle (t<-->f) a bit from an existing
        permission set (a role) for a box.
    """
    roleKey = (roleClass, roleId)
    if thisBox.box_id == '' and roleKey == ('system', 'admin'):
        raise OstracionError('Cannot edit root box permissions for admin')
    elif thisBox.box_id == '' and roleKey == ('system', 'anonymous'):
        raise OstracionError('Cannot edit root box permissions for anonymous')
    else:
        if userIsAdmin(db, user):
            foundRecords = list(
                dbRetrieveRecordsByKey(
                    db,
                    'box_role_permissions',
                    {
                        'box_id': thisBox.box_id,
                        'role_class': roleClass,
                        'role_id': roleId,
                    },
                    dbTablesDesc=dbSchema,
                ))
            if len(foundRecords) > 0:
                foundBRP = BoxRolePermission(**foundRecords[0])
                lBit = bit.lower()
                newBRPDict = recursivelyMergeDictionaries(
                    {lBit: 1 if not foundBRP.booleanBit(lBit) else 0},
                    defaultMap={
                        k: v
                        for k, v in foundBRP.asDict().items()
                        if k in {'box_id', 'role_class', 'role_id'}
                    },
                )
                try:
                    dbUpdateRecordOnTable(
                        db,
                        'box_role_permissions',
                        newBRPDict,
                        dbTablesDesc=dbSchema,
                        allowPartial=True,
                    )
                    if not skipCommit:
                        db.commit()
                except Exception as e:
                    db.rollback()
                    raise e
            else:
                raise OstracionError('Box role permission does not exist')
        else:
            raise OstracionError('Insufficient permissions')
Esempio n. 5
0
def calendarMakerSetCover(coverObjPath):
    """Calendar cover image selection view (uses quoted coverObjPath)."""
    request._onErrorUrl = url_for('calendarMakerImagesView', )
    coverImagePath = urllib.parse.unquote_plus(coverObjPath)
    response = redirect(url_for('calendarMakerImagesView'))
    currentCalendar = cookiesToCurrentCalendar(request.cookies)
    dResponse = dressResponseWithCurrentCalendar(
        response,
        recursivelyMergeDictionaries(
            {'cover_image_path_string': coverImagePath},
            defaultMap=currentCalendar),
    )
    return dResponse
Esempio n. 6
0
def calendarMakerResetSettingsView():
    """Reset calendar settings view."""
    request._onErrorUrl = url_for('calendarMakerIndexView', )
    currentCalendar = cookiesToCurrentCalendar(request.cookies)
    response = redirect(url_for('calendarMakerIndexView'))
    dResponse = dressResponseWithCurrentCalendar(
        response,
        recursivelyMergeDictionaries(
            {
                'properties': defaultCalendarProperties(),
            },
            defaultMap=currentCalendar,
        ),
    )
    return dResponse
Esempio n. 7
0
def calendarMakerAddImage(imageObjPath):
    """Calendar image-list add-image view (through quoted imageObjPath)."""
    request._onErrorUrl = url_for('calendarMakerImagesView', )
    imagePath = urllib.parse.unquote_plus(imageObjPath)
    response = redirect(url_for('calendarMakerImagesView'))
    currentCalendar = cookiesToCurrentCalendar(request.cookies)
    images = currentCalendar.get('image_path_strings', []) + [imagePath]
    dResponse = dressResponseWithCurrentCalendar(
        response,
        recursivelyMergeDictionaries(
            {'image_path_strings': images},
            defaultMap=currentCalendar,
        ),
    )
    return dResponse
Esempio n. 8
0
def cookiesToCurrentCalendar(cookies):
    """
        Extract, from the passed request 'cookies',
        all currently stored settings for the calendar generation.
    """
    cpCookie = cookies.get('apps_calendarmaker_current')
    if cpCookie is None:
        calFromCookie = {}
    else:
        calFromCookie = json.loads(cpCookie)
    # defaults
    defaultCal = {'properties': defaultCalendarProperties()}
    #
    return recursivelyMergeDictionaries(
        calFromCookie,
        defaultMap=defaultCal,
    )
Esempio n. 9
0
def updateSettingThumbnail(db,
                           richSetting,
                           tId,
                           tMT,
                           user,
                           fileStorageDirectory,
                           skipCommit=False):
    """ Update the image in a setting of type Image. This returns
        the (actual) filesystem deletion queue after taking care of
        the DB part.
        The new thumbnail ID is passed to this function ('' to reset).
        richSetting['setting'] is the DB object, at top-level we
        have enrichment info (such as the default/value resolved etc)
    """
    prevId = richSetting['setting'].value
    if prevId != '':
        delQueue = [
            fileIdToPath(prevId, fileStorageDirectory=fileStorageDirectory)
        ]
    else:
        delQueue = []
    #
    newSettingDict = recursivelyMergeDictionaries(
        {
            'value': tId if tId is not None else '',
            'icon_mime_type': tMT if tMT is not None else '',
        },
        defaultMap={
            k: v
            for k, v in richSetting['setting'].asDict().items()
            if k in {'value', 'icon_mime_type', 'group_id', 'id'}
        },
    )
    dbUpdateRecordOnTable(
        db,
        'settings',
        newSettingDict,
        dbTablesDesc=dbSchema,
        allowPartial=True,
    )
    #
    if not skipCommit:
        db.commit()
    return delQueue
Esempio n. 10
0
def moveFile(
        db, file, srcBox, dstBox, user,
        fileStorageDirectory, skipCommit=False):
    """ Move a file between boxes: also
        check for w permission on both boxes,
        check that no box in dstBox yields a name clash."""
    if file.box_id != srcBox.box_id:
        raise OstracionError('Parent mismatch between file and source box')
    elif srcBox.box_id == dstBox.box_id:
        raise OstracionError('Source and destination are the same')
    else:
        if all([
            userHasPermission(db, user, srcBox.permissions, 'w'),
            userHasPermission(db, user, dstBox.permissions, 'w'),
        ]):
            #
            fileName = file.name
            if isNameUnderParentBox(db, dstBox, fileName):
                raise OstracionError(
                    'Destination box contains an item with same name'
                )
            else:
                # now can the actual MV be performed
                newFile = recursivelyMergeDictionaries(
                    {'box_id': dstBox.box_id},
                    defaultMap=file.asDict(),
                )
                dbUpdateRecordOnTable(
                    db,
                    'files',
                    newFile,
                    dbTablesDesc=dbSchema,
                )
                #
                if not skipCommit:
                    db.commit()
                #
                messages = []
                return messages
        else:
            raise OstracionError('User has no write permission')
Esempio n. 11
0
def applyReindexingToImages(req, idxMap):
    """
        Apply an altered index-to-new-position map
        to the selected calendar images and build the response
        which cookifies the choice.
        Abstracts deletion and swaps among chosen calendar images.
    """
    response = redirect(url_for('calendarMakerImagesView'))
    currentCalendar = cookiesToCurrentCalendar(req.cookies)
    prevImages = currentCalendar.get('image_path_strings', [])
    images = [
        prevImages[idxMap.get(idx, idx)] for idx in range(len(prevImages))
        if idxMap.get(idx, idx) is not None if idxMap.get(idx, idx) >= 0
        if idxMap.get(idx, idx) < len(prevImages)
    ]
    dResponse = dressResponseWithCurrentCalendar(
        response,
        recursivelyMergeDictionaries({'image_path_strings': images},
                                     defaultMap=currentCalendar),
    )
    return dResponse
Esempio n. 12
0
def convertRoleRelatedRecord(db, legacySchema,
                             srcTableName, inRecord):
    if srcTableName == 'roles':
        isSystem = inRecord['system'] != 0
        outRecord = {
            'role_id': inRecord['role_id'],
            'role_class': determineRoleClass(inRecord),
            # 'system' DISAPPEARS
            'description': inRecord['description'],
            'can_box': (
                0
                if isSystem and inRecord['role_id'] == 'ticketer'
                else 1
            ),
            'can_user': (
                0
                if isSystem and inRecord['role_id'] == 'anonymous'
                else 1
            ),
            'can_delete': 0 if isSystem else 1,
        }
        return outRecord
    elif srcTableName in {'box_role_permissions', 'user_roles'}:
        referenceRole = dbRetrieveRecordByKey(
            db,
            'roles',
            {'role_id': inRecord['role_id']},
            dbTablesDesc=legacySchema,
        )
        outRecord = recursivelyMergeDictionaries(
            {'role_class': determineRoleClass(referenceRole)},
            defaultMap=inRecord,
        )
        return outRecord
    else:
        raise NotImplementedError('Cannot translate records for table "%s"' % (
            srcTableName,
        ))
Esempio n. 13
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
Esempio n. 14
0
def dbDeleteUser(db, username, user, fileStorageDirectory):
    """ Delete a user altogether. Return a fsDeletionQueue for deletions."""
    if username != '':
        if not userIsAdmin(db, dbGetUser(db, username)):
            try:
                if username == user.username or userIsAdmin(db, user):
                    fsDeleteQueue = []
                    # 1. cleanup of file system
                    rootBox = getRootBox(db)
                    fsDeleteQueue += _traverseForAccountDeletion(
                        db,
                        rootBox,
                        username,
                        user,
                        path=[''],
                        fileStorageDirectory=fileStorageDirectory,
                    )
                    # 2. deleting user-related data around
                    dbDeleteRecordsByKey(
                        db,
                        'user_roles',
                        {'username': username},
                        dbTablesDesc=dbSchema,
                    )
                    deleteeUser = dbGetUser(db, username)
                    if deleteeUser.icon_file_id != '':
                        fsDeleteQueue.append(fileIdToPath(
                            deleteeUser.icon_file_id,
                            fileStorageDirectory=fileStorageDirectory,
                        ))
                    dbDeleteRecordsByKey(
                        db,
                        'tickets',
                        {'username': username},
                        dbTablesDesc=dbSchema,
                    )
                    for u in dbGetAllUsers(db, user,
                                           accountDeletionInProgress=True):
                        if u.username != username:
                            if u.icon_file_id_username == username:
                                if u.icon_file_id != '':
                                    fsDeleteQueue.append(fileIdToPath(
                                        u.icon_file_id,
                                        fileStorageDirectory,
                                    ))
                                dbUpdateUser(
                                    db,
                                    User(**recursivelyMergeDictionaries(
                                        {
                                            'icon_file_id': '',
                                            'icon_file_id_username': '',
                                        },
                                        defaultMap=u.asDict(),
                                    )),
                                    user,
                                    skipCommit=True,
                                )
                    # 3. delete user-specific role association from boxes
                    dbDeleteRecordsByKey(
                        db,
                        'box_role_permissions',
                        {'role_class': 'user', 'role_id': username},
                        dbTablesDesc=dbSchema,
                    )
                    # 4. delete user-specific role
                    dbDeleteRecordsByKey(
                        db,
                        'roles',
                        {'role_class': 'user', 'role_id': username},
                        dbTablesDesc=dbSchema
                    )
                    # 5. finally, delete the user
                    dbDeleteRecordsByKey(
                        db,
                        'users',
                        {'username': username},
                        dbTablesDesc=dbSchema
                    )
                    db.commit()
                    return fsDeleteQueue
                else:
                    raise OstracionError('Insufficient permissions')
            except Exception as e:
                db.rollback()
                raise e
        else:
            raise OstracionError('Cannot delete an admin')
    else:
        raise OstracionError('Cannot alter system user')
Esempio n. 15
0
 'tasks': recursivelyMergeDictionaries(
     {
         'images': {
             'title': 'Images',
             'subtitle': ('Configure images '
                          '(icons and so on)'),
             'image_id': (
                 'admin_images',
                 'admin_settings_images'
             ),
             'endpoint_name': (
                 'adminHomeSettingsImagesView',
                 {},
             ),
         },
         'colors': {
             'title': 'Colors',
             'subtitle': ('Configure colors (for box, '
                          'file, task cards and so on)'),
             'image_id': (
                 'admin_images',
                 'admin_settings_colors'
             ),
             'endpoint_name': (
                 'adminHomeSettingsColorsView',
                 {},
             ),
         },
     },
     defaultMap={
         genericSettingKey: {
             'title': genericSettingInfo['pageTitle'],
             'subtitle': genericSettingInfo['pageSubtitle'],
             'image_id': (
                 'admin_images',
                 genericSettingInfo['image_id'],
             ),
             'endpoint_name': (
                 'adminHomeSettingsGenericView',
                 {'settingType': genericSettingKey},
             ),
         }
         for genericSettingKey, genericSettingInfo in (
             genericSettingsPageDesc.items()
         )
     }
 ),
Esempio n. 16
0
def calendarMakerSettingsView():
    """Calendar settings form view."""
    user = g.user
    db = dbGetDatabase()
    request._onErrorUrl = url_for('calendarMakerIndexView', )
    #
    currentCalendar = cookiesToCurrentCalendar(request.cookies)
    cProps = currentCalendar.get('properties', {})
    currentYear = datetime.datetime.now().year
    form = CalendarMakerPropertyForm()
    #
    if form.validate_on_submit():
        month0 = safeInt(form.month0.data, 1)
        year0 = form.year0.data
        month1 = safeInt(form.month1.data, 12)
        year1 = form.year1.data
        language = form.language.data
        startingweekday = safeInt(form.startingweekday.data, 6)
        response = redirect(url_for('calendarMakerIndexView'))
        dResponse = dressResponseWithCurrentCalendar(
            response,
            recursivelyMergeDictionaries(
                {
                    'properties': {
                        'month0': month0,
                        'year0': year0,
                        'month1': month1,
                        'year1': year1,
                        'language': language,
                        'startingweekday': startingweekday,
                    },
                },
                defaultMap=currentCalendar,
            ),
        )
        return dResponse
    else:
        form.month0.data = str(applyDefault(cProps.get('month0'), 1))
        form.year0.data = applyDefault(cProps.get('year0'), currentYear)
        form.month1.data = str(applyDefault(cProps.get('month1'), 12))
        form.year1.data = applyDefault(cProps.get('year1'), currentYear)
        form.language.data = applyDefault(cProps.get('language'), 'en')
        form.startingweekday.data = applyDefault(
            cProps.get('startingweekday'),
            6,
        )
        #
        pageFeatures = prepareTaskPageFeatures(
            appsPageDescriptor,
            ['root', 'calendar_maker', 'settings'],
            g,
        )
        #
        return render_template(
            'apps/calendarmaker/settings.html',
            user=user,
            bgcolor=g.settings['color']['app_colors']['calendar_maker_color']
            ['value'],
            form=form,
            **pageFeatures,
        )
Esempio n. 17
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,
        )
Esempio n. 18
0
             dbTablesDesc=dbSchema,
         )
         if itemDictFound is None:
             # new: insert
             print('inserting... ', end='')
             dbAddRecordToTable(
                 db,
                 tName,
                 model.asDict(),
                 dbTablesDesc=dbSchema,
             )
             print('done ', end='')
         else:
             # careful override and update back
             mergedDict = recursivelyMergeDictionaries(
                 {'value': itemDictFound['value']},
                 defaultMap=model.asDict(),
             )
             print('updating... ', end='')
             dbUpdateRecordOnTable(
                 db,
                 tName,
                 mergedDict,
                 dbTablesDesc=dbSchema,
             )
             print('done ', end='')
         print('#')
     print('        * done.')
 elif tName == 'links':
     # we may have to add a field
     columns = dbQueryColumns(db, tName)
     if 'title' not in columns:
Esempio n. 19
0
def metadataBoxView(boxPathString=''):
    """edit-metadata-of-box route."""
    user = g.user
    db = dbGetDatabase()
    boxPath = splitPathString(boxPathString)
    box = getBoxFromPath(db, boxPath, user)
    parentBox = getBoxFromPath(db, boxPath[:-1], user)
    request._onErrorUrl = url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:-1]),
    )
    #
    form = makeMakeBoxForm('Save')()
    if parentBox is None:
        # target box was root
        raise OstracionError('Cannot act on this object')
    else:
        if box is not None:
            #
            if form.validate_on_submit():
                newBox = Box(
                    **recursivelyMergeDictionaries(
                        {
                            'box_name': form.boxname.data,
                            'title': form.boxtitle.data,
                            'description': form.boxdescription.data,
                            'metadata_username': user.username,
                        },
                        defaultMap=box.asDict(),
                    )
                )
                updateBox(db, boxPath, newBox, user)
                return redirect(url_for(
                    'lsView',
                    lsPathString='/'.join(boxPath[1:-1]),
                ))
            else:
                form.boxname.data = applyDefault(
                    form.boxname.data,
                    box.box_name,
                )
                form.boxdescription.data = applyDefault(
                    form.boxdescription.data,
                    box.description,
                )
                form.boxtitle.data = applyDefault(
                    form.boxtitle.data,
                    box.title,
                )
                pathBCrumbs = makeBreadCrumbs(
                    boxPath,
                    g,
                    appendedItems=[{
                        'kind': 'link',
                        'target': None,
                        'name': 'Metadata',
                    }],
                )
                return render_template(
                    'makebox.html',
                    form=form,
                    user=user,
                    breadCrumbs=pathBCrumbs,
                    pageTitle='Edit box metadata',
                    pageSubtitle='Name and title are mandatory',
                    iconUrl=url_for(
                        'boxThumbnailView',
                        dummyId=box.icon_file_id + '_',
                        boxPathString='/'.join(boxPath[1:]),
                    ),
                )
            #
        else:
            raise OstracionWarning('Box not accessible')
    return redirect(url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:-1]),
    ))
Esempio n. 20
0
def dbUpdateStandardSettingDict(db,
                                enrichedSetting,
                                newFormValue,
                                user,
                                skipCommit=False):
    """ Update a non-image setting with a new value (taking care of
        deforming before the actual writing to DB).
    """
    if userIsAdmin(db, user):
        deformedValue = _deformSettingValueByType(
            enrichedSetting['setting'].type,
            newFormValue,
        )
        newSettingDict = recursivelyMergeDictionaries(
            {
                'value': deformedValue,
            },
            defaultMap={
                k: v
                for k, v in enrichedSetting['setting'].asDict().items()
                if k in {'value', 'icon_mime_type', 'group_id', 'id'}
            })
        #
        if (enrichedSetting['setting'].type == 'string'
                and enrichedSetting['metadata'].get('is_text_image', False)):
            # we handle the special case of deleting outdated
            # image-text that may have been produced
            #
            # this largerSettingDict is used only to determine the nextValue
            largerNextSettingDict = recursivelyMergeDictionaries(
                {
                    'value': deformedValue,
                },
                defaultMap={
                    k: v
                    for k, v in enrichedSetting['setting'].asDict().items()
                    if k in {'value', 'type', 'default_value'}
                })
            #
            prevValue = enrichedSetting['value']
            nextValue = _getValueFromSetting(Setting(**largerNextSettingDict))
            # if there is a picture-with-text to be superseded, delete it
            prevPath, prevTitle, prevTag = determineManagedTextImagePath(
                prevValue,
                prefix='%s/%s' % (
                    enrichedSetting['setting'].group_id,
                    enrichedSetting['setting'].id,
                ),
            )
            nextPath, nextTitle, nextTag = determineManagedTextImagePath(
                nextValue,
                prefix='%s/%s' % (
                    enrichedSetting['setting'].group_id,
                    enrichedSetting['setting'].id,
                ),
            )
            if prevTag != nextTag:
                prevFileName = os.path.join(
                    prevPath,
                    prevTitle,
                )
                if os.path.isfile(prevFileName):
                    # delete the old, unused file
                    os.remove(prevFileName)
        #
        dbUpdateRecordOnTable(db,
                              'settings',
                              newSettingDict,
                              dbTablesDesc=dbSchema,
                              allowPartial=True)
        if not skipCommit:
            db.commit()
    else:
        raise OstracionError('Insufficient permissions')
Esempio n. 21
0
def moveBox(db, box, srcBox, dstBox, user, skipCommit=False):
    """ Move 'box' from being contained in
        'srcBox' to being contained in 'dstBox'
        (with all involved permission checks).
    """
    if box.box_id == '':
        # nobody can touch root
        raise OstracionError('Cannot act on this object')
    else:
        if box.parent_id != srcBox.box_id:
            # consistency in request
            raise RuntimeError(
                'Parent mismatch between box to move and source box'
            )
        else:
            if box.parent_id == dstBox.box_id:
                raise OstracionError(
                    'Source and destination box are the same'
                )
            else:
                if not canDeleteBox(db, box, srcBox, user):
                    # must be able to remove from source
                    raise OstracionError(
                        'Insufficient permissions to move box away'
                    )
                else:
                    if not all(
                            userHasPermission(
                                db, user, dstBox.permissions, prm
                            )
                            for prm in {'w', 'c'}):
                        # must be able to upload and create to dest
                        raise OstracionError(
                            'Insufficient permissions to move boxes '
                            'to the destination box'
                        )
                    else:
                        # name clash check for destination
                        if isNameUnderParentBox(db, dstBox, box.box_name):
                            raise OstracionError(
                                'An object with that name '
                                'exists already'
                            )
                        else:
                            # check against box incest
                            if isAncestorBoxOf(db, box, dstBox):
                                raise OstracionError(
                                    'Cannot move box to a sub-box of itself'
                                )
                            else:
                                # perform the move
                                newBox = recursivelyMergeDictionaries(
                                    {'parent_id': dstBox.box_id},
                                    defaultMap=box.asDict(),
                                )
                                dbUpdateRecordOnTable(
                                    db,
                                    'boxes',
                                    newBox,
                                    dbTablesDesc=dbSchema,
                                )
                                #
                                if not skipCommit:
                                    db.commit()
                                return []
Esempio n. 22
0
def placeFSFileInBox(db,
                     user,
                     fileStorageDirectory,
                     box,
                     filePhysicalPath,
                     fileName,
                     fileDescription,
                     fileTextualMode='',
                     fileThumbnailFormat=None):
    """
        Given an actual file at a physical location,
        insert it as a Ostracion file by handling the
        filesystem DB as well as the actual file copy
        into the storage directories.
    """
    # can user write to box?
    if userHasPermission(db, user, box.permissions, 'w'):
        # is the name available?
        if not isNameUnderParentBox(db, box, fileName):
            protoFile = {
                'box_id': box.box_id,
                'name': fileName,
                'description': fileDescription,
                'date': datetime.datetime.now(),
            }
            userName = user.username
            newFile = File(**recursivelyMergeDictionaries(
                protoFile,
                defaultMap={
                    'creator_username': userName,
                    'icon_file_id_username': userName,
                    'metadata_username': userName,
                    'editor_username': userName,
                    'textual_mode': fileTextualMode,
                },
            ))
            filePath = fileIdToPath(
                newFile.file_id,
                fileStorageDirectory=fileStorageDirectory,
            )
            shutil.copy2(filePhysicalPath, filePath)
            #
            fileProperties = determineFileProperties(filePath)
            newFile.mime_type = fileProperties['file_mime_type']
            newFile.type = fileProperties['file_type']
            newFile.size = fileProperties['file_size']
            #
            if (fileThumbnailFormat is not None
                    and isImageMimeType(newFile.mime_type)):
                # thumbnail preparation
                fileThumbnailId, fileThumbnailMimeType = makeFileThumbnail(
                    newFile.file_id,
                    newFile.mime_type,
                    thumbnailFormat=fileThumbnailFormat,
                    fileStorageDirectory=fileStorageDirectory,
                )
                if fileThumbnailId is not None:
                    newFile.icon_file_id = fileThumbnailId
                    newFile.icon_mime_type = fileThumbnailMimeType
            #
            makeFileInParent(db, parentBox=box, newFile=newFile)
            db.commit()
        else:
            raise OstracionError('Cannot create a file with that name')
    else:
        raise OstracionError('User has no write permission on box')
Esempio n. 23
0
def setIconView(mode, itemPathString=''):
    """ Route to set/replace the thumbnail of various items."""
    if (mode == 'au' and not g.settings['behaviour']['behaviour_admin_powers']
        ['admin_is_god']['value']):
        request._onErrorUrl = url_for('adminHomeUsersView')
        raise OstracionError('This feature is turned off in the configuration')
    else:
        user = g.user
        form = UploadIconForm()
        db = dbGetDatabase()
        tempFileDirectory = g.settings['system']['system_directories'][
            'temp_directory']['value']
        fileStorageDirectory = g.settings['system']['system_directories'][
            'fs_directory']['value']
        if mode == 'b':
            boxPath = splitPathString(itemPathString)
            request._onErrorUrl = url_for(
                'lsView',
                lsPathString='/'.join(boxPath[1:]),
            )
            parentBox = None
            thisItem = getBoxFromPath(db, boxPath, user)
            itemName = thisItem.getName()
            pageFeatures = {
                'breadCrumbs':
                makeBreadCrumbs(
                    splitPathString(itemPathString),
                    g,
                    appendedItems=[{
                        'kind': 'link',
                        'target': None,
                        'name': 'Icon',
                    }],
                ),
            }
        elif mode == 'f':
            fullPath = splitPathString(itemPathString)
            boxPath, fileName = fullPath[:-1], fullPath[-1]
            request._onErrorUrl = url_for(
                'lsView',
                lsPathString='/'.join(boxPath[1:]),
            )
            parentBox = getBoxFromPath(db, boxPath, user)
            thisItem = getFileFromParent(db, parentBox, fileName, user)
            itemName = thisItem.getName()
            pageFeatures = {
                'breadCrumbs':
                makeBreadCrumbs(
                    splitPathString(itemPathString)[:-1],
                    g,
                    appendedItems=[{
                        'kind': 'file',
                        'target': thisItem,
                    }, {
                        'kind': 'link',
                        'target': None,
                        'name': 'Icon',
                    }],
                ),
            }
        elif mode == 'l':
            fullPath = splitPathString(itemPathString)
            boxPath, linkName = fullPath[:-1], fullPath[-1]
            request._onErrorUrl = url_for(
                'lsView',
                lsPathString='/'.join(boxPath[1:]),
            )
            parentBox = getBoxFromPath(db, boxPath, user)
            thisItem = getLinkFromParent(db, parentBox, linkName, user)
            itemName = thisItem.getName()
            pageFeatures = {
                'breadCrumbs':
                makeBreadCrumbs(
                    splitPathString(itemPathString)[:-1],
                    g,
                    appendedItems=[{
                        'kind': 'external_link',
                        'target': thisItem,
                    }, {
                        'kind': 'link',
                        'target': None,
                        'name': 'Icon',
                    }],
                ),
            }
        elif mode == 'u':
            pageFeatures = prepareTaskPageFeatures(
                userProfilePageDescriptor,
                ['root', 'icon'],
                g,
                overrides={
                    'pageTitle': None,
                    'pageSubtitle': None,
                    'iconUrl': None,
                },
            )
            thisItem = user
            itemName = thisItem.getName()
            parentBox = None
        elif mode == 'au':
            pageFeatures = prepareTaskPageFeatures(
                adminPageDescriptor,
                ['root', 'users'],
                g,
                appendedItems=[{
                    'kind': 'link',
                    'link': False,
                    'target': None,
                    'name': 'Icon',
                }],
                overrides={
                    'pageTitle': None,
                    'pageSubtitle': None,
                    'iconUrl': None,
                },
            )
            if userIsAdmin(db, user):
                thisItem = dbGetUser(db, itemPathString)
                itemName = thisItem.getName()
                parentBox = None
            else:
                raise OstracionError('Insufficient permissions')
        elif mode == 's':
            pageFeatures = prepareTaskPageFeatures(
                adminPageDescriptor,
                ['root', 'settings', 'images'],
                g,
                appendedItems=[{
                    'kind': 'link',
                    'link': False,
                    'target': None,
                    'name': 'Set image',
                }],
                overrides={
                    'pageTitle': None,
                    'pageSubtitle': None,
                    'iconUrl': None,
                },
            )
            if userIsAdmin(db, user):
                settingGroupId, settingId = itemPathString.split('/')
                thisItem = g.settings['image'][settingGroupId][settingId]
                itemName = thisItem['setting'].getName()
                parentBox = None
            else:
                raise OstracionError('Insufficient permissions')
        else:
            raise RuntimeError('Unknown mode encountered')
        #
        if form.validate_on_submit():
            #
            storageSuccess = storeFileAsThumbnail(
                db,
                fileToSave=form.file.data,
                mode=mode,
                thumbnailFormat=determineThumbnailFormatByModeAndTarget(
                    db,
                    mode,
                    thisItem,
                ),
                targetItem=thisItem,
                parentBox=parentBox,
                user=user,
                tempFileDirectory=tempFileDirectory,
                fileStorageDirectory=fileStorageDirectory,
            )
            if not storageSuccess:
                raise OstracionError('Could not set the icon')
            #
            if mode in {'f', 'b', 'l'}:
                return redirect(
                    url_for(
                        'lsView',
                        lsPathString='/'.join(boxPath[1:-1] if mode ==
                                              'b' else boxPath[1:]),
                    ))
            elif mode == 'u':
                return redirect(url_for('userProfileView', ))
            elif mode == 'au':
                return redirect(url_for('adminHomeUsersView', ))
            elif mode == 's':
                return redirect(url_for('adminHomeSettingsImagesView', ))
            else:
                raise RuntimeError('Unknown mode encountered')
        else:
            #
            titleMap = {
                'f': 'Set File Icon',
                'l': 'Set Link Icon',
                'b': 'Set Box Icon',
                'u': 'Set User Icon',
                'au': 'Set User Icon (as admin)',
                's': 'Set Application Image',
            }
            modeNameMap = {
                'f': 'for file',
                'l': 'for link',
                'b': 'for box',
                'u': 'for user',
                'au': '(as admin) for user',
                's': 'for setting',
            }
            finalPageFeatures = recursivelyMergeDictionaries(
                {
                    'pageTitle':
                    titleMap[mode],
                    'pageSubtitle':
                    'Upload an image file %s "%s"' % (
                        modeNameMap[mode],
                        itemName,
                    ),
                },
                defaultMap=pageFeatures,
            )
            if mode == 'u':
                finalPageFeatures['iconUrl'] = url_for(
                    'userThumbnailView',
                    dummyId='%s_' % thisItem.icon_file_id,
                    username=thisItem.username,
                )
            elif mode == 'au':
                finalPageFeatures['iconUrl'] = url_for(
                    'userThumbnailView',
                    dummyId='%s_' % thisItem.icon_file_id,
                    username=thisItem.username,
                )
            elif mode == 's':
                finalPageFeatures['iconUrl'] = makeSettingImageUrl(
                    g,
                    settingGroupId,
                    settingId,
                )
            elif mode == 'b':
                finalPageFeatures['iconUrl'] = url_for(
                    'boxThumbnailView',
                    dummyId=thisItem.icon_file_id + '_',
                    boxPathString='/'.join(boxPath[1:]),
                )
            elif mode == 'f':
                finalPageFeatures['iconUrl'] = url_for(
                    'fileThumbnailView',
                    dummyId=thisItem.icon_file_id + '_',
                    fsPathString='/'.join(boxPath[1:] + [thisItem.name]),
                )
            elif mode == 'l':
                finalPageFeatures['iconUrl'] = url_for(
                    'linkThumbnailView',
                    dummyId=thisItem.icon_file_id + '_',
                    fsPathString='/'.join(boxPath[1:] + [thisItem.name]),
                )
            #
            return render_template(
                'uploadicon.html',
                form=form,
                user=user,
                mode=mode,
                itemPathString=itemPathString,
                **finalPageFeatures,
            )
Esempio n. 24
0
def saveAndAnalyseFilesInBox(db,
                             files,
                             parentBox,
                             user,
                             thumbnailFormat,
                             fileStorageDirectory,
                             pastActionVerbForm='uploaded'):
    """ Save files and enrich them with type/mimetype,
        unless something fails - this handles overwrites
        (file-on-file) and blockades (file has same name as box)
    """
    #
    # checking for name clashes with boxes
    if any(
            isBoxNameUnderParentBox(db, parentBox, fName)
            for fName in (fObj['name'] for fObj in files)):
        raise OstracionError('Files cannot have the name of existing boxes')
    else:
        if not userHasPermission(db, user, parentBox.permissions, 'w'):
            raise OstracionError('User has no write permission on this box')
        else:
            userName = user.username
            fsDeletionQueue = []
            numReplacements = 0
            #
            for file in files:
                newFile = File(**recursivelyMergeDictionaries(
                    {k: v
                     for k, v in file.items() if k != 'fileObject'},
                    defaultMap={
                        'creator_username': userName,
                        'icon_file_id_username': userName,
                        'metadata_username': userName,
                        'editor_username': userName,
                        'textual_mode': 'plain',
                    },
                ))
                # are we overwriting a file?
                if isFileNameUnderParentBox(db, parentBox, newFile.name):
                    # delete the old file entry
                    # AND mark the file and its thumbnail
                    # (if any) for later deletion
                    prevFile = getFileFromParent(
                        db,
                        parentBox,
                        newFile.name,
                        user,
                    )
                    fsDeletionQueue += deleteFile(
                        db,
                        parentBox,
                        prevFile,
                        user,
                        fileStorageDirectory=fileStorageDirectory,
                        skipCommit=True,
                    )
                    numReplacements += 1
                #
                filePath = fileIdToPath(
                    newFile.file_id,
                    fileStorageDirectory=fileStorageDirectory,
                )
                file['fileObject'].save(filePath)
                #
                fileProperties = determineFileProperties(filePath)
                newFile.mime_type = fileProperties['file_mime_type']
                newFile.type = fileProperties['file_type']
                newFile.size = fileProperties['file_size']
                #
                if (thumbnailFormat is not None
                        and isImageMimeType(newFile.mime_type)):
                    # thumbnail preparation
                    fileThumbnailId, fileThumbnailMimeType = makeFileThumbnail(
                        newFile.file_id,
                        newFile.mime_type,
                        thumbnailFormat=thumbnailFormat,
                        fileStorageDirectory=fileStorageDirectory,
                    )
                    if fileThumbnailId is not None:
                        newFile.icon_file_id = fileThumbnailId
                        newFile.icon_mime_type = fileThumbnailMimeType
                #
                makeFileInParent(db, parentBox=parentBox, newFile=newFile)
            flushFsDeleteQueue(fsDeletionQueue)
            db.commit()
            return '%i file%s %s successfully%s.' % (
                len(files), '' if len(files) == 1 else 's', pastActionVerbForm,
                '' if numReplacements == 0 else
                (' (%i replaced)' % numReplacements))