def fsDoMoveLinkView(quotedLinkPath, quotedDestBox=''): """Move-link, view 2/2: dest box is selected, actually move.""" user = g.user db = dbGetDatabase() # we retrieve the source file and the destination box srcFsPathString = urllib.parse.unquote_plus(quotedLinkPath) srcLsPath = splitPathString(srcFsPathString) srcBoxPath, linkName = srcLsPath[:-1], srcLsPath[-1] srcBox = getBoxFromPath(db, srcBoxPath, user) link = getLinkFromParent(db, srcBox, linkName, user) dstBoxPathString = urllib.parse.unquote_plus(quotedDestBox) dstBoxPath = splitPathString(dstBoxPathString) dstBox = getBoxFromPath(db, dstBoxPath, user) fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] # request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(srcBoxPath[1:]), ) messages = moveLink( db, link, srcBox, dstBox, user, fileStorageDirectory=fileStorageDirectory, ) for msg in messages: flashMessage('Info', 'Info', msg) return redirect(url_for( 'lsView', lsPathString='/'.join(dstBoxPath[1:]), ))
def fsDeleteLinkView(fsPathString=''): """ Delete-link view. Permission checks are performed by the deleteLink filesystem call. """ user = g.user db = dbGetDatabase() fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] lsPath = splitPathString(fsPathString) boxPath, linkName = lsPath[:-1], lsPath[-1] parentBox = getBoxFromPath(db, boxPath, user) request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ) link = getLinkFromParent(db, parentBox, linkName, user) fsDeleteQueue = deleteLink( db, parentBox, link, user, fileStorageDirectory=fileStorageDirectory, ) flushFsDeleteQueue(fsDeleteQueue) return redirect(url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ))
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 _resolveUponPermissions(db, richObject, user, mode, score): """ Verify and validate the input (rich-)box/file against permissions, and return either a similar structure or a None if permissions turn out to be blocking. ( richObject has keys "path" and "box/file", mode = 'file' / 'box' ) """ pBox = getBoxFromPath(db, richObject['path'][:-1], user) if mode == 'box': nBox = getBoxFromPath(db, richObject['path'], user) if nBox is not None and pBox is not None: return { 'path': richObject['path'][1:], 'box': nBox, 'actions': prepareBoxActions(db, nBox, richObject['path'][1:], pBox, user, prepareParentButton=True), 'info': prepareBoxInfo(db, nBox), 'parentInfo': 'Parent box: "%s"' % (describeBoxTitle(pBox), ), 'object_type': mode, 'score': score, } else: return None elif mode == 'file': if pBox is not None: nFile = getFileFromParent(db, pBox, richObject['path'][-1], user) if nFile is not None: return { 'path': richObject['path'][1:], 'file': nFile, 'actions': prepareFileActions(db, nFile, richObject['path'][1:], pBox, user, prepareParentButton=True), 'info': prepareFileInfo(db, nFile), 'nice_size': formatBytesSize(nFile.size), 'parentInfo': 'Container box: "%s"' % (describeBoxTitle(pBox), ), 'object_type': mode, 'score': score, } else: return None else: return None elif mode == 'link': if pBox is not None: nLink = getLinkFromParent(db, pBox, richObject['path'][-1], user) if nLink is not None: return { 'path': richObject['path'][1:], 'link': nLink, 'actions': prepareLinkActions(db, nLink, richObject['path'][1:], pBox, user, prepareParentButton=True), 'info': prepareLinkInfo(db, nLink), 'parentInfo': 'Container box: "%s"' % (describeBoxTitle(pBox), ), 'object_type': mode, 'score': score, } else: return None else: return None else: raise NotImplementedError('Unknown _resolveUponPermissions mode "%s"' % mode)
def fsMoveLinkView(quotedLinkPath): """Move-link, view 1/2: select destination box.""" user = g.user db = dbGetDatabase() # first we find the link fsPathString = urllib.parse.unquote_plus(quotedLinkPath) lsPath = splitPathString(fsPathString) boxPath, linkName = lsPath[:-1], lsPath[-1] parentBox = getBoxFromPath(db, boxPath, user) link = getLinkFromParent(db, parentBox, linkName, user) if link is None: raise OstracionError('Link not found') # 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']['link']['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='link_move', object_quoted_path=quotedLinkPath, colorShadeMap=colorShadeMap, user=user, iconUrl=makeSettingImageUrl(g, 'app_images', 'move'), pageTitle='Select link destination', pageSubtitle=(('Choose the box to which link "%s" shall ' 'be moved from "%s"') % ( link.title, describeBoxTitle(parentBox), )), actions=None, backToUrl=None if destinationsExist else url_for( 'lsView', lsPathString='/'.join(boxPath[1:]), ), breadCrumbs=makeBreadCrumbs( boxPath, g, appendedItems=[{ 'kind': 'external_link', 'target': link, }, { 'kind': 'link', 'target': None, 'name': 'Move link', }], ), )
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 _traverseForAccountDeletion(db, parentBox, username, user, path, fileStorageDirectory): """ Traverse the tree (one call per box, recursively+iteratively) and collect a delete queue while updating items found in various ways (deletions, icon resets, metadata resets, forced renames). """ fsDeleteQueue = [] for file in getFilesFromBox(db, parentBox): if (file.creator_username == username or file.editor_username == username): fsDeleteQueue += deleteFile( db, parentBox, file, None, fileStorageDirectory=fileStorageDirectory, skipCommit=True, accountDeletionInProgress=True, ) else: if file.icon_file_id_username == username: fsDeleteQueue += updateFileThumbnail( db, file, None, None, user, fileStorageDirectory=fileStorageDirectory, accountDeletionInProgress=True, skipCommit=True, ) iconedFile = getFileFromParent(db, parentBox, file.name, None) else: iconedFile = file # "iconed" as in "icon-wise fixed" if iconedFile.metadata_username == username: newFileName = findFirstAvailableObjectNameInBox( db, parentBox, prefix='REDACTED_FILE_', suffix='', ) newDescription = 'File name redacted upon account deletion' newFile = File(**recursivelyMergeDictionaries( { 'name': newFileName, 'description': newDescription, 'metadata_username': '', }, defaultMap=iconedFile.asDict(), )) updateFile( db, path, iconedFile.name, newFile, None, accountDeletionInProgress=True, skipCommit=True, ) # for link in getLinksFromBox(db, parentBox): if link.creator_username == username: fsDeleteQueue += deleteLink( db, parentBox, link, None, fileStorageDirectory=fileStorageDirectory, skipCommit=True, accountDeletionInProgress=True, ) else: if link.icon_file_id_username == username: fsDeleteQueue += updateLinkThumbnail( db, link, None, None, user, fileStorageDirectory=fileStorageDirectory, accountDeletionInProgress=True, skipCommit=True, ) iconedLink = getLinkFromParent(db, parentBox, link.name, None) else: iconedLink = link # "iconed" as in "icon-wise fixed" if iconedLink.metadata_username == username: newLinkName = findFirstAvailableObjectNameInBox( db, parentBox, prefix='REDACTED_LINK_', suffix='', ) newDescription = 'Link data redacted upon account deletion' newLink = Link(**recursivelyMergeDictionaries( { 'name': newLinkName, 'description': newDescription, 'target': '#', 'metadata_username': '', }, defaultMap=iconedLink.asDict(), )) updateLink( db, path, iconedLink.name, newLink, None, accountDeletionInProgress=True, skipCommit=True, ) # for box in getBoxesFromParent( db, parentBox, None, accountDeletionInProgress=True): if box is not None and box.box_name != '': fsDeleteQueue += _traverseForAccountDeletion( db, box, username, user, path + [box.box_name], fileStorageDirectory=fileStorageDirectory, ) if box.creator_username == username and _boxHasNoChildren(db, box): fsDeleteQueue += deleteBox( db, box, parentBox, None, fileStorageDirectory=fileStorageDirectory, accountDeletionInProgress=True, skipCommit=True, ) else: if (box.icon_file_id_username == username or box.creator_username == username): fsDeleteQueue += updateBoxThumbnail( db, box, None, None, user, fileStorageDirectory=fileStorageDirectory, accountDeletionInProgress=True, skipCommit=True, ) iconedBox = getBoxFromPath( db, path + [box.box_name], None, accountDeletionInProgress=True, ) else: iconedBox = box # if (iconedBox.metadata_username == username or iconedBox.creator_username == username): # newBoxName = findFirstAvailableObjectNameInBox( db, parentBox, prefix='REDACTED_BOX_', suffix='', ) newDescription = 'Box name redacted upon account deletion' mdNewBoxContrib = { 'box_name': newBoxName, 'description': newDescription, 'title': newBoxName, 'metadata_username': '', } # if iconedBox.creator_username == username: cNewBoxContrib = { 'creator_username': '', } else: cNewBoxContrib = {} # newBox = Box(**recursivelyMergeDictionaries( recursivelyMergeDictionaries( mdNewBoxContrib, defaultMap=cNewBoxContrib, ), defaultMap=iconedBox.asDict(), )) updateBox( db, path + [box.box_name], newBox, None, accountDeletionInProgress=True, skipCommit=True, ) # return fsDeleteQueue
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 unsetIconView(mode, itemPathString=''): """Route for explicit removal of thumbnail, if any, to 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': modeName = 'box' boxPath = splitPathString(itemPathString) thisItem = getBoxFromPath(db, boxPath, user) parentBox = None elif mode == 'f': modeName = 'file' fullPath = splitPathString(itemPathString) boxPath, fileName = fullPath[:-1], fullPath[-1] parentBox = getBoxFromPath(db, boxPath, user) thisItem = getFileFromParent(db, parentBox, fileName, user) elif mode == 'l': modeName = 'link' fullPath = splitPathString(itemPathString) boxPath, linkName = fullPath[:-1], fullPath[-1] parentBox = getBoxFromPath(db, boxPath, user) thisItem = getLinkFromParent(db, parentBox, linkName, user) elif mode == 'u': modeName = 'user' parentBox = None thisItem = user elif mode == 'au': modeName = 'adminuser' if userIsAdmin(db, user): thisItem = dbGetUser(db, itemPathString) parentBox = None else: raise OstracionError('Insufficient permissions') elif mode == 's': modeName = 'settingIcon' if userIsAdmin(db, user): settingGroupId, settingId = itemPathString.split('/') thisItem = g.settings['image'][settingGroupId][settingId] parentBox = None else: raise OstracionError('Insufficient permissions') else: raise RuntimeError('Unknown mode encountered') # storageSuccess = storeFileAsThumbnail( db, fileToSave=None, mode=mode, thumbnailFormat=determineThumbnailFormatByModeAndTarget( db, mode, thisItem, ), targetItem=thisItem, parentBox=parentBox, user=user, tempFileDirectory=tempFileDirectory, fileStorageDirectory=fileStorageDirectory, ) if not storageSuccess: raise OstracionError('Could not unset 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')