def boxThumbnailView(dummyId, boxPathString=''): """Route for access to thumbnail image files based on box path.""" user = g.user db = dbGetDatabase() fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] if boxPathString == '': # root case return redirect(makeSettingImageUrl(g, 'app_images', 'root_box')) else: db = dbGetDatabase() boxPath = splitPathString(boxPathString) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) box = getBoxFromPath(db, boxPath, user) if (box is not None and box.icon_file_id is not None and box.icon_file_id != ''): filePhysicalPath, filePhysicalName = fileIdToSplitPath( box.icon_file_id, fileStorageDirectory=fileStorageDirectory, ) return send_from_directory( filePhysicalPath, filePhysicalName, mimetype=box.icon_mime_type, ) else: return redirect( makeSettingImageUrl( g, 'app_images', 'standard_box', ))
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'], })
def linkThumbnailView(dummyId, fsPathString=''): """Route for access to thumbnail image files based on link path.""" user = g.user lsPath = splitPathString(fsPathString) boxPath, linkName = lsPath[:-1], lsPath[-1] db = dbGetDatabase() fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] parentBox = getBoxFromPath(db, boxPath, user) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) link = getLinkFromParent(db, parentBox, linkName, user) if (link is not None and link.icon_file_id is not None and link.icon_file_id != ''): filePhysicalPath, filePhysicalName = fileIdToSplitPath( link.icon_file_id, fileStorageDirectory=fileStorageDirectory, ) return send_from_directory( filePhysicalPath, filePhysicalName, mimetype=link.icon_mime_type, ) else: return redirect(makeSettingImageUrl(g, 'app_images', 'external_link'))
def makeLinkView(fsPathString=''): """Generate-new-link route.""" user = g.user form = EditLinkForm() db = dbGetDatabase() boxPath = splitPathString(fsPathString) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) parentBoxPath = boxPath parentBox = getBoxFromPath(db, parentBoxPath, user) if form.validate_on_submit(): linkName = secure_filename(form.linkname.data) linkTitle = form.linktitle.data linkDescription = form.linkdescription.data linkTarget = form.linktarget.data openInNewWindow = form.openinnewwindow.data savingResult = makeLinkInParent( db=db, user=user, parentBox=parentBox, date=datetime.now(), linkName=linkName, linkTitle=linkTitle, linkDescription=linkDescription, linkTarget=linkTarget, linkOptions={ 'open_in_new_window': openInNewWindow, }, ) return redirect(url_for( 'lsView', lsPathString=fsPathString, )) else: pathBCrumbs = makeBreadCrumbs( parentBoxPath, g, appendedItems=[{ 'kind': 'link', 'target': None, 'name': 'New link', }], ) form.openinnewwindow.data = True return render_template( 'editlink.html', form=form, user=user, breadCrumbs=pathBCrumbs, iconUrl=makeSettingImageUrl(g, 'app_images', 'external_link'), pageTitle='New link', pageSubtitle='Create a new link in "%s"' % (describeBoxTitle(parentBox)), )
def preparePickBoxPageView(db, user, callbackUrl, startBox, message, predicate=lambda richFileOrBox: True): """ Prepare a full response for a "select box" view. Boxes are made selectable according to a 'predicate' and upon selection the callback URL is invokect, with the chosen box path passed as querystring parameter 'chosenBoxObjPath'. """ dstBoxTree = collectTreeFromBox( db, startBox, user, admitFiles=False, fileOrBoxEnricher=lambda richBox: { 'obj_path': urllib.parse.quote_plus('/'.join(richBox['path'])), }, predicate=predicate, ) # maxDepth = getMaxTreeDepth(dstBoxTree) colorShadeMap = prepareColorShadeMap( g.settings['color']['navigation_colors']['box']['value'], g.settings['color']['tree_shade_colors']['shade_treeview_pickbox'] ['value'], numShades=1 + maxDepth, ) # return render_template( 'dirtreeview.html', tree=dstBoxTree, mode='pick_box', object_quoted_path=callbackUrl, colorShadeMap=colorShadeMap, user=user, iconUrl=makeSettingImageUrl(g, 'app_images', 'move'), pageTitle='Choose a box', pageSubtitle=message, actions=None, backToUrl=None, breadCrumbs=[ { 'kind': 'link', 'target': None, 'name': 'Move box', }, ], )
def userThumbnailView(dummyId, username): """Route for access to thumbnail image files based on user name.""" user = g.user db = dbGetDatabase() fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] if user.username == username or userIsAdmin(db, user): targetUser = (user if user.username == username else dbGetUser( db, username)) if targetUser.icon_file_id != '': filePhysicalPath, filePhysicalName = fileIdToSplitPath( targetUser.icon_file_id, fileStorageDirectory=fileStorageDirectory, ) return send_from_directory( filePhysicalPath, filePhysicalName, mimetype=targetUser.icon_mime_type, ) else: return redirect(makeSettingImageUrl(g, 'user_images', 'user_icon')) else: return abort(400, 'User has no permission to access this resource.')
def changePasswordUponTicket(db, user, issuer, richTicket, urlRoot): """Change-password-ticket route.""" ticketsByformerAdminsAreProtected = g.settings['behaviour'][ 'behaviour_tickets']['protect_nonadmin_user_password_tickets']['value'] applicationLongName = g.settings['behaviour']['behaviour_appearance'][ 'application_long_name']['value'] if not ticketsByformerAdminsAreProtected or userIsAdmin(db, issuer): form = generateTicketChangePasswordForm(g.settings) if form.validate_on_submit(): changeeUser = dbGetUser(db, richTicket['metadata']['username']) if form.username.data == changeeUser.username: # newPassword = form.newpassword.data minPasswordLength = g.settings['behaviour'][ 'behaviour_security']['password_min_length']['value'] if len(form.newpassword.data) < minPasswordLength: print('richTicket ', richTicket) flashMessage( 'Info', 'Please retry', 'New password too short (min. %i characters)' % (minPasswordLength, ), ) return redirect( url_for( 'redeemTicketView', mode='p', ticketId=richTicket['ticket'].ticket_id, securityCode=richTicket['ticket'].security_code, )) else: newUser = User( **({(k if k != 'passwordhash' else 'password'): ( v if k != 'passwordhash' else form.newpassword.data ) for k, v in changeeUser.asDict().items()})) try: dbPunchRichTicket(db, richTicket, skipCommit=True) dbUpdateUser(db, newUser, user, skipCommit=True) db.commit() # flash a message flashMessage( 'Success', 'Success', 'Password changed. You can now log in to %s' % (applicationLongName, ), ) # go to login return redirect(url_for('loginView')) except Exception as e: db.rollback() raise e else: raise OstracionError('Wrong username provided') else: pageSubtitle = ('Complete the process by entering your ' 'new password twice%s') % ( '' if richTicket['metadata'].get('message') is None else '. Message on ticket: "%s"' % (richTicket['metadata'].get('message'), )) return render_template( 'userchangepassword.html', user=user, form=form, showOldPasswordField=False, mode='ticket', breadCrumbs=None, pageTitle='Change password', pageSubtitle=pageSubtitle, iconUrl=makeSettingImageUrl(g, 'admin_images', 'change_password_ticket'), backToUrl=url_for('lsView'), ) else: raise OstracionError('Ticket not acessible or expired')
def uploadFilesUponTicket(db, user, issuer, richTicket, urlRoot): """ Upload-file(s)-upon-ticket route. Upload fails if 1. user banned; 2. issuer has no upload permission (incl. access) on the target box. """ noBandUsrTickets = g.settings['behaviour']['behaviour_tickets'][ 'protect_banned_user_tickets']['value'] if not noBandUsrTickets or issuer.banned == 0: boxPath = richTicket['metadata']['box_path'] request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) box = getBoxFromPath(db, boxPath[1:], issuer) fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] if userHasPermission(db, issuer, box.permissions, 'w'): # ticket is completely valid: here the form # handling (get/post) occurs uploadsLeft = (None if richTicket['ticket'].multiplicity is None else (richTicket['ticket'].multiplicity - richTicket['ticket'].times_redeemed)) form = UploadMultipleFilesForm() if form.validate_on_submit(): uploadedFiles = [ uf for uf in request.files.getlist('files') if uf.filename != '' ] filesdescription = form.filesdescription.data # are there too many files? if uploadsLeft is None or len(uploadedFiles) <= uploadsLeft: filesToUpload = [{ 'box_id': box.box_id, 'name': secure_filename(uploadedFile.filename), 'description': form.filesdescription.data, 'date': datetime.datetime.now(), 'fileObject': uploadedFile, } for uploadedFile in uploadedFiles] # we punch the ticket as many times as # there were files provided dbPunchRichTicket( db, richTicket, numPunches=len(filesToUpload), ) makeThumbnails = g.settings['behaviour'][ 'behaviour_appearance']['extract_thumbnails']['value'] savingResult = saveAndAnalyseFilesInBox( db=db, files=filesToUpload, parentBox=box, user=issuer, fileStorageDirectory=fileStorageDirectory, thumbnailFormat=('thumbnail' if makeThumbnails else None), ) flashMessage('Success', 'Info', savingResult) return redirect(url_for( 'lsView', lsPathString='', )) else: request._onErrorUrl = url_for( 'redeemTicketView', mode='c', ticketId=richTicket['ticket'].ticket_id, securityCode=richTicket['ticket'].security_code, ) raise OstracionError( ('Cannot upload this many files ' '(maximum %i allowed)') % uploadsLeft) else: return render_template( 'uploadmultiplefiles.html', form=form, user=user, breadCrumbs=[], pageTitle='Upload file(s)', pageSubtitle='Upload%s files%s' % ( ('' if uploadsLeft is None else ' up to %i' % uploadsLeft), ('' if richTicket['metadata'].get('message') is None else ('. Message on ticket: "%s"' % (richTicket['metadata']['message']))), ), iconUrl=makeSettingImageUrl( g, 'app_images', ('single_upload' if optionNumberLeq(1, uploadsLeft) else 'multiple_upload'), ), ) else: # issuer has no write permission in box raise OstracionError('Ticket not acessible or expired') else: raise OstracionError('Ticket not acessible or expired')
def fsMoveBoxView(quotedSrcBox): """ Move-box-phase-1 route: where the source box is selected (and then in offering the choose-dest-box it is put in the URL for calling phase two). """ user = g.user db = dbGetDatabase() # first we find the box bxPathString = urllib.parse.unquote_plus(quotedSrcBox) boxPath = splitPathString(bxPathString) parentBox = getBoxFromPath(db, boxPath[:-1], user) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:-1]), ) box = getBoxFromPath(db, boxPath, user) if not canDeleteBox(db, box, parentBox, user): raise OstracionWarning('Cannot act on this object') # next we prepare the selectable destinations rootBox = getRootBox(db) def rbPredicate(richBox, _box=box, _srcBox=parentBox): _dstBox = richBox['box'] if _box.parent_id != _dstBox.box_id: if all(userHasPermission(db, user, _dstBox.permissions, prm) for prm in {'w', 'c'}): if not isNameUnderParentBox(db, _dstBox, _box.box_name): if not isAncestorBoxOf(db, _box, _dstBox): return True return False dstBoxTree = collectTreeFromBox( db, rootBox, user, admitFiles=False, fileOrBoxEnricher=lambda richBox: { 'obj_path': urllib.parse.quote_plus('/'.join(richBox['path'])), }, predicate=rbPredicate, ) # maxDepth = getMaxTreeDepth(dstBoxTree) colorShadeMap = prepareColorShadeMap( g.settings['color']['navigation_colors']['box']['value'], g.settings['color']['tree_shade_colors'][ 'shade_treeview_pickbox']['value'], numShades=1 + maxDepth, ) destinationsExist = treeAny( dstBoxTree, property=lambda node: node['predicate'], ) # return render_template( 'dirtreeview.html', tree=dstBoxTree if destinationsExist else None, mode='box_move', object_quoted_path=quotedSrcBox, colorShadeMap=colorShadeMap, user=user, iconUrl=makeSettingImageUrl(g, 'app_images', 'move'), pageTitle='Select box destination', pageSubtitle=('Choose the box to which box "%s" ' 'shall be moved from "%s"') % ( describeBoxTitle(box), describeBoxTitle(parentBox), ), actions=None, backToUrl=(None if destinationsExist else url_for( 'lsView', lsPathString='/'.join(boxPath[1:]))), breadCrumbs=makeBreadCrumbs( boxPath, g, appendedItems=[ { 'kind': 'link', 'target': None, 'name': 'Move box', } ], ), )
def makeTicketBoxUploadView(boxPathString=''): """Make-upload-ticket (to a box) route.""" user = g.user db = dbGetDatabase() boxPath = splitPathString(boxPathString) box = getBoxFromPath(db, boxPath, user) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) # if userHasPermission(db, user, box.permissions, 'w'): # pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[ { 'name': '(create upload ticket)', 'kind': 'link', 'target': url_for( 'makeTicketBoxUploadView', boxPathString=boxPathString, ), 'link': False, }, ], ) form = generateFsTicketForm( fileModePresent=False, settings=g.settings, ) if form.validate_on_submit(): magicLink = dbMakeUploadTicket( db=db, ticketName=form.name.data, validityHours=transformIfNotEmpty( form.validityhours.data, int, ), multiplicity=transformIfNotEmpty( form.multiplicity.data, int, ), ticketMessage=transformIfNotEmpty( form.ticketmessage.data, ), box=box, boxPath=boxPath, user=user, urlRoot=request.url_root, settings=g.settings, ) flashMessage( 'Success', 'Done', ('Upload ticket generated. Give the recipient ' 'the following magic link:'), pillText=magicLink, ) return redirect(url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), )) else: defaultName = 'Upload-To-%s' % ( describeBoxName(box) ) form.name.data = applyDefault(form.name.data, defaultName) form.ticketmessage.data = applyDefault( form.ticketmessage.data, 'Please, upload files to this box', ) maxValidityHours = g.settings['behaviour']['behaviour_tickets'][ 'max_ticket_validityhours']['value'] form.validityhours.data = applyDefault( form.validityhours.data, str(maxValidityHours) if maxValidityHours is not None else '', ) maxMultiplicity = g.settings['behaviour']['behaviour_tickets'][ 'max_ticket_multiplicity']['value'] form.multiplicity.data = applyDefault( form.multiplicity.data, str(maxMultiplicity) if maxMultiplicity is not None else '', ) return render_template( 'fsticket.html', pageTitle='Create public upload ticket', pageSubtitle=('Recipient(s) of the ticket will be able to ' 'upload to "%s", without an account, on ' 'your behalf.') % ( describeBoxTitle(box) ), baseMultiplicityCaption='Number of granted file uploads', user=user, form=form, iconUrl=makeSettingImageUrl(g, 'app_images', 'upload_ticket'), showFileMode=False, breadCrumbs=pathBCrumbs, ) # else: raise OstracionError('Insufficient permissions')
def loginView(): """Login view.""" user = g.user db = dbGetDatabase() g._onErrorUrl = url_for('loginView') if user is not None and user.is_authenticated: return redirect(url_for('indexView')) form = LoginForm() loginProtectionSeconds = int(g.settings['behaviour']['behaviour_security'] ['login_protection_seconds']['value']) if form.validate_on_submit(): # loginWaitSeconds = secondsToWaitBeforeLogin( db, request.remote_addr, doWrite=True, loginProtectionSeconds=loginProtectionSeconds, hashSalt=g.settings['behaviour']['behaviour_security'] ['ip_addr_hashing_salt']['value'], ) if loginWaitSeconds <= 0: # qUser = dbGetUser(db, form.username.data) if qUser and qUser.checkPassword(form.password.data): # newUser = User(**qUser.asDict()) newUser.last_login = datetime.datetime.now() dbUpdateUser(db, newUser, qUser) # login_user(qUser) # flashMessage( 'Success', 'Login successful', 'welcome, %s!' % (qUser.fullname, ), ) # return redirect(url_for('indexView')) else: g._onErrorUrl = url_for( 'loginView', username=form.username.data, ) raise OstracionError('invalid username or password') else: raise OstracionWarning( ('Automated repeated login protection. ' 'Please wait %i seconds ...') % int(loginWaitSeconds)) else: requestParams = request.args form.username.data = applyDefault( form.username.data, requestParams.get('username', ''), ) appShortName = g.settings['behaviour']['behaviour_appearance'][ 'application_short_name']['value'] iconUrl = makeSettingImageUrl(g, 'user_images', 'login') return render_template( 'login.html', form=form, user=user, pageTitle=loginTitle(g), pageSubtitle=loginSubtitle(g), iconUrl=iconUrl, )
def fsMoveFileView(quotedFilePath): """Move-file, view 1/2: select destination box.""" user = g.user db = dbGetDatabase() # first we find the file fsPathString = urllib.parse.unquote_plus(quotedFilePath) lsPath = splitPathString(fsPathString) boxPath, fileName = lsPath[:-1], lsPath[-1] parentBox = getBoxFromPath(db, boxPath, user) file = getFileFromParent(db, parentBox, fileName, user) # next we prepare the selectable destinations rootBox = getRootBox(db) def rbPredicate(richBox, idToAvoid=parentBox.box_id): return all((richBox['box'].box_id != idToAvoid, userHasPermission(db, user, richBox['box'].permissions, 'w'))) dstBoxTree = collectTreeFromBox( db, rootBox, user, admitFiles=False, fileOrBoxEnricher=lambda richBox: { 'obj_path': urllib.parse.quote_plus('/'.join(richBox['path'])), }, predicate=rbPredicate, ) # maxDepth = getMaxTreeDepth(dstBoxTree) colorShadeMap = prepareColorShadeMap( g.settings['color']['navigation_colors']['file']['value'], g.settings['color']['tree_shade_colors']['shade_treeview_pickbox'] ['value'], numShades=1 + maxDepth, ) destinationsExist = treeAny( dstBoxTree, property=lambda node: node['predicate'], ) # return render_template( 'dirtreeview.html', tree=dstBoxTree if destinationsExist else None, mode='file_move', object_quoted_path=quotedFilePath, colorShadeMap=colorShadeMap, user=user, iconUrl=makeSettingImageUrl(g, 'app_images', 'move'), pageTitle='Select file destination', pageSubtitle=(('Choose the box to which file "%s" shall ' 'be moved from "%s"') % ( file.name, describeBoxTitle(parentBox), )), actions=None, backToUrl=None if destinationsExist else url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ), breadCrumbs=makeBreadCrumbs( boxPath, g, appendedItems=[{ 'kind': 'file', 'target': file, }, { 'kind': 'link', 'target': None, 'name': 'Move file', }], ), )
def quickFindView(): """Quick (i.e. in-navbar) box- and file-find route.""" user = g.user db = dbGetDatabase() form = QuickFindForm() # if not g.canPerformSearch: raise OstracionError('Insufficient permissions') # search parameter collection searchMode = 'sim_ci' searchBoxes = True searchFiles = True searchLinks = True searchInDescription = False searchTerm = form.quicktext.data if form.quicktext.data is not None else '' options = { 'mode': searchMode, 'searchBoxes': searchBoxes, 'searchFiles': searchFiles, 'searchLinks': searchLinks, 'useDescription': searchInDescription, } # recasting of the above default for the displayed form findForm = FindForm() findForm.searchMode.data = searchMode findForm.searchTypeBoxes.data = searchBoxes findForm.searchTypeFiles.data = searchFiles findForm.searchTypeLinks.data = searchLinks findForm.searchFieldDescription.data = searchInDescription findForm.text.data = searchTerm # initTime = time.time() findResults = fsFind( db, searchTerm, user, options=options, ) resultsDescription = describeFindResults(findResults) elapsed = time.time() - initTime # return render_template( 'findform.html', user=user, form=findForm, pageTitle='Search Results', pageSubtitle='Search term: "%s"' % searchTerm, iconUrl=makeSettingImageUrl(g, 'app_images', 'search'), breadCrumbs=[ { 'name': 'Tools', 'type': 'link', 'target': None, 'link': False, }, { 'name': 'Search', 'type': 'link', 'target': None, 'link': False, }, ], findResults=findResults, resultsDescription=resultsDescription, elapsed=elapsed, searchTerm=searchTerm, )
def uploadMultipleFilesView(fsPathString=''): """Upload-several-files (to a box) route.""" user = g.user form = UploadMultipleFilesForm() db = dbGetDatabase() boxPath = splitPathString(fsPathString) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] parentBoxPath = boxPath parentBox = getBoxFromPath(db, parentBoxPath, user) # if form.validate_on_submit(): uploadedFiles = [ uf for uf in request.files.getlist('files') if uf.filename != '' ] # filesToUpload = [ { 'box_id': parentBox.box_id, 'name': secure_filename(uploadedFile.filename), 'description': form.filesdescription.data, 'date': datetime.datetime.now(), 'fileObject': uploadedFile, } for uploadedFile in uploadedFiles ] makeThumbnails = g.settings['behaviour']['behaviour_appearance'][ 'extract_thumbnails']['value'] savingResult = saveAndAnalyseFilesInBox( db=db, files=filesToUpload, parentBox=parentBox, user=user, fileStorageDirectory=fileStorageDirectory, thumbnailFormat='thumbnail' if makeThumbnails else None, ) flashMessage('Success', 'Info', savingResult) return redirect(url_for( 'lsView', lsPathString='/'.join(parentBoxPath[1:]), )) else: pathBCrumbs = makeBreadCrumbs( parentBoxPath, g, appendedItems=[{ 'kind': 'link', 'target': None, 'name': 'Multiple upload', }], ) return render_template( 'uploadmultiplefiles.html', form=form, user=user, breadCrumbs=pathBCrumbs, pageTitle='Upload new files', pageSubtitle='Upload new files to box "%s"' % ( describeBoxTitle(parentBox) ), iconUrl=makeSettingImageUrl(g, 'app_images', 'multiple_upload') )
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, )
def createUserUponTicket(db, user, issuer, richTicket, urlRoot): """User-creation-ticket route.""" ticketsByformerAdminsAreProtected = g.settings['behaviour'][ 'behaviour_tickets']['protect_nonadmin_user_password_tickets']['value'] appLongName = g.settings['behaviour']['behaviour_appearance'][ 'application_long_name']['value'] if not ticketsByformerAdminsAreProtected or userIsAdmin(db, issuer): form = generateNewUserForm(g.settings) if form.validate_on_submit(): userDict = { 'username': form.username.data, 'fullname': form.fullname.data, 'email': form.email.data, 'password': form.password.data, } if ('username' in richTicket['metadata'] and richTicket['metadata']['username'] != userDict['username']): raise RuntimeError( 'Detected attempt to escape username set by ticket issuer') else: # the usename must not exist (relevant if left free in ticket) if isUsername(db, userDict['username'], user): if 'username' in richTicket['metadata']: request._onErrorUrl = url_for('lsView') else: request._onErrorUrl = url_for( 'redeemTicketView', mode='u', ticketId=ticketId, securityCode=securityCode, ) raise OstracionError('Username "%s" exists already' % userDict['username']) else: # we proceed with the user creation proper newUser = User( icon_file_id='', icon_file_id_username=userDict['username'], banned=0, terms_accepted='0', terms_accepted_version='', **userDict, ) try: dbPunchRichTicket(db, richTicket, skipCommit=True) dbCreateUser(db, newUser, user) # flashMessage( 'Info', 'Success', 'User created. You can now log in to %s' % (appLongName), ) return redirect(url_for('loginView')) except Exception as e: db.rollback() raise e else: form.username.data = applyDefault( form.username.data, richTicket['metadata'].get('username', ''), ) form.fullname.data = applyDefault( form.fullname.data, richTicket['metadata'].get('fullname', ''), ) form.email.data = applyDefault( form.email.data, richTicket['metadata'].get('email', ''), ) return render_template( 'newuser.html', form=form, user=user, pageTitle='Create user', pageSubtitle='Create your user account on %s%s' % ( appLongName, ('' if richTicket['metadata'].get('message') is None else '. Message on ticket: "%s"' % (richTicket['metadata']['message'])), ), iconUrl=makeSettingImageUrl(g, 'user_images', 'user_icon'), lockUsernameField='username' in richTicket['metadata'], ) else: raise OstracionError('Ticket not acessible or expired') return redirect(url_for('lsView'))
def fsMakeTicketView(fsPathString=''): """Create-file-ticket (file-read) view.""" user = g.user lsPath = splitPathString(fsPathString) boxPath, fileName = lsPath[:-1], lsPath[-1] db = dbGetDatabase() parentBox = getBoxFromPath(db, boxPath, user) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) if parentBox is not None: file = getFileFromParent(db, parentBox, fileName, user) if file is not None: pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[ { 'kind': 'file', 'target': file, }, { 'name': '(create ticket)', 'kind': 'link', 'target': url_for( 'fsMakeTicketView', fsPathString=fsPathString, ), 'link': False, }, ], ) # if this succeeded, user has read permission on 'file' form = generateFsTicketForm( fileModePresent=True, settings=g.settings, ) if form.validate_on_submit(): magicLink = dbMakeFileTicket( db=db, ticketName=form.name.data, validityHours=transformIfNotEmpty( form.validityhours.data, int, ), multiplicity=transformIfNotEmpty( form.multiplicity.data, int, ), ticketMessage=transformIfNotEmpty( form.ticketmessage.data, ), file=file, fileMode=form.filemode.data, lsPath=lsPath, user=user, urlRoot=request.url_root, settings=g.settings, ) flashMessage( 'Success', 'Done', ('File ticket generated. Give the recipient ' 'the following magic link:'), pillText=magicLink, ) return redirect( url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), )) else: form.name.data = applyDefault(form.name.data, file.name) form.ticketmessage.data = applyDefault( form.ticketmessage.data, 'Please access this file', ) form.filemode.data = applyDefault( form.filemode.data, 'direct', additionalNulls=['None'], ) maxValidityHours = g.settings['behaviour'][ 'behaviour_tickets']['max_ticket_validityhours']['value'] form.validityhours.data = applyDefault( form.validityhours.data, (str(maxValidityHours) if maxValidityHours is not None else ''), ) maxMultiplicity = g.settings['behaviour']['behaviour_tickets'][ 'max_ticket_multiplicity']['value'] form.multiplicity.data = applyDefault( form.multiplicity.data, (str(maxMultiplicity) if maxMultiplicity is not None else ''), ) return render_template( 'fsticket.html', pageTitle='Create public file ticket', pageSubtitle=('Recipient(s) of the ticket will be able ' 'to access "%s" without an account.') % (fsPathString, ), baseMultiplicityCaption=('Number of granted accesses (bo' 'th views and downloads count)'), user=user, form=form, iconUrl=makeSettingImageUrl( g, 'app_images', 'file_ticket', ), showFileMode=True, breadCrumbs=pathBCrumbs, ) else: return abort(404) else: return abort(404)
def makeBoxView(parentBoxPathString=''): """MKBOX-in-a-box- route.""" user = g.user form = makeMakeBoxForm('Create')() db = dbGetDatabase() parentBoxPath = splitPathString(parentBoxPathString) parentBox = getBoxFromPath(db, parentBoxPath, user) boxNiceName = describeBoxTitle(parentBox) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(parentBoxPath), ) if form.validate_on_submit(): # boxName = form.boxname.data boxDescription = form.boxdescription.data boxTitle = form.boxtitle.data # newBox = Box( box_name=boxName, title=boxTitle, description=boxDescription, icon_file_id='', nature='box', parent_id=parentBox.box_id, date=datetime.now(), creator_username=user.username, icon_file_id_username=user.username, metadata_username=user.username, ) makeBoxInParent(db, parentBox, newBox, user, skipCommit=True) if parentBox.box_id == '': # the new box is a direct child of root: # act according to the localhost-mode policy setting rootChildAnonPerms = g.settings['behaviour'][ 'behaviour_permissions'][ 'rootchild_box_anonymous_permissions']['value'] rcPermSet = { k: 1 if rootChildAnonPerms[i] != '_' else 0 for i, k in enumerate('rwc') } # the above is a bit of a hack which parses the char # of the setting 'r__', 'rwc', ... rootChildBRP = BoxRolePermission( box_id=newBox.box_id, role_class='system', role_id='anonymous', **rcPermSet, ) dbInsertBoxRolePermission( db, rootChildBRP, user, skipCommit=True, ) # db.commit() additionalLsItems = [boxName] # return redirect(url_for( 'lsView', lsPathString='/'.join(parentBoxPath[1:] + additionalLsItems), )) else: pathBCrumbs = makeBreadCrumbs( parentBoxPath, g, appendedItems=[{ 'kind': 'link', 'target': None, 'name': 'Make box', }], ) return render_template( 'makebox.html', form=form, user=user, breadCrumbs=pathBCrumbs, iconUrl=makeSettingImageUrl(g, 'app_images', 'standard_box'), pageTitle='Create box in "%s"' % boxNiceName, pageSubtitle='Name and title are mandatory', )
def makeTicketBoxGalleryView(boxPathString=''): """Make-gallery-ticket-of-box route.""" user = g.user db = dbGetDatabase() boxPath = splitPathString(boxPathString) box = getBoxFromPath(db, boxPath, user) request._onErrorUrl = url_for('lsView', lsPathString='/'.join(boxPath[1:])) # pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[ { 'name': '(create gallery ticket)', 'kind': 'link', 'target': url_for( 'makeTicketBoxGalleryView', boxPathString=boxPathString, ), 'link': False, }, ], ) form = generateFsTicketForm( fileModePresent=False, settings=g.settings, ) if form.validate_on_submit(): magicLink = dbMakeGalleryTicket( db=db, ticketName=form.name.data, validityHours=transformIfNotEmpty( form.validityhours.data, int ), multiplicity=transformIfNotEmpty( form.multiplicity.data, int ), ticketMessage=transformIfNotEmpty( form.ticketmessage.data ), box=box, boxPath=boxPath, user=user, urlRoot=request.url_root, settings=g.settings, ) flashMessage( 'Success', 'Done', ('Gallery ticket generated. Give the recipient ' 'the following magic link:'), pillText=magicLink, ) return redirect(url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), )) else: defaultName = 'Gallery-View-%s' % describeBoxName(box) form.name.data = applyDefault(form.name.data, defaultName) form.ticketmessage.data = applyDefault( form.ticketmessage.data, 'Please, look at this gallery', ) maxValidityHours = g.settings['behaviour']['behaviour_tickets'][ 'max_ticket_validityhours']['value'] form.validityhours.data = applyDefault( form.validityhours.data, str(maxValidityHours) if maxValidityHours is not None else '', ) maxMultiplicity = g.settings['behaviour']['behaviour_tickets'][ 'max_ticket_multiplicity']['value'] form.multiplicity.data = applyDefault( form.multiplicity.data, str(maxMultiplicity) if maxMultiplicity is not None else '', ) return render_template( 'fsticket.html', pageTitle='Create public gallery-view ticket', pageSubtitle=('Recipient(s) of the ticket will be able to view ' 'files (and not contained boxes) in "%s", without ' 'an account, as a gallery. If setting a number of ' 'accesses, keep in mind that every single-file view' ' counts toward the total accesses.') % ( describeBoxTitle(box) ), baseMultiplicityCaption='Number of granted accesses', user=user, form=form, iconUrl=makeSettingImageUrl(g, 'app_images', 'gallery_ticket'), showFileMode=False, breadCrumbs=pathBCrumbs, )
def before_request(): """ Preparation of globally-accessible info for all views, handling of special post-install situations and of banned users and logged-in-only setups. """ db = dbGetDatabase() g.user = current_user g.settings = dbLoadAllSettings(db, g.user) g.applicationLogoUrl = makeSettingImageUrl( g, 'ostracion_images', 'navbar_logo', ) # g.canPerformSearch = isUserWithinPermissionCircle( db, g.user, g.settings['behaviour']['search']['search_access']['value'], ) g.quickFindForm = QuickFindForm() g.canShowTreeView = isUserWithinPermissionCircle( db, g.user, g.settings['behaviour']['search']['tree_view_access']['value'], ) # task lists - must happen after the above (which set access flags) g.availableApps = selectAvailableApps(db, g.user, g) g.availableInfoItems = selectAvailableInfoItems(db, g.user, g) g.availableTools = selectAvailableTools(db, g.user, g) # if g.user.is_authenticated: g.user.setRoles(list(dbGetUserRoles(db, g.user))) if g.user.banned: flashMessage( 'Warning', 'Warning', ('Your user is momentarily banned. ' 'Please continue as anonymous'), ) logout_user() # handling of first-time post-install forced steps dirsSetUp = g.settings['managed']['post_install_finalisations'][ 'directories_set_up']['value'] if (not dirsSetUp and request.endpoint not in endpointsWithoutAppInitRerouting): if g.user.is_authenticated and userIsAdmin(db, g.user): flashMessage( 'Warning', 'Action required', ('Please review carefully the following directory settings ' 'to make the application function. Changing them later, ' 'when material is uploaded, is a disruptive operation.'), ) return redirect( url_for('adminHomeSettingsGenericView', settingType='system_settings')) else: if g.user.is_authenticated: logout_user() flashMessage( 'Warning', 'Action required', ('To finalise installation/make the application function ' 'properly, an administrator should log in and ' 'complete the setup'), ) return redirect(url_for('loginView')) else: # we care about reviewing the settings only if the dirs are OK if g.user.is_authenticated and userIsAdmin(db, g.user): if request.endpoint not in endpointsWithoutAppInitRerouting: settingsReviewed = g.settings['managed'][ 'post_install_finalisations']['settings_reviewed']['value'] if not settingsReviewed: flashMessage( 'Warning', 'Action required', ('Please carefully review the following application ' 'behaviour settings before opening the service ' 'to users (anyway, these settings can be ' 'changed at any time).'), ) return redirect( url_for('adminHomeSettingsGenericView', settingType='behaviour')) # we take care of terms-and-conditions acceptance here if request.endpoint not in endpointsWithoutTermAcceptanceBlocking: usersMustAbideByTOS = g.settings['terms']['terms']['terms_must_agree'][ 'value'] anonymousMustAbideByTOS = g.settings['terms']['terms'][ 'terms_must_agree_anonymous']['value'] currentTermVersion = g.settings['terms']['terms']['terms_version'][ 'value'] # if g.user.is_authenticated: mustAbideByTOS = usersMustAbideByTOS typeOfUsers = 'Users' storedTermsVersion = g.user.terms_accepted_version storedTermsAcceptance = safeInt( g.user.terms_accepted, default=None, ) else: mustAbideByTOS = anonymousMustAbideByTOS typeOfUsers = 'Visitors' storedTermsVersion = request.cookies.get('termsAcceptedVersion') storedTermsAcceptance = safeInt( request.cookies.get('termsAccepted'), default=None, ) # if storedTermsVersion == currentTermVersion: thisVersionAcceptance = storedTermsAcceptance else: thisVersionAcceptance = None # if thisVersionAcceptance is None: canContinueTermwise = not mustAbideByTOS elif thisVersionAcceptance == 0: # explicit not-acceptance canContinueTermwise = False else: # positive updated acceptance canContinueTermwise = True # if not canContinueTermwise: quotedTravelToPath = urllib.parse.quote_plus(request.full_path) flashMessage( 'Info', 'Action required', ('%s must review the Terms and Conditions' ' before accessing the site.') % typeOfUsers, ) return redirect( url_for( 'termsView', showAgreementButtons='y', travelTo=quotedTravelToPath, )) # here the ordinary flow is resumed if g.settings['behaviour']['behaviour_permissions'][ 'logged_in_users_only']['value']: if (not g.user.is_authenticated and request.endpoint not in endpointsWithoutInviteOnlyBlocking): return redirect(url_for('loginView'))