Пример #1
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')
Пример #2
0
def dbRevokeRoleFromUser(db, role, targetUser, user):
    """Revoke a role from a user, i.e. ungrant it."""
    if userIsAdmin(db, user):
        grantedRoleKeys = {r.roleKey() for r in targetUser.roles}
        if role.roleKey() not in grantedRoleKeys:
            raise OstracionError('Role is not granted to user')
        else:
            # delicate checks: cannot remove 'admin' from self
            if (user.username == targetUser.username
                    and role.roleKey() == ('system', 'admin')):
                raise OstracionError('Cannot revoke "admin" role from self')
            else:
                dbDeleteRecordsByKey(
                    db,
                    'user_roles',
                    {
                        'username': targetUser.username,
                        'role_class': role.role_class,
                        'role_id': role.role_id,
                    },
                    dbTablesDesc=dbSchema,
                )
                db.commit()
    else:
        raise OstracionError('Insufficient permissions')
Пример #3
0
def dbDeleteRole(db, roleClass, roleId, user):
    """ Delete a role from DB."""
    if userIsAdmin(db, user):
        role = dbGetRole(db, roleClass, roleId, user)
        if role.can_delete == 0:
            raise OstracionError('Role cannot be deleted')
        else:
            dbDeleteRecordsByKey(
                db,
                'box_role_permissions',
                {
                    'role_class': role.role_class,
                    'role_id': role.role_id
                },
                dbTablesDesc=dbSchema,
            )
            dbDeleteRecordsByKey(
                db,
                'roles',
                {
                    'role_class': role.role_class,
                    'role_id': role.role_id
                },
                dbTablesDesc=dbSchema,
            )
            db.commit()
    else:
        raise OstracionError('Insufficient permissions')
Пример #4
0
def dbGrantRoleToUser(db, role, targetUser, user):
    """Assign a role to a user, i.e. grant it."""
    if userIsAdmin(db, user):
        grantedRoleKeys = {r.roleKey() for r in targetUser.roles}
        if role.can_user == 0:
            raise OstracionError('Role cannot be granted to users')
        elif role.roleKey() in grantedRoleKeys:
            raise OstracionError('Role is already granted to user')
        else:
            #
            newUserRole = UserRole(
                username=targetUser.username,
                role_class=role.role_class,
                role_id=role.role_id,
            )
            dbAddRecordToTable(
                db,
                'user_roles',
                newUserRole.asDict(),
                dbTablesDesc=dbSchema,
            )
            #
            db.commit()
    else:
        raise OstracionError('Insufficient permissions')
Пример #5
0
def duplicateImageForCalendar(src, dst):
    """
        Given a source file (e.g. a standard Ostracion physical filepath)
        and a destination filepath to create (with extension, amenable to
        LaTeX), generate the latter and return its path.
        May be a simple symlink or a new, capped-res file, to optimize
        calendar pdf for file size.
    """
    args = [
        'convert',
        src,
        '-resize',
        '%ix>' % maxCalendarImageResolutionWidth,
        dst,
    ]
    imgDuplicationOutput = subprocess.run(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    if imgDuplicationOutput.returncode == 0:
        if os.path.isfile(dst):
            return dst
        else:
            raise OstracionError('Could not resize input image')
            return None
    else:
        raise OstracionError('Could not resize input image')
        return None
Пример #6
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')
Пример #7
0
def makeCalendarPdf(properties, imageTexPaths, coverImageTexPath,
                    workingDirectory, pdfTitle):
    """
        Generate the pdf of a calendar given its properties.
        Uses 'pdflatex' under the hood.

        Input
            properties:         a dictionary with all required properties
            imageTexPaths:      an array of physical-files-to-use
            coverImageTexPath:  a single path to the cover physical-image-file
            workingDirectory:   where to generate all files (incl. final pdf)
            pdfTitle:           pdf-name, without extension

        Output
            pdfTitleOrNone, [tempFileToDelete_1, ...]

        pdfTitleOrNone is None upon failures.
        It is care of the caller to arrange deletion of temporary files.
    """
    # generating
    calendarStructure = makeCalendarStructure(properties, imageTexPaths,
                                              coverImageTexPath)
    outputTexFile = '%s.tex' % pdfTitle
    outputPdfFile = '%s.pdf' % pdfTitle
    outputTexPath = os.path.join(workingDirectory, outputTexFile)
    outputPdfPath = os.path.join(workingDirectory, outputPdfFile)
    makeCalendarTexfile(calendarStructure, outputTexPath)
    # compiling, checking+returning the resulting file
    pdfMakingOutput = subprocess.run(
        [
            'timeout',
            '%is' % pdfGenerationTimeoutSeconds,
            'pdflatex',
            '-halt-on-error',
            outputTexFile,
        ],
        cwd=workingDirectory,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    if pdfMakingOutput.returncode == 0:
        if os.path.isfile(outputPdfPath):
            finalPdfPath = outputPdfPath
        else:
            raise OstracionError('Could not retrieve generated calendar')
            finalPdfPath = None
    else:
        raise OstracionError('Calendar generation command failed')
        finalPdfPath = None
    temporaryFiles = [
        os.path.join(workingDirectory, '%s.%s' % (pdfTitle, extension))
        for extension in ['tex', 'log', 'aux']
    ]
    return finalPdfPath, temporaryFiles
Пример #8
0
def dbMakeUserInvitationTicket(db, ticketName, validityHours, userName,
                               userFullName, userEmail, ticketMessage, user,
                               urlRoot, settings):
    """ Generate a ticket to be used to create a user
        (with/out username pre-specified.

        This is an admin-only operation.
    """
    if isTicketIssuablePerSettings(validityHours, 1, settings):
        '''
            only admins can do this by design
        '''
        if userIsAdmin(db, user):
            ticketId, securityCode = randomTicketNumbers(user)
            issueDate = datetime.datetime.now()
            metadata = {
                k: v
                for k, v in {
                    'username': userName,
                    'fullname': userFullName,
                    'email': userEmail,
                    'message': ticketMessage,
                }.items() if v is not None
            }
            expirationDate = None if validityHours is None else (
                issueDate + datetime.timedelta(hours=validityHours))
            newTicket = Ticket(
                ticket_id=ticketId,
                name=ticketName,
                security_code=securityCode,
                username=user.username,
                issue_date=issueDate,
                expiration_date=expirationDate,
                multiplicity=1,
                target_type='user',
                metadata=json.dumps(metadata),
                last_redeemed=None,
                times_redeemed=0,
            )
            #
            dbAddRecordToTable(
                db,
                'tickets',
                newTicket.asDict(),
                dbTablesDesc=dbSchema,
            )
            db.commit()
            return makeTicketMagicLink(newTicket, urlRoot)
        else:
            raise OstracionError('Insufficient permissions')
    else:
        raise OstracionError(
            'Ticket parameters not allowed under the current settings')
Пример #9
0
def updateBox(
        db, path, newBox, user,
        accountDeletionInProgress=False, skipCommit=False):
    """ Update the fields of a box on DB."""
    #
    # we check box_id is unchanged for updating
    prevBox = getBoxFromPath(
        db,
        path,
        user,
        accountDeletionInProgress=accountDeletionInProgress,
    )
    parentBox = getBoxFromPath(
        db,
        path[:-1],
        user,
        accountDeletionInProgress=accountDeletionInProgress,
    )
    if newBox.box_id != prevBox.box_id:
        raise RuntimeError('Box ID mismatch')
    else:
        if (
                not accountDeletionInProgress and
                not userHasPermission(db, user, prevBox.permissions, 'w')):
            raise OstracionError('User is not allowed to edit box')
        else:
            if not isNameUnderParentBox(
                    db,
                    parentBox,
                    newBox.box_name,
                    excludedIds=[('box', newBox.box_id)]):
                newBoxItem = Box(**{
                    k: v
                    for k, v in newBox.asDict().items()
                    if k not in {
                        'dvector_box_name',
                        'dvector_title',
                        'dvector_description',
                    }
                })
                dbUpdateRecordOnTable(
                    db,
                    'boxes',
                    newBoxItem.asDict(),
                    dbTablesDesc=dbSchema,
                )
                if not skipCommit:
                    db.commit()
            else:
                raise OstracionError('Name already exists')
Пример #10
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')
Пример #11
0
def dbDeleteTicket(db, ticketId, user, mode, skipCommit=False):
    """ Remove a ticket from DB."""
    ticketDict = dbRetrieveRecordByKey(
        db,
        'tickets',
        {'ticket_id': ticketId},
        dbTablesDesc=dbSchema,
    )
    if (ticketDict is not None and
            ticketTargetTypeToModeNameMap[ticketDict['target_type']] == mode):
        ticket = Ticket(**ticketDict)
        if userIsAdmin(db, user) or user.username == ticket.username:
            #
            dbDeleteRecordsByKey(
                db,
                'tickets',
                {'ticket_id': ticketId},
                dbTablesDesc=dbSchema,
            )
            if not skipCommit:
                db.commit()
        else:
            raise OstracionError('Insufficient permissions')
    else:
        raise OstracionWarning('Ticket unavailable')
Пример #12
0
def deleteLink(
        db, parentBox, link, user, fileStorageDirectory,
        skipCommit=False, accountDeletionInProgress=False):
    """ Delete a link (either because permissions allow it
        or the caller is working as part of an account deletion,
        in which case the caller is responsible for lifting
        permission checks).
        Returns the filesystem delete queue.
    """
    if (accountDeletionInProgress or
            userHasPermission(db, user, parentBox.permissions, 'w')):
        #
        fsDeleteQueue = (
            [
                fileIdToPath(
                    link.icon_file_id,
                    fileStorageDirectory=fileStorageDirectory,
                )
            ]
            if link.icon_file_id != '' else []
        )
        dbDeleteRecordsByKey(
            db,
            'links',
            {'link_id': link.link_id},
            dbTablesDesc=dbSchema,
        )
        if not skipCommit:
            db.commit()
        return fsDeleteQueue
    else:
        raise OstracionError('User has no write permission')
Пример #13
0
def calendarMakerBrowseBoxView(mode):
    """
        Three-way view to manage image-selection browsing box: handles
            reset
            initiate box selection (through preparePickBoxPageView)
            complete box selection
    """
    user = g.user
    db = dbGetDatabase()
    request._onErrorUrl = url_for('calendarMakerImagesView', )
    if mode == 'start':
        rootBox = getRootBox(db)
        return preparePickBoxPageView(
            db=db,
            user=user,
            callbackUrl=url_for('calendarMakerBrowseBoxView', mode='end'),
            startBox=rootBox,
            message='Choose box to browse images from',
        )
    elif mode == 'end':
        chosenBoxObjPathBlob = request.args.get('chosenBoxObjPath')
        chosenBoxObjPath = urllib.parse.unquote_plus(chosenBoxObjPathBlob)
        response = redirect(url_for('calendarMakerImagesView'))
        response.set_cookie('apps_calendarmaker_browsebox', chosenBoxObjPath)
        return response
    elif mode == 'clear':
        response = redirect(url_for('calendarMakerImagesView'))
        response.set_cookie('apps_calendarmaker_browsebox', '', expires=0)
        return response
    else:
        raise OstracionError('Malformed request')
Пример #14
0
def _recursiveBoxDeletion(
        db, box, parentBox, user,
        fileStorageDirectory, accountDeletionInProgress=False):
    """ Take care of deleting a box, invoking itself on children boxes
        and erasing contained files, joining the results (the delete queue)
        accumulated in the sub-deletions. Used internaly by deleteBox.
    """
    if box.box_id == '':
        raise OstracionError('Box cannot be deleted')
    else:
        if (accountDeletionInProgress or
                (
                    userHasPermission(db, user, box.permissions, 'w') and
                    userHasPermission(db, user, parentBox.permissions, 'c')
                )):
            fsDeleteQueue = ([fileIdToPath(
                box.icon_file_id,
                fileStorageDirectory=fileStorageDirectory,
            )]) if box.icon_file_id != '' else []
            allChildren = list(getBoxesFromParent(db, box, user))
            if any(c is None for c in allChildren):
                raise OstracionError('User is not allowed to delete box')
            #
            for c in allChildren:
                if c is not None:
                    fsDeleteQueue += _recursiveBoxDeletion(
                        db, c, box, user,
                        fileStorageDirectory=fileStorageDirectory,
                        accountDeletionInProgress=accountDeletionInProgress)
            allChildFiles = getFilesFromBox(db, box)
            for f in allChildFiles:
                fsDeleteQueue += deleteFile(
                    db, box, f, user,
                    fileStorageDirectory=fileStorageDirectory,
                    skipCommit=True,
                    accountDeletionInProgress=accountDeletionInProgress)
            # actual deletion
            dbDeleteRecordsByKey(
                db, 'box_role_permissions', {'box_id': box.box_id},
                dbTablesDesc=dbSchema)
            dbDeleteRecordsByKey(
                db, 'boxes', {'box_id': box.box_id},
                dbTablesDesc=dbSchema)
            return fsDeleteQueue
        else:
            raise OstracionError('User is not allowed to delete box')
Пример #15
0
def dbDeleteBoxRolePermission(db,
                              boxId,
                              roleClass,
                              roleId,
                              user,
                              skipCommit=False):
    """Remove a permission set (i.e. for a role) from a box."""
    if boxId == '':
        raise OstracionError('Cannot delete root box permissions')
    else:
        if userIsAdmin(db, user):
            recordExists = len(
                list(
                    dbRetrieveRecordsByKey(
                        db,
                        'box_role_permissions',
                        {
                            'box_id': boxId,
                            'role_class': roleClass,
                            'role_id': roleId,
                        },
                        dbTablesDesc=dbSchema,
                    ))) != 0
            if recordExists:
                try:
                    dbDeleteRecordsByKey(
                        db,
                        'box_role_permissions',
                        {
                            'box_id': boxId,
                            'role_class': roleClass,
                            'role_id': roleId,
                        },
                        dbTablesDesc=dbSchema,
                    )
                    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')
Пример #16
0
def dbCreateRole(db, newRole, user):
    """Create a new role in DB."""
    if userIsAdmin(db, user):
        if dbGetRole(db, newRole.role_class, newRole.role_id, user) is None:
            if newRole.can_delete == 0:
                raise OstracionError('Manual roles must be deletable')
            else:
                dbAddRecordToTable(
                    db,
                    'roles',
                    newRole.asDict(),
                    dbTablesDesc=dbSchema,
                )
                db.commit()
        else:
            raise OstracionWarning('Role "%s/%s" exists already' %
                                   newRole.roleKey())
    else:
        raise OstracionError('Insufficient permissions')
Пример #17
0
def dbInsertBoxRolePermission(db,
                              newBoxRolePermission,
                              user,
                              skipCommit=False):
    """Add a new permission-set (i.e. tied to a role) to a box."""
    if newBoxRolePermission.box_id == '':
        raise OstracionError('Cannot add a permission to root box')
    else:
        # system/admin cannot be added/removed
        if newBoxRolePermission.roleKey() == ('system', 'admin'):
            raise OstracionError('Cannot add permissions for admin role')
        else:
            role = dbGetRole(
                db,
                newBoxRolePermission.role_class,
                newBoxRolePermission.role_id,
                user,
            )
            if role is not None:
                # the role must have can_box attribute
                if role.can_box == 0:
                    raise OstracionError(
                        'Cannot add permissions for this role')
                else:
                    if userIsAdmin(db, user):
                        try:
                            dbAddRecordToTable(
                                db,
                                'box_role_permissions',
                                newBoxRolePermission.asDict(),
                                dbTablesDesc=dbSchema,
                            )
                            if not skipCommit:
                                db.commit()
                        except Exception as e:
                            db.rollback()
                            raise e
                    else:
                        raise OstracionError('Insufficient permissions')
            else:
                raise OstracionError('Could not find role')
Пример #18
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')
Пример #19
0
def makeBoxInParent(db, parentBox, newBox, user, skipCommit=False):
    """ Create a box, with name newBox, in parentBox
        on behalf of 'user'. Does all permission/name availability checks.
    """
    # first we check user has permission to create boxes here
    if not userHasPermission(db, user, parentBox.permissions, 'c'):
        raise OstracionError('User is not allowed to create boxes')
    else:
        # then we check there are no children with same name in the parent
        if not isNameUnderParentBox(db, parentBox, newBox.box_name):
            # now we create
            dbAddRecordToTable(
                db,
                'boxes',
                newBox.asDict(),
                dbTablesDesc=dbSchema,
            )
            if not skipCommit:
                db.commit()
        else:
            raise OstracionError('Name already exists')
Пример #20
0
def dbUpdateUser(db, newUser, user, skipCommit=False):
    """Update some columns of a user row."""
    if newUser.username != '':
        dbUpdateRecordOnTable(
            db,
            'users',
            newUser.asDict(),
            dbTablesDesc=dbSchema,
        )
        if not skipCommit:
            db.commit()
    else:
        raise OstracionError('Cannot alter system user')
Пример #21
0
def deleteBoxView(boxPathString=''):
    """RMBOX route."""
    user = g.user
    db = dbGetDatabase()
    fileStorageDirectory = g.settings['system']['system_directories'][
        'fs_directory']['value']
    boxPath = splitPathString(boxPathString)
    box = getBoxFromPath(db, boxPath, user)
    parentBox = getBoxFromPath(db, boxPath[:-1], user)
    request._onErrorUrl = url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:-1]),
    )
    #
    canDelete = canDeleteBox(db, box, parentBox, user)
    #
    if canDelete:
        if parentBox is None:
            # deletee box was root
            raise OstracionError('Cannot act on this object')
        else:
            if box is not None:
                fsDeleteQueue = deleteBox(
                    db,
                    box,
                    parentBox,
                    user,
                    fileStorageDirectory=fileStorageDirectory,
                )
                flushFsDeleteQueue(fsDeleteQueue)
            else:
                raise OstracionError('Box not accessible')
    else:
        raise OstracionError('Cannot delete this box')
    return redirect(url_for(
        'lsView',
        lsPathString='/'.join(boxPath[1:-1]),
    ))
Пример #22
0
def dbGetAllUsers(db, user, accountDeletionInProgress=False):
    """Get a listing of all existing users (except the '' system user)."""
    if accountDeletionInProgress or userIsAdmin(db, user):
        return (
            User(**u)
            for u in dbRetrieveAllRecords(
                db,
                'users',
                dbTablesDesc=dbSchema,
            )
            if u['username'] != ''
        )
    else:
        raise OstracionError('Insufficient permissions')
Пример #23
0
def makeFileInParent(db, parentBox, newFile):
    """ Create a file object in a box."""
    if newFile.box_id != parentBox.box_id:
        raise RuntimeError('wrong parent box id in makeFileInParent')
    else:
        if not isBoxNameUnderParentBox(db, parentBox, newFile.name):
            dbAddRecordToTable(
                db,
                'files',
                newFile.asDict(),
                dbTablesDesc=dbSchema,
            )
            db.commit()
        else:
            raise OstracionError('Name already exists')
Пример #24
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')
Пример #25
0
def dbPunchTicket(db, mode, ticketId, securityCode, urlRoot,
                  protectBannedUserTickets):
    """Retrieve/enrich a ticket and punch it with dbPunchRichTicket."""
    richTicket = dbGetEnrichAndCheckTicket(
        db,
        mode,
        ticketId,
        securityCode,
        urlRoot,
    )
    issuer = (dbGetUser(db, richTicket['ticket'].username)
              if richTicket is not None else None)
    if (issuer is not None
            and (not protectBannedUserTickets or issuer.banned == 0)):
        dbPunchRichTicket(db, richTicket)
    else:
        raise OstracionError('Not allowed to punch ticket')
Пример #26
0
def dbUpdateRole(db, newRole, user):
    """Update role metadata on DB."""
    if userIsAdmin(db, user):
        dbUpdateRecordOnTable(
            db,
            'roles',
            {
                k: v
                for k, v in newRole.asDict().items()
                if k in {'description', 'role_class', 'role_id'}
            },
            dbTablesDesc=dbSchema,
            allowPartial=True,
        )
        db.commit()
    else:
        raise OstracionError('Insufficient permissions')
Пример #27
0
def dbMakeGalleryTicket(db, ticketName, validityHours, multiplicity,
                        ticketMessage, box, boxPath, user, urlRoot, settings):
    """ Generate a gallery-view ticket on a
        box (with the specified ticket settings).
    """
    if isTicketIssuablePerSettings(validityHours, multiplicity, settings):
        ticketId, securityCode = randomTicketNumbers(user)
        issueDate = datetime.datetime.now()
        metadata = {
            k: v
            for k, v in {
                'box_id': box.box_id,
                'box_path': boxPath,
                'box_name': box.box_name,
                'box_title': box.title,
                'message': ticketMessage,
            }.items() if v is not None
        }
        expirationDate = None if validityHours is None else (
            issueDate + datetime.timedelta(hours=validityHours))
        newTicket = Ticket(
            ticket_id=ticketId,
            name=ticketName,
            security_code=securityCode,
            username=user.username,
            issue_date=issueDate,
            expiration_date=expirationDate,
            multiplicity=multiplicity,
            target_type='gallery',
            metadata=json.dumps(metadata),
            last_redeemed=None,
            times_redeemed=0,
        )
        #
        dbAddRecordToTable(
            db,
            'tickets',
            newTicket.asDict(),
            dbTablesDesc=dbSchema,
        )
        db.commit()
        return makeTicketMagicLink(newTicket, urlRoot)
    else:
        raise OstracionError(
            'Ticket parameters not allowed under the current settings')
Пример #28
0
def dbGetUsersByRole(db, roleClass, roleId, user):
    """ Get all users with a given roleId attached.

        In particular, a list of "UserRole" instances is
        returned, whose userid is to be inspected.
    """
    if userIsAdmin(db, user):
        return (UserRole(**u) for u in dbRetrieveRecordsByKey(
            db,
            'user_roles',
            {
                'role_id': roleId,
                'role_class': roleClass
            },
            dbTablesDesc=dbSchema,
        ))
    else:
        raise OstracionError('Insufficient permissions')
Пример #29
0
def calendarMakerDestBoxView(mode):
    """
        Three-way view to manage pdf destination box: handles
            reset
            initiate box selection (through preparePickBoxPageView)
            complete box selection
    """
    user = g.user
    db = dbGetDatabase()
    request._onErrorUrl = url_for('calendarMakerIndexView', )
    rootBox = getRootBox(db)
    if mode == 'start':

        def writableRichBoxPicker(rBox):
            return userHasPermission(db, user, rBox['box'].permissions, 'w')

        return preparePickBoxPageView(
            db=db,
            user=user,
            callbackUrl=url_for('calendarMakerDestBoxView', mode='end'),
            startBox=rootBox,
            predicate=writableRichBoxPicker,
            message='Choose the box where the calendar will be created',
        )
    elif mode == 'end':
        chosenBoxObjPathBlob = request.args.get('chosenBoxObjPath')
        chosenBoxObjPath = urllib.parse.unquote_plus(chosenBoxObjPathBlob)
        response = redirect(url_for('calendarMakerIndexView'))
        response.set_cookie('apps_calendarmaker_destbox', chosenBoxObjPath)
        return response
    elif mode == 'clear':
        response = redirect(url_for('calendarMakerIndexView'))
        response.set_cookie('apps_calendarmaker_destbox', '', expires=0)
        return response
    else:
        raise OstracionError('Malformed request')
Пример #30
0
def calendarMakerGenerateCalendar():
    """
        Calendar actual generation view.
        Handles everything:
            building temporary image files
            driving the engine functions to make the pdf
            inserting the pdf in the box
            removing temporary files
    """
    user = g.user
    db = dbGetDatabase()
    request._onErrorUrl = url_for('calendarMakerIndexView', )
    #
    destBoxString = request.cookies.get('apps_calendarmaker_destbox')
    currentCalendar = cookiesToCurrentCalendar(request.cookies)
    coverImagePathString = currentCalendar.get('cover_image_path_string')
    calendarImagePaths = currentCalendar.get('image_path_strings', [])
    cProps = currentCalendar.get('properties', {})
    #
    if destBoxString is None:
        destBox = None
    else:
        destBoxPath = splitPathString(destBoxString)
        destBox = getBoxFromPath(db, destBoxPath, user)
    if coverImagePathString is None:
        coverImageFileObject = None
    else:
        coverImageFileObject = pathToFileStructure(
            db,
            user,
            coverImagePathString,
        )
    #
    calendarImages = [
        pathToFileStructure(db, user, imgPath)
        for imgPath in calendarImagePaths
    ]
    numRequiredImages = countMonths(
        cProps.get('year0'),
        cProps.get('month0'),
        cProps.get('year1'),
        cProps.get('month1'),
    )
    if (destBox is None or coverImageFileObject is None
            or any([ci is None
                    for ci in calendarImages]) or numRequiredImages is None
            or numRequiredImages > len(calendarImages)):
        raise OstracionError('Cannot generate calendar')
    else:
        fileStorageDirectory = g.settings['system']['system_directories'][
            'fs_directory']['value']
        # proceed with generation
        tempFileDirectory = g.settings['system']['system_directories'][
            'temp_directory']['value']
        mkDirP(tempFileDirectory)
        texImageCoverPath = duplicateImageForCalendar(
            fileIdToPath(
                coverImageFileObject['file'].file_id,
                fileStorageDirectory=fileStorageDirectory,
            ),
            os.path.join(
                tempFileDirectory, '%s.%s' % (
                    uuid4().hex,
                    admittedImageMimeTypeToExtension[
                        coverImageFileObject['file'].mime_type],
                )),
        )
        texImagePaths = [
            duplicateImageForCalendar(
                fileIdToPath(
                    imageFile['file'].file_id,
                    fileStorageDirectory=fileStorageDirectory,
                ),
                os.path.join(
                    tempFileDirectory, '%s.%s' % (
                        uuid4().hex,
                        admittedImageMimeTypeToExtension[
                            imageFile['file'].mime_type],
                    )),
            ) for imageFile in calendarImages
        ]
        #
        fsDeletionQueue = [texImageCoverPath] + texImagePaths
        createdPdfTitle = uuid4().hex
        createdFile, creationToDelete = makeCalendarPdf(
            cProps,
            texImagePaths,
            texImageCoverPath,
            tempFileDirectory,
            createdPdfTitle,
        )
        #
        if createdFile is not None:
            # name and description
            calDescription = 'Calendar %i/%i - %i/%i' % (
                cProps['month0'],
                cProps['year0'],
                cProps['month1'],
                cProps['year1'],
            )
            calFileName = findFirstAvailableObjectNameInBox(
                db,
                destBox,
                'calendar_',
                '.pdf',
            )
            # place the pdf in the box
            placeFSFileInBox(
                db,
                user,
                fileStorageDirectory,
                destBox,
                createdFile,
                calFileName,
                calDescription,
            )
            # flushing the delete queue
            flushFsDeleteQueue(fsDeletionQueue + creationToDelete +
                               [createdFile])
            # messaging the user
            successMessage = ('Calendar generated. Please find the file '
                              '"%s" in the destination box.') % calFileName
            flashMessage('Success', 'Info', successMessage)
            # redirecting user to box
            return redirect(url_for('lsView', lsPathString=destBoxString))
        else:
            # flushing the delete queue
            flushFsDeleteQueue(
                fsDeletionQueue + creationToDelete + [createdFile], )
            # messaging the user
            flashMessage('Error', 'Error', 'Could not generate the calendar')
            return redirect(url_for('calendarMakerIndexView'))