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 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 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 fsView(fsPathString=''): """View file route. If not viewable, display an error message.""" user = g.user lsPath = splitPathString(fsPathString) boxPath, fileName = 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:]), ) file = getFileFromParent(db, parentBox, fileName, user) if file is not None: fileInfo = prepareFileInfo(db, file) fileActions = prepareFileActions( db, file, boxPath[1:] + [file.name], parentBox, user, discardedActions={'view'}, ) fileContents = produceFileViewContents( db, file, mode='fsview', viewParameters={ 'boxPath': boxPath, 'fileName': fileName, }, fileStorageDirectory=fileStorageDirectory, ) # pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[{ 'kind': 'file', 'target': file, }], ) # return render_template( 'fileview.html', fileActions=fileActions, fileInfo=fileInfo, filecontents=fileContents, breadCrumbs=pathBCrumbs, user=user, pageTitle='"%s" file view' % file.name, pageSubtitle='%s (%s; %s)' % ( file.description, file.type, formatBytesSize(file.size), ), downloadUrl=None, ) else: return abort(404)
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 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 editTextFileView(fsPathString=''): """Edit-text-file route.""" user = g.user db = dbGetDatabase() lsPath = splitPathString(fsPathString) boxPath, fileName = lsPath[:-1], lsPath[-1] request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] parentBox = getBoxFromPath(db, boxPath, user) file = getFileFromParent(db, parentBox, fileName, user) if file is None: raise OstracionError('File not found.') else: fileActions = prepareFileActions( db, file, boxPath[1:] + [file.name], parentBox, user, discardedActions={'text_edit'}, ) fileInfo = prepareFileInfo(db, file) form = EditTextFileForm() form.textformat.choices = [ (mId, mDesc['title']) for mId, mDesc in sorted( textFileViewingModes.items(), key=lambda kv: kv[1]['index'], ) ] ## if form.validate_on_submit(): newcontents = form.filecontents.data filePath = fileIdToPath( file.file_id, fileStorageDirectory=fileStorageDirectory, ) with open(filePath, 'w') as openFile: openFile.write('%s' % newcontents) # file properties fileProperties = determineFileProperties(filePath) newFile = File(**file.asDict()) newFile.mime_type = fileProperties['file_mime_type'] newFile.type = fileProperties['file_type'] newFile.size = fileProperties['file_size'] newFile.textual_mode = form.textformat.data newFile.editor_username = user.username updateFile(db, boxPath, file.name, newFile, user) # flashMessage('Info', 'Info', 'File "%s" saved.' % file.name) return redirect( url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) ) else: form.filecontents.data = applyDefault( form.filecontents.data, open( fileIdToPath( file.file_id, fileStorageDirectory=fileStorageDirectory, ) ).read(), ) form.textformat.data = applyDefault( form.textformat.data, file.textual_mode, additionalNulls=['None'], ) pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[ { 'kind': 'file', 'target': file, }, { 'kind': 'link', 'target': None, 'name': 'Edit text', } ], ) return render_template( 'edittextfile.html', user=user, form=form, fileActions=fileActions, fileInfo=fileInfo, pageTitle='"%s" file edit' % file.name, pageSubtitle='Click "Save" to commit the changes', breadCrumbs=pathBCrumbs, )
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 lsView(lsPathString=''): """LS-of-a-box route, additionally with 'tasks' if viewing root.""" user = g.user lsPath = splitPathString(lsPathString) db = dbGetDatabase() thisBox = getBoxFromPath(db, lsPath, user) boxPath = lsPath[1:] # showBoxPermissionToAll = g.settings['behaviour']['behaviour_permissions'][ 'show_permission']['value'] # if thisBox is not None: request._onErrorUrl = url_for('lsView') if thisBox.box_id == '': tasks = prepareRootTasks(db, g, user) else: tasks = [] boxes = [ { 'box': box, 'path': boxPath + [box.box_name], 'info': prepareBoxInfo(db, box), 'actions': prepareBoxActions( db, box, boxPath + [box.box_name], thisBox, user ), } for box in sorted( ( b for b in getBoxesFromParent(db, thisBox, user) if b is not None ), key=lambda b: (b.box_name.lower(), b.box_name), ) if box.box_id != '' ] files = [ { 'file': file, 'path': boxPath + [file.name], 'nice_size': formatBytesSize(file.size), 'info': prepareFileInfo(db, file), 'actions': prepareFileActions( db, file, boxPath + [file.name], thisBox, user ), } for file in sorted( getFilesFromBox(db, thisBox), key=lambda f: (f.name.lower(), f.name), ) ] links = [ { 'link': link, 'path': boxPath + [link.name], 'info': prepareLinkInfo(db, link), 'actions': prepareLinkActions( db, link, boxPath + [link.name], thisBox, user ), } for link in sorted( getLinksFromBox(db, thisBox), key=lambda l: (l.name.lower(), l.name), ) ] # pathBCrumbs = makeBreadCrumbs(lsPath, g) boxNiceName = transformIfNotEmpty(thisBox.box_name) if thisBox.box_id == '': boxTitle, boxDescription = describeRootBoxCaptions(g) else: boxTitle = describeBoxTitle(thisBox) boxDescription = thisBox.description # boxActions = prepareBoxHeaderActions( db, thisBox, boxPath, user, g.settings, discardedActions=( set() if len(files) > 0 else {'gallery_view', 'issue_gallery_ticket'} ), ) showAdminToolsLink = userIsAdmin(db, user) if showBoxPermissionToAll or userIsAdmin(db, user): thisBoxPermissionAlgebra = calculateBoxPermissionAlgebra( thisBox.permissionHistory, thisBox.permissions, ) # roleKeyToRoleMap = { r.roleKey(): r for r in dbGetAllRoles(db, user) if r.can_box != 0 } structuredPermissionInfo = reformatBoxPermissionAlgebraIntoLists( thisBoxPermissionAlgebra, roleKeyToRoleMap, ) # permissionInfo = { 'powers': structuredPermissionInfo, 'assignments': { 'edit_url': ( url_for( 'adminLsPermissionsView', lsPathString='/'.join(boxPath), ) if showAdminToolsLink else None ), 'native': [ { 'role_class': brp.role_class, 'role_id': brp.role_id, 'r': brp.r, 'w': brp.w, 'c': brp.c, 'role': roleKeyToRoleMap[( brp.role_class, brp.role_id, )], } for brp in sorted(thisBox.listPermissions('native')) ], 'inherited': [ { 'role_class': brp.role_class, 'role_id': brp.role_id, 'r': brp.r, 'w': brp.w, 'c': brp.c, 'role': roleKeyToRoleMap[( brp.role_class, brp.role_id, )], } for brp in sorted(thisBox.listPermissions('inherited')) ], }, } else: permissionInfo = None # if len(boxes) + len(files) + len(links) > 0: foundCounts = [ (len(boxes), 'box', 'boxes'), (len(files), 'file', 'files'), (len(links), 'link', 'links'), ] foundParts = pickSingularPluralSentences( foundCounts, keepZeroes=False, ) boxChildrenCounter = colloquialJoinClauses(foundParts) else: boxChildrenCounter = 'no contents' # return render_template( 'ls.html', user=user, thisBox=thisBox, boxTitle=boxTitle, boxNiceName=boxNiceName, boxDescription=boxDescription, pageTitle=boxNiceName, boxChildrenCounter=boxChildrenCounter, boxActions=boxActions, boxPath=boxPath, permissionInfo=permissionInfo, breadCrumbs=pathBCrumbs, tasks=tasks, boxes=boxes, files=files, links=links, ) else: request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(lsPath[1:-1]), ) raise OstracionWarning( 'Cannot access the specified box "%s"' % lsPath[-1] )
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, )
def makeTextFileView(fsPathString=''): """Generate-new-text-file route.""" user = g.user form = MakeTextFileForm() 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(): fileName = secure_filename(form.filename.data) savableFile = SavableTextFile('') filesToUpload = [ { 'box_id': parentBox.box_id, 'name': fileName, 'description': form.filedescription.data, 'date': datetime.datetime.now(), 'fileObject': savableFile, } ] 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, pastActionVerbForm='created', ) flashMessage('Success', 'Info', savingResult) return redirect(url_for( 'editTextFileView', fsPathString='/'.join(parentBoxPath[1:] + [fileName]), )) else: pathBCrumbs = makeBreadCrumbs( parentBoxPath, g, appendedItems=[{ 'kind': 'link', 'target': None, 'name': 'New text', }], ) return render_template( 'maketextfile.html', form=form, user=user, breadCrumbs=pathBCrumbs, iconUrl=pickFileThumbnail('text/plain'), pageTitle='New text', pageSubtitle='Create a new text file in "%s"' % ( describeBoxTitle(parentBox) ), )
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 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 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]), ))
def fsGalleryView(fsPathString=''): """ Gallery view route on a box. If just box, redirect to first file. If a file, use the ls of files to prepare prev/next links. That is to say, if user has read permission on box, gallery URLs are not index-based, rather filename-based and recalculated on actual 'ls'. """ isTopAccess = 1 if safeInt(request.args.get('top'), 0) != 0 else 0 user = g.user fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] db = dbGetDatabase() lsPath = splitPathString(fsPathString) # is it a box or a file? targetBox = getBoxFromPath(db, lsPath, user) if targetBox is not None: # if there are files, we redirect to the first one # otherwise, a message and falling back to ls view of the box files = sorted( getFilesFromBox(db, targetBox), key=lambda f: (f.name.lower(), f.name), ) if len(files) > 0: return redirect( url_for( 'fsGalleryView', fsPathString='/'.join(lsPath[1:] + [files[0].name]), top=str(isTopAccess), )) else: flashMessage( 'Info', 'Empty box', 'Cannot view as gallery a box without files', ) return redirect( url_for( 'lsView', lsPathString='/'.join(lsPath[1:]), )) else: # is it a file? boxPath, fileName = lsPath[:-1], lsPath[-1] parentBox = getBoxFromPath(db, boxPath, user) file = getFileFromParent(db, parentBox, fileName, user) if file is not None: if isTopAccess: # gallery navigation calculations files = sorted( getFilesFromBox(db, parentBox), key=lambda f: (f.name.lower(), f.name), ) thisFileIndex = [ idx for idx, fil in enumerate(files) if fil.name == fileName ][0] numGalleryFiles = len(files) nextFileIndex = (thisFileIndex + 1) % numGalleryFiles prevFileIndex = (thisFileIndex - 1 + numGalleryFiles) % numGalleryFiles # pathBCrumbs = makeBreadCrumbs( boxPath, g, appendedItems=[{ 'kind': 'link', 'name': 'Gallery view %i/%i' % ( thisFileIndex + 1, numGalleryFiles, ), 'target': None, }], ) fileContents = produceFileViewContents( db, file, mode='fsview', viewParameters={ 'boxPath': boxPath, 'fileName': fileName, }, fileStorageDirectory=fileStorageDirectory, ) fileActions = { 'gallery_prev': url_for( 'fsGalleryView', fsPathString='/'.join(boxPath[1:] + [files[prevFileIndex].name]), top=str(isTopAccess), ), 'gallery_next': url_for( 'fsGalleryView', fsPathString='/'.join(boxPath[1:] + [files[nextFileIndex].name]), top=str(isTopAccess), ), 'gallery_up': url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ), 'download': url_for( 'fsDownloadView', fsPathString=fsPathString, ), } return render_template( 'fileview.html', fileActions=fileActions, fileInfo=None, filecontents=fileContents, breadCrumbs=pathBCrumbs, user=user, pageTitle='"%s" gallery, file "%s" (%i/%i)' % ( parentBox.title, file.name, thisFileIndex + 1, numGalleryFiles, ), pageSubtitle=file.description, downloadUrl=None, hideBreadCrumbs=True, hideNavbar=True, ) else: return fsDownloadView(fsPathString=fsPathString) else: # extreme fallback to ls, which will hiearchically # deal with the retrieval return redirect(url_for('lsView', lsPathString=fsPathString))
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, )