def calendarMakerIndexView(): """Main calendar maker view.""" user = g.user db = dbGetDatabase() request._onErrorUrl = url_for( 'lsView', lsPathString='', ) # destBoxString = request.cookies.get('apps_calendarmaker_destbox') currentCalendar = cookiesToCurrentCalendar(request.cookies) coverImagePathString = currentCalendar.get('cover_image_path_string') calendarImagePaths = currentCalendar.get('image_path_strings', []) cProps = currentCalendar.get('properties', {}) # if destBoxString is None: destBoxMessage = 'Destination box not set.' destBox = None destBoxName = None else: destBoxMessage = 'Destination box: "%s".' % destBoxString destBoxPath = splitPathString(destBoxString) destBox = getBoxFromPath(db, destBoxPath, user) destBoxName = describeBoxName(destBox) if coverImagePathString is None: coverMessage = 'Please select a cover' coverImageFileObject = None else: coverMessage = 'Cover selected' coverImageFileObject = pathToFileStructure( db, user, coverImagePathString, ) # calendarImages = [ pathToFileStructure(db, user, imgPath) for imgPath in calendarImagePaths ] # numRequiredImages = countMonths( cProps.get('year0'), cProps.get('month0'), cProps.get('year1'), cProps.get('month1'), ) # settingsDesc = describeSettings(cProps) settingsSummaryText = ('Not set' if settingsDesc is None else ' '.join( '%s.' % stc for stc in settingsDesc)) # if numRequiredImages is not None: if numRequiredImages <= len(calendarImages): gen1 = True gen1Message = [] else: gen1 = False gen1Message = ['Select enough images'] else: gen1 = False gen1Message = ['Set valid start/end dates'] if destBox is not None: gen2 = True gen2Message = [] else: gen2 = False gen2Message = ['Select a destination box'] if coverImageFileObject is not None: gen0 = True gen3Message = [] else: gen0 = False gen3Message = ['Select a cover image'] canGenerate = all([gen0, gen1, gen2]) generationMessages = gen3Message + gen1Message + gen2Message pageFeatures = prepareTaskPageFeatures( appsPageDescriptor, ['root', 'calendar_maker'], g, overrides={ 'pageSubtitle': ('Create your own custom calendar. (1) Configure ' 'dates and calendar appearance. (2) Select enoug' 'h images. (3) Choose a destination box for the ' 'calendar. (4) Hit "Generate calendar".'), }, ) # return render_template( 'apps/calendarmaker/index.html', user=user, settingsText=settingsSummaryText, destBox=destBox, destBoxName=destBoxName, bgcolor=g.settings['color']['app_colors']['calendar_maker_color'] ['value'], calendarImages=calendarImages, coverImageFileObject=coverImageFileObject, numRequiredImages=numRequiredImages, canGenerate=canGenerate, generationMessages=generationMessages, **pageFeatures, )
def calendarMakerImagesView(): """Calendar image-selection page view.""" user = g.user db = dbGetDatabase() request._onErrorUrl = url_for( 'calendarMakerIndexView', lsPathString='', ) # browseBoxString = request.cookies.get('apps_calendarmaker_browsebox') currentCalendar = cookiesToCurrentCalendar(request.cookies) coverImagePathString = currentCalendar.get('cover_image_path_string') calendarImagePaths = currentCalendar.get('image_path_strings', []) cProps = currentCalendar.get('properties', {}) # if coverImagePathString is None: coverImageFileObject = None else: coverImageFileObject = pathToFileStructure( db, user, coverImagePathString, ) # if browseBoxString is not None: browseBoxPath = splitPathString(browseBoxString) browseBox = getBoxFromPath(db, browseBoxPath, user) choosableFiles = [{ 'file': file, 'path': browseBoxPath[1:] + [file.name], 'obj_path': urllib.parse.quote_plus('/'.join(browseBoxPath[1:] + [file.name], )), } for file in sorted( getFilesFromBox(db, browseBox), key=lambda f: (f.name.lower(), f.name), ) if file.mime_type in admittedImageMimeTypeToExtension] browseBoxName = describeBoxName(browseBox) else: browseBox = None browseBoxName = None choosableFiles = [] # calendarImages = [ pathToFileStructure(db, user, imgPath) for imgPath in calendarImagePaths ] # numRequiredImages = countMonths( cProps.get('year0'), cProps.get('month0'), cProps.get('year1'), cProps.get('month1'), ) # pageFeatures = prepareTaskPageFeatures( appsPageDescriptor, ['root', 'calendar_maker', 'images'], g, ) return render_template( 'apps/calendarmaker/images.html', user=user, browseBox=browseBox, browseBoxName=browseBoxName, choosableFiles=choosableFiles, coverImageFileObject=coverImageFileObject, bgcolor=g.settings['color']['app_colors']['calendar_maker_color'] ['value'], bgcolorbrowse=g.settings['color']['app_colors'] ['calendar_maker_browse_color']['value'], calendarImages=calendarImages, numRequiredImages=numRequiredImages, **pageFeatures, )
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 downloadBoxView(boxPathString=''): user = g.user lsPath = splitPathString(boxPathString) db = dbGetDatabase() # canDownloadArchive = userCanDownloadArchive( db, user, g.settings, ) # if not canDownloadArchive: return abort(404) else: thisBox = getBoxFromPath(db, lsPath, user) if thisBox is not None: boxPath = lsPath[1:] tempFileDirectory = g.settings['system']['system_directories'][ 'temp_directory']['value'] fileStorageDirectory = g.settings['system']['system_directories'][ 'fs_directory']['value'] # we extract the tree "from this box downward" tree = collectTreeFromBox(db, thisBox, user, admitFiles=True) overallSize = treeSize(tree) # size-dependent handling by reading settings mibSize = bytesToMiB(overallSize) archiveWarningSizeMib = g.settings['behaviour']['archives'][ 'archive_download_alert_size']['value'] archiveBlockSizeMib = g.settings['behaviour']['archives'][ 'archive_download_blocking_size']['value'] if not optionNumberLeq(archiveBlockSizeMib, mibSize): # archive is simply too big (hard limit) oeText = ('Cannot prepare archive: box size, %s' ', exceeds configured limits') raise OstracionError(oeText % formatBytesSize(overallSize)) else: # we may have to issue a warning to the downloader: # this if (1) rather large archive, # (2) no previous 'ok' was given hasConfirmed = request.args.get('confirmed') == 'yes' if all([ not optionNumberLeq(archiveWarningSizeMib, mibSize), not hasConfirmed, ]): # we issue the warning and wait confirmText = ('Preparing this archive may take some ' 'time due to the size of the box (%s). ' 'Click this message to really proceed ' 'with the download.') flashMessage( 'Warning', 'Caution', confirmText % formatBytesSize(overallSize), url=url_for( 'downloadBoxView', boxPathString=boxPathString, confirmed='yes', ), ) return redirect( url_for( 'lsView', lsPathString=boxPathString, )) else: # we collect the information needed to prepare the # archive file. For now, no empty boxes # (a zip format limitation) def collectArchivablePairs(tr, accPath=''): hereFiles = [{ 'type': 'file', 'path': fileIdToPath( file['file'].file_id, fileStorageDirectory, ), 'zip_path': os.path.join( accPath, file['file'].name, ), } for file in tr['contents']['files']] + [{ 'type': 'data', 'data': link['link'].formatAsString(), 'zip_path': os.path.join( accPath, '%s' % link['link'].name, ), } for link in tr['contents']['links']] subFiles = [ fp for subBox in tr['contents']['boxes'] for fp in collectArchivablePairs(subBox, accPath=os.path.join( accPath, subBox['box'].box_name, )) ] return hereFiles + subFiles # we make the tree into a list of filePairs, ready to zip inPairs = collectArchivablePairs(tree) filePairs = [p for p in inPairs if p['type'] == 'file'] dataPairs = [p for p in inPairs if p['type'] == 'data'] # we create the zip _, archiveFileTitle = temporarySplitFileName( tempFileDirectory, ) makeZipFile( os.path.join(tempFileDirectory, archiveFileTitle), filePairs, dataPairs, ) # Now the file exists, ready to be served. # Instead of a plain send_from_directory, though, # we use the answer "Stream file, then delete" # by Sean Vieira here: # https://stackoverflow.com/questions/24612366/ # delete-an-uploaded-file-after-downloading-it-from-flask def StreamFileAndRemoveIt(localFileName): fileHandle = open(localFileName, 'rb') yield from fileHandle fileHandle.close() os.remove(localFileName) zipFileName = '%s.zip' % describeBoxName(thisBox, ) contentDisposition = 'attachment; filename="%s"' % ( zipFileName, ) return current_app.response_class( StreamFileAndRemoveIt(localFileName=os.path.join( tempFileDirectory, archiveFileTitle, ), ), headers={ 'Content-Disposition': contentDisposition, }, mimetype='application/zip', ) else: request._onErrorUrl = url_for( 'lsView', lsPathString='/'.join(lsPath[1:-1]), ) raise OstracionWarning('Cannot access the specified box "%s"' % lsPath[-1])
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, )