def _get_base_path(self, attachment): # TODO: adapt to new models (needs extra properties to use event TZ) obj = linked_object = attachment.folder.object paths = [] while obj != self.event_new: start_date = _get_start_dt(obj) if start_date is not None: if isinstance(obj, SubContribution): paths.append(secure_filename('{}_{}'.format(obj.position, obj.title), '')) else: paths.append(secure_filename('{}_{}'.format(format_time(start_date, format='HHmm', timezone=self.event_new.timezone), obj.title), '')) else: if isinstance(obj, SubContribution): paths.append(secure_filename('{}){}'.format(obj.position, obj.title), unicode(obj.id))) else: paths.append(secure_filename(obj.title, unicode(obj.id))) obj = _get_obj_parent(obj) linked_obj_start_date = _get_start_dt(linked_object) if attachment.folder.object != self.event_new and linked_obj_start_date is not None: paths.append(secure_filename(linked_obj_start_date.strftime('%Y%m%d_%A'), '')) return reversed(paths)
def _get_base_path(self, attachment): obj = linked_object = attachment.folder.linked_object paths = [] while obj != self._conf: owner = obj.getOwner() if isinstance(obj, SubContribution): start_date = owner.getAdjustedStartDate() else: start_date = obj.getAdjustedStartDate() if start_date is not None: paths.append(secure_filename(start_date.strftime('%H%M_{}').format(obj.getTitle()), '')) else: paths.append(secure_filename(obj.getTitle(), unicode(obj.getId()))) obj = owner if isinstance(linked_object, SubContribution): linked_obj_start_date = linked_object.getOwner().getAdjustedStartDate() else: linked_obj_start_date = linked_object.getAdjustedStartDate() if attachment.folder.linked_object != self._conf and linked_obj_start_date is not None: paths.append(secure_filename(linked_obj_start_date.strftime('%Y%m%d_%A'), '')) return reversed(paths)
def _prepare_folder_structure(self, attachment): registration = attachment.registration regform_title = secure_filename(attachment.registration.registration_form.title, 'registration_form') registrant_name = secure_filename("{}_{}".format(registration.get_full_name(), unicode(registration.friendly_id)), registration.friendly_id) file_name = secure_filename("{}_{}_{}".format(attachment.field_data.field.title, attachment.field_data.field_id, attachment.filename), attachment.filename) return os.path.join(*self._adjust_path_length([regform_title, registrant_name, file_name]))
def _prepare_folder_structure(self, attachment): event_dir = secure_filename(self._conf.getTitle(), None) segments = [event_dir] if event_dir else [] segments.extend(self._get_base_path(attachment)) if not attachment.folder.is_default: segments.append(secure_filename(attachment.folder.title, unicode(attachment.folder.id))) segments.append(attachment.file.filename) path = os.path.join(*adjust_path_length(filter(None, segments))) while path in self.used: # prepend the id if there's a path collision segments[-1] = '{}-{}'.format(attachment.id, segments[-1]) path = os.path.join(*adjust_path_length(filter(None, segments))) return path
def _process(self): files = request.files.getlist('file') for f in files: filename = secure_filename(f.filename, 'image') data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except IOError: # Invalid image data continue data.seek(0) if image_type not in {'jpeg', 'gif', 'png'}: continue content_type = 'image/' + image_type image = ImageFile(event_id=self._conf.id, filename=filename, content_type=content_type) image.save(data) db.session.add(image) db.session.flush() logger.info('Image {} uploaded by {}'.format(image, session.user)) signals.event_management.image_created.send(image, user=session.user) flash(ngettext("The image has been uploaded", "{count} images have been uploaded", len(files)) .format(count=len(files)), 'success') return jsonify_data(image_list=_render_image_list(self._conf))
def migrate_event_images(self): self.print_step('migrating event images') for event, picture in committing_iterator(self._iter_pictures()): local_file = picture._localFile content_type = mimetypes.guess_type(local_file.fileName)[0] or 'application/octet-stream' storage_backend, storage_path, size = self._get_local_file_info(local_file) if storage_path is None: self.print_warning(cformat('%{yellow}[{}]%{reset} -> %{red!}Not found in filesystem').format( local_file.id), event_id=event.id) continue filename = secure_filename(convert_to_unicode(local_file.fileName), 'image') image = ImageFile(event_id=event.id, filename=filename, content_type=content_type, created_dt=now_utc(), size=size, storage_backend=storage_backend, storage_file_id=storage_path) db.session.add(image) db.session.flush() map_entry = LegacyImageMapping(event_id=event.id, legacy_image_id=local_file.id, image_id=image.id) db.session.add(map_entry) if not self.quiet: self.print_success(cformat('%{cyan}[{}]%{reset} -> %{blue!}{}').format(local_file.id, image), event_id=event.id)
def _process(self): defaults = FormDefaults(self.attachment, protected=self.attachment.is_self_protected, skip_attrs={'file'}) if self.attachment.type == AttachmentType.file: form = EditAttachmentFileForm(linked_object=self.object, obj=defaults, file=self.attachment) else: form = EditAttachmentLinkForm(linked_object=self.object, obj=defaults) if form.validate_on_submit(): folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object) logger.info('Attachment %s edited by %s', self.attachment, session.user) form.populate_obj(self.attachment, skip={'acl', 'file'}) self.attachment.folder = folder if self.attachment.is_self_protected: # can't use `=` because of https://bitbucket.org/zzzeek/sqlalchemy/issues/3583 self.attachment.acl |= form.acl.data self.attachment.acl &= form.acl.data # files need special handling; links are already updated in `populate_obj` if self.attachment.type == AttachmentType.file: file = form.file.data['added'] if file: self.attachment.file = AttachmentFile(user=session.user, content_type=file.mimetype, filename=secure_filename(file.filename, 'attachment')) self.attachment.file.save(file.stream) signals.attachments.attachment_updated.send(self.attachment, user=session.user) flash(_("The attachment \"{name}\" has been updated").format(name=self.attachment.title), 'success') return jsonify_data(attachment_list=_render_attachment_list(self.object)) template = ('attachments/upload.html' if self.attachment.type == AttachmentType.file else 'attachments/add_link.html') return jsonify_template(template, form=form, existing_attachment=self.attachment, action=url_for('.modify_attachment', self.attachment), protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def _process(self): files = request.files.getlist("image") for f in files: filename = secure_filename(f.filename, "image") data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except IOError: # Invalid image data continue data.seek(0) if image_type not in {"jpeg", "gif", "png"}: continue content_type = "image/" + image_type image = ImageFile(event_new=self.event_new, filename=filename, content_type=content_type) image.save(data) db.session.flush() logger.info("Image %s uploaded by %s", image, session.user) signals.event_management.image_created.send(image, user=session.user) flash( ngettext("The image has been uploaded", "{count} images have been uploaded", len(files)).format( count=len(files) ), "success", ) return jsonify_data(image_list=_render_image_list(self.event_new))
def _process(self): f = request.files['logo'] try: img = Image.open(f) except IOError: flash(_('You cannot upload this file as a logo.'), 'error') return jsonify_data(content=None) if img.format.lower() not in {'jpeg', 'png', 'gif'}: flash(_('The file has an invalid format ({format})').format(format=img.format), 'error') return jsonify_data(content=None) if img.mode == 'CMYK': flash(_('The logo you uploaded is using the CMYK colorspace and has been converted to RGB. Please check if ' 'the colors are correct and convert it manually if necessary.'), 'warning') img = img.convert('RGB') image_bytes = BytesIO() img.save(image_bytes, 'PNG') image_bytes.seek(0) content = image_bytes.read() self.event.logo = content self.event.logo_metadata = { 'hash': crc32(content), 'size': len(content), 'filename': os.path.splitext(secure_filename(f.filename, 'logo'))[0] + '.png', 'content_type': 'image/png' } flash(_('New logo saved'), 'success') logger.info("New logo '%s' uploaded by %s (%s)", f.filename, session.user, self.event) return jsonify_data(content=get_logo_data(self.event))
def _process(self): f = request.files["file"] try: img = Image.open(f) except IOError: flash(_("You cannot upload this file as a logo."), "error") return jsonify_data(content=None) if img.format.lower() not in {"jpeg", "png", "gif"}: flash(_("The file has an invalid format ({format})").format(format=img.format), "error") return jsonify_data(content=None) if img.mode == "CMYK": flash( _( "The logo you uploaded is using the CMYK colorspace and has been converted to RGB. Please check if " "the colors are correct and convert it manually if necessary." ), "warning", ) img = img.convert("RGB") image_bytes = BytesIO() img.save(image_bytes, "PNG") image_bytes.seek(0) content = image_bytes.read() self.event.logo = content self.event.logo_metadata = { "hash": crc32(content), "size": len(content), "filename": os.path.splitext(secure_filename(f.filename, "logo"))[0] + ".png", "content_type": "image/png", } flash(_("New logo saved"), "success") logger.info("New logo '%s' uploaded by %s (%s)", f.filename, session.user, self.event) return jsonify_data(content=_logo_data(self.event))
def _process(self): files = request.files.getlist('image') num = 0 for f in files: filename = secure_filename(f.filename, 'image') data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except IOError: # Invalid image data continue data.seek(0) # XXX: mpo is basically JPEG and JPEGs from some cameras are (wrongfully) detected as mpo if image_type == 'mpo': image_type = 'jpeg' elif image_type not in {'jpeg', 'gif', 'png'}: flash(_("The image '{name}' has an invalid type ({type}); only JPG, GIF and PNG are allowed.") .format(name=f.filename, type=image_type), 'error') continue content_type = 'image/' + image_type image = ImageFile(event=self.event, filename=filename, content_type=content_type) image.save(data) num += 1 db.session.flush() logger.info('Image %s uploaded by %s', image, session.user) signals.event_management.image_created.send(image, user=session.user) flash(ngettext("The image has been uploaded", "{count} images have been uploaded", num) .format(count=len(files)), 'success') return jsonify_data(image_list=_render_image_list(self.event))
def _process_logo(self, logo, event): path = get_archived_file(logo, self.archive_dirs)[1] if path is None: self.print_error(cformat('%{red!}Logo not found on disk; skipping it'), event_id=event.id) return try: logo_image = Image.open(path) except IOError as e: self.print_warning("Cannot open {}: {}".format(path, e), event_id=event.id) return if logo_image.mode == 'CMYK': self.print_warning("Logo is a CMYK {}; converting to RGB".format(logo_image.format), event_id=event.id) # this may result in wrong colors, but there's not much we can do... logo_image = logo_image.convert('RGB') logo_bytes = BytesIO() logo_image.save(logo_bytes, 'PNG') logo_bytes.seek(0) logo_content = logo_bytes.read() logo_filename = secure_filename(convert_to_unicode(logo.fileName), 'logo') logo_filename = os.path.splitext(logo_filename)[0] + '.png' event.logo_metadata = { 'size': len(logo_content), 'hash': crc32(logo_content), 'filename': logo_filename, 'content_type': 'image/png' } event.logo = logo_content if not self.quiet: self.print_success(cformat('- %{cyan}[Logo] {}').format(logo.fileName), event_id=event.id)
def _process_POST(self): f = request.files[self.IMAGE_TYPE] try: img = Image.open(f) except IOError: flash(_('You cannot upload this file as an icon/logo.'), 'error') return jsonify_data(content=None) if img.format.lower() not in {'jpeg', 'png', 'gif'}: flash(_('The file has an invalid format ({format})').format(format=img.format), 'error') return jsonify_data(content=None) if img.mode == 'CMYK': flash(_('The image you uploaded is using the CMYK colorspace and has been converted to RGB. ' 'Please check if the colors are correct and convert it manually if necessary.'), 'warning') img = img.convert('RGB') img = self._resize(img) image_bytes = BytesIO() img.save(image_bytes, 'PNG') image_bytes.seek(0) content = image_bytes.read() metadata = { 'hash': crc32(content), 'size': len(content), 'filename': os.path.splitext(secure_filename(f.filename, self.IMAGE_TYPE))[0] + '.png', 'content_type': 'image/png' } self._set_image(content, metadata) flash(self.SAVED_FLASH_MSG, 'success') logger.info("New {} '%s' uploaded by %s (%s)".format(self.IMAGE_TYPE), f.filename, session.user, self.category) return jsonify_data(content=get_image_data(self.IMAGE_TYPE, self.category))
def _prepare_folder_structure(self, item): attachment = item.attachment event_dir = secure_filename(self.event_new.title, None) segments = [event_dir] if event_dir else [] if _get_start_dt(attachment.folder.object) is None: segments.append('Unscheduled') segments.extend(self._get_base_path(attachment)) if not attachment.folder.is_default: segments.append(secure_filename(attachment.folder.title, unicode(attachment.folder.id))) segments.append(attachment.file.filename) path = os.path.join(*self._adjust_path_length(filter(None, segments))) while path in self.used_filenames: # prepend the id if there's a path collision segments[-1] = '{}-{}'.format(attachment.id, segments[-1]) path = os.path.join(*self._adjust_path_length(filter(None, segments))) return path
def _process(self): filename = '{}-category.atom'.format(secure_filename(self.category.title, str(self.category.id))) buf = serialize_category_atom(self.category, url_for(request.endpoint, self.category, _external=True), session.user, Event.end_dt >= now_utc()) return send_file(filename, buf, 'application/atom+xml')
def _process(self): from indico.modules.events import Event filename = '{}-category.atom'.format(secure_filename(self._target.getName(), str(self._target.id))) buf = serialize_category_atom(self._target, url_for(request.endpoint, self._target, _external=True), session.user, Event.end_dt >= now_utc()) return send_file(filename, buf, 'application/atom+xml')
def pack(self, fileHandler=None): for contribution in self._conf.as_event.contributions: reviewingStatus = self._conf.getReviewManager(contribution).getLastReview().getRefereeJudgement().getJudgement() if reviewingStatus == "Accept": dirName = secure_filename(contribution.title, fallback='') self._packContribution(contribution, dirName, fileHandler) fileHandler.close() return fileHandler.getPath()
def _store_paper_template_file(template, file): content_type = mimetypes.guess_type(file.filename)[0] or file.mimetype or 'application/octet-stream' filename = secure_filename(file.filename, 'template') # reset fields in case an existing file is replaced so we can save() again template.storage_backend = None template.storage_file_id = None template.size = None template.content_type = content_type template.filename = filename template.save(file.stream)
def send_file(name, path_or_fd, mimetype, last_modified=None, no_cache=True, inline=None, conditional=False, safe=True): """Sends a file to the user. `name` is required and should be the filename visible to the user. `path_or_fd` is either the physical path to the file or a file-like object (e.g. a StringIO). `mimetype` SHOULD be a proper MIME type such as image/png. It may also be an indico-style file type such as JPG. `last_modified` may contain a unix timestamp or datetime object indicating the last modification of the file. `no_cache` can be set to False to disable no-cache headers. `inline` defaults to true except for certain filetypes like XML and CSV. It SHOULD be set to false only when you want to force the user's browser to download the file. Usually it is much nicer if e.g. a PDF file can be displayed inline so don't disable it unless really necessary. `conditional` is very useful when sending static files such as CSS/JS/images. It will allow the browser to retrieve the file only if it has been modified (based on mtime and size). `safe` adds some basic security features such a adding a content-security-policy and forcing inline=False for text/html mimetypes """ name = secure_filename(name, 'file') if inline is None: inline = mimetype not in ('XML', 'CSV') if request.user_agent.platform == 'android': # Android is just full of fail when it comes to inline content-disposition... inline = False if mimetype.isupper() and '/' not in mimetype: # Indico file type such as "JPG" or "CSV" from indico.core.config import Config mimetype = Config.getInstance().getFileTypeMimeType(mimetype) if _is_office_mimetype(mimetype): inline = False if safe and mimetype in ('text/html', 'image/svg+xml'): inline = False try: rv = _send_file(path_or_fd, mimetype=mimetype, as_attachment=not inline, attachment_filename=name, conditional=conditional) except IOError: from MaKaC.common.info import HelperMaKaCInfo if not app.debug: raise raise NotFound('File not found: %s' % path_or_fd) if safe: rv.headers.add('Content-Security-Policy', "script-src 'self'; object-src 'self'") if inline: # send_file does not add this header if as_attachment is False rv.headers.add('Content-Disposition', 'inline', filename=name) if last_modified: if not isinstance(last_modified, int): last_modified = int(time.mktime(last_modified.timetuple())) rv.last_modified = last_modified if no_cache: del rv.expires del rv.cache_control.max_age rv.cache_control.public = False rv.cache_control.private = True rv.cache_control.no_cache = True return rv
def _attachment_from_resource(self, folder, material, resource, base_object=None): modified_dt = ( getattr(material, "_modificationDS", None) or getattr(base_object, "startDate", None) or getattr(base_object, "_modificationDS", None) or now_utc() ) data = { "id": self._get_id(Attachment), "folder_id": folder["id"], "user_id": self.janitor_user_id, "title": convert_to_unicode(resource.name).strip() or folder["title"], "description": convert_to_unicode(resource.description), "modified_dt": modified_dt, } if resource.__class__.__name__ == "Link": data["type"] = AttachmentType.link data["link_url"] = convert_to_unicode(resource.url).strip() if not data["link_url"]: self.print_error( cformat("%{red!}[{}] Skipping link, missing URL").format(data["title"]), event_id=base_object.id ) return None else: data["type"] = AttachmentType.file storage_backend, storage_path, size = self._get_local_file_info(resource) if storage_path is None: self.print_error( cformat("%{red!}File {} not found on disk").format(resource._LocalFile__archivedId), event_id=base_object.id, ) return None filename = secure_filename(convert_to_unicode(resource.fileName), "attachment") file_data = { "id": self._get_id(AttachmentFile), "attachment_id": data["id"], "user_id": self.janitor_user_id, "created_dt": modified_dt, "filename": filename, "content_type": mimetypes.guess_type(filename)[0] or "application/octet-stream", "size": size, "storage_backend": storage_backend, "storage_file_id": storage_path, } data["file_id"] = file_data["id"] self.todo[AttachmentFile].append(file_data) tmp = ProtectionTarget() protection_from_ac(tmp, resource._Resource__ac) self.todo[AttachmentPrincipal] += tmp.make_principal_rows(attachment_id=data["id"]) data["protection_mode"] = tmp.protection_mode self.todo[Attachment].append(data) return data
def _process(self): files = request.files.getlist('file') for f in files: filename = secure_filename(f.filename, 'paper') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' paper_file = PaperFile(filename=filename, content_type=content_type, contribution=self.contrib) paper_file.save(f.file) db.session.flush() # TODO: logger logger.info('Paper file %s uploaded by %s', paper_file, session.user) # TODO: add signal flash(ngettext("The paper file has been uploaded", "{count} paper files have been uploaded", len(files)) .format(count=len(files)), 'success') return jsonify_data(html=_render_paper_file_list(self.contrib))
def _process(self): files = request.files.getlist('paper_file') for f in files: filename = secure_filename(f.filename, 'paper') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' paper_file = PaperFile(filename=filename, content_type=content_type, contribution=self.contrib) paper_file.save(f.file) db.session.flush() # TODO: logger logger.info('Paper file %s uploaded by %s', paper_file, session.user) # TODO: add signal flash(ngettext("The paper file has been uploaded", "{count} paper files have been uploaded", len(files)) .format(count=len(files)), 'success') return jsonify_data(html=_render_paper_file_list(self.contrib))
def _process(self): f = request.files['css_file'] self.event.stylesheet = to_unicode(f.read()).strip() self.event.stylesheet_metadata = { 'hash': crc32(self.event.stylesheet), 'size': len(self.event.stylesheet), 'filename': secure_filename(f.filename, 'stylesheet.css') } db.session.flush() flash(_('New CSS file saved. Do not forget to enable it ("Use custom CSS") after verifying that it is correct ' 'using the preview.'), 'success') logger.info('CSS file for %s uploaded by %s', self.event, session.user) return jsonify_data(content=get_css_file_data(self.event))
def process_form_data(self, registration, value, old_data=None, billable_items_locked=False): data = {'field_data': self.form_item.current_data} file_ = value['uploaded_file'] if file_: # we have a file -> always save it data['file'] = { 'data': file_.file, 'name': secure_filename(file_.filename, 'attachment'), 'content_type': mimetypes.guess_type(file_.filename)[0] or file_.mimetype or 'application/octet-stream' } elif not value['keep_existing']: data['file'] = None return data
def set_user_avatar(user, avatar, filename, lastmod=None): if lastmod is None: lastmod = http_date(now_utc()) elif isinstance(lastmod, datetime): lastmod = http_date(lastmod) user.picture = avatar user.picture_metadata = { 'hash': crc32(avatar), 'size': len(avatar), 'filename': os.path.splitext(secure_filename(filename, 'avatar'))[0] + '.png', 'content_type': 'image/png', 'lastmod': lastmod, }
def send_file(name, path_or_fd, mimetype, last_modified=None, no_cache=True, inline=None, conditional=False, safe=True): """Sends a file to the user. `name` is required and should be the filename visible to the user. `path_or_fd` is either the physical path to the file or a file-like object (e.g. a StringIO). `mimetype` SHOULD be a proper MIME type such as image/png. It may also be an indico-style file type such as JPG. `last_modified` may contain a unix timestamp or datetime object indicating the last modification of the file. `no_cache` can be set to False to disable no-cache headers. `inline` defaults to true except for certain filetypes like XML and CSV. It SHOULD be set to false only when you want to force the user's browser to download the file. Usually it is much nicer if e.g. a PDF file can be displayed inline so don't disable it unless really necessary. `conditional` is very useful when sending static files such as CSS/JS/images. It will allow the browser to retrieve the file only if it has been modified (based on mtime and size). `safe` adds some basic security features such a adding a content-security-policy and forcing inline=False for text/html mimetypes """ name = secure_filename(name, 'file') assert '/' in mimetype if inline is None: inline = mimetype not in ('text/csv', 'text/xml', 'application/xml') if request.user_agent.platform == 'android': # Android is just full of fail when it comes to inline content-disposition... inline = False if _is_office_mimetype(mimetype): inline = False if safe and mimetype in ('text/html', 'image/svg+xml'): inline = False try: rv = _send_file(path_or_fd, mimetype=mimetype, as_attachment=not inline, attachment_filename=name, conditional=conditional) except IOError: if not current_app.debug: raise raise NotFound('File not found: %s' % path_or_fd) if safe: rv.headers.add('Content-Security-Policy', "script-src 'self'; object-src 'self'") if inline: # send_file does not add this header if as_attachment is False rv.headers.add('Content-Disposition', 'inline', filename=name) if last_modified: if not isinstance(last_modified, int): last_modified = int(time.mktime(last_modified.timetuple())) rv.last_modified = last_modified if no_cache: del rv.expires del rv.cache_control.max_age rv.cache_control.public = False rv.cache_control.private = True rv.cache_control.no_cache = True return rv
def _process(self): defaults = FormDefaults(self.attachment, protected=self.attachment.is_self_protected, skip_attrs={'file'}) if self.attachment.type == AttachmentType.file: form = EditAttachmentFileForm(linked_object=self.object, obj=defaults, file=self.attachment) else: form = EditAttachmentLinkForm(linked_object=self.object, obj=defaults) if form.validate_on_submit(): folder = form.folder.data or AttachmentFolder.get_or_create_default( linked_object=self.object) logger.info('Attachment %s edited by %s', self.attachment, session.user) form.populate_obj(self.attachment, skip={'acl', 'file'}) self.attachment.folder = folder if self.attachment.is_self_protected: # can't use `=` because of https://bitbucket.org/zzzeek/sqlalchemy/issues/3583 self.attachment.acl |= form.acl.data self.attachment.acl &= form.acl.data # files need special handling; links are already updated in `populate_obj` if self.attachment.type == AttachmentType.file: file = form.file.data['added'] if file: self.attachment.file = AttachmentFile( user=session.user, content_type=file.mimetype, filename=secure_filename(file.filename, 'attachment')) self.attachment.file.save(file.file) signals.attachments.attachment_updated.send(self.attachment, user=session.user) flash( _("The attachment \"{name}\" has been updated").format( name=self.attachment.title), 'success') return jsonify_data( attachment_list=_render_attachment_list(self.object)) template = ('attachments/upload.html' if self.attachment.type == AttachmentType.file else 'attachments/add_link.html') return jsonify_template( template, form=form, existing_attachment=self.attachment, action=url_for('.modify_attachment', self.attachment), protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def _get_base_path(self, attachment): # TODO: adapt to new models (needs extra properties to use event TZ) obj = linked_object = attachment.folder.object paths = [] while obj != self.event: start_date = _get_start_dt(obj) if start_date is not None: if isinstance(obj, SubContribution): paths.append(secure_filename(f'{obj.position}_{obj.title}', '')) else: time = format_time(start_date, format='HHmm', timezone=self.event.timezone) paths.append(secure_filename(f'{time}_{obj.title}', '')) else: if isinstance(obj, SubContribution): paths.append(secure_filename(f'{obj.position}_{obj.title}', str(obj.id))) else: paths.append(secure_filename(obj.title, str(obj.id))) obj = _get_obj_parent(obj) linked_obj_start_date = _get_start_dt(linked_object) if attachment.folder.object != self.event and linked_obj_start_date is not None: paths.append(secure_filename(linked_obj_start_date.strftime('%Y%m%d_%A'), '')) return reversed(paths)
def _build_storage_path(self): self.registration.registration_form.assign_id() self.registration.assign_id() path_segments = [ 'event', strict_unicode(self.registration.event_id), 'registrations', strict_unicode(self.registration.registration_form.id), strict_unicode(self.registration.id) ] assert None not in path_segments # add timestamp in case someone uploads the same file again filename = '{}-{}-{}'.format(self.field_data.field_id, int(time.time()), secure_filename(self.filename, 'file')) path = posixpath.join(*(path_segments + [filename])) return config.ATTACHMENT_STORAGE, path
def create_paper_revision(paper, submitter, files): revision = PaperRevision(paper=paper, submitter=submitter) for f in files: filename = secure_filename(f.filename, 'paper') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' pf = PaperFile(filename=filename, content_type=content_type, paper_revision=revision, _contribution=paper.contribution) pf.save(f.stream) db.session.flush() db.session.expire(revision._contribution, ['_paper_last_revision']) notify_paper_revision_submission(revision) logger.info('Paper revision %r submitted by %r', revision, session.user) paper.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Papers', "Paper revision {} submitted for contribution {} ({})" .format(revision.id, paper.contribution.title, paper.contribution.friendly_id), session.user) return revision
def create_paper_revision(paper, submitter, files): revision = PaperRevision(paper=paper, submitter=submitter) for f in files: filename = secure_filename(f.filename, 'paper') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' pf = PaperFile(filename=filename, content_type=content_type, paper_revision=revision, _contribution=paper.contribution) pf.save(f.stream) db.session.flush() db.session.expire(revision._contribution, ['_paper_last_revision']) notify_paper_revision_submission(revision) logger.info('Paper revision %r submitted by %r', revision, session.user) paper.event.log(EventLogRealm.management, EventLogKind.positive, 'Papers', "Paper revision {} submitted for contribution {} ({})" .format(revision.id, paper.contribution.title, paper.contribution.friendly_id), session.user) return revision
def _process_css(self, css): stylesheet = css._localFile path = get_archived_file(stylesheet, self.archive_dirs)[1] if path is None: self.print_error('%[red!]CSS file not found on disk; skipping it') return with open(path, 'rb') as f: stylesheet_content = convert_to_unicode(f.read()) self.event.stylesheet_metadata = { 'size': len(stylesheet_content), 'hash': crc32(stylesheet_content), 'filename': secure_filename(convert_to_unicode(stylesheet.fileName), 'stylesheet.css'), 'content_type': 'text/css' } self.event.stylesheet = stylesheet_content if not self.quiet: self.print_success('- %[cyan][CSS] {}'.format(stylesheet.fileName))
def _process_css(self, css, event): stylesheet = css._localFile path = get_archived_file(stylesheet, self.archive_dirs)[1] if path is None: self.print_error(cformat('%{red!}CSS file not found on disk; skipping it'), event_id=event.id) return with open(path, 'rb') as f: stylesheet_content = convert_to_unicode(f.read()) event.stylesheet_metadata = { 'size': len(stylesheet_content), 'hash': crc32(stylesheet_content), 'filename': secure_filename(convert_to_unicode(stylesheet.fileName), 'stylesheet.css'), 'content_type': 'text/css' } event.stylesheet = stylesheet_content if not self.quiet: self.print_success(cformat('- %{cyan}[CSS] {}').format(stylesheet.fileName), event_id=event.id)
def add_abstract_files(abstract, files, log_action=True): if not files: return for f in files: filename = secure_filename(f.filename, 'attachment') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' abstract_file = AbstractFile(filename=filename, content_type=content_type, abstract=abstract) abstract_file.save(f.stream) db.session.flush() if log_action: logger.info('%d abstract file(s) added to %s by %s', len(files), abstract, session.user) num = len(files) if num == 1: msg = 'Added file to abstract {}'.format(abstract.verbose_title) else: msg = 'Added {} files to abstract {}'.format(num, abstract.verbose_title) abstract.event.log(EventLogRealm.management, EventLogKind.positive, 'Abstracts', msg, session.user, data={'Files': ', '.join(f.filename for f in abstract.files)})
def build_storage_path(self, obj, _new_path_re=re.compile(r'^(event/\d+/registrations/\d+/\d+/\d+-)(\d+)(-.*)$')): old_filename = obj.filename new_filename = secure_filename(obj.filename, None) assert new_filename obj.filename = new_filename new_storage_path = obj._build_storage_path()[1] obj.filename = old_filename assert new_storage_path if not isinstance(obj, RegistrationData): return new_storage_path, new_filename match = _new_path_re.match(obj.storage_file_id) if match: # already in the current format assert obj.storage_file_id == new_storage_path.replace('-0-', '-{}-'.format(match.group(2))) return obj.storage_file_id, new_filename else: match = _new_path_re.match(new_storage_path) return '{}{}{}'.format(match.group(1), crc32(obj.storage_file_id), match.group(3)), new_filename
def _process(self): f = request.files["file"] self.event.stylesheet = to_unicode(f.read()).strip() self.event.stylesheet_metadata = { "hash": crc32(self.event.stylesheet), "size": len(self.event.stylesheet), "filename": secure_filename(f.filename, "stylesheet.css"), } db.session.flush() flash( _( 'New CSS file saved. Do not forget to enable it ("Use custom CSS") after verifying that it is correct ' "using the preview." ), "success", ) logger.info("CSS file for %s uploaded by %s", self.event, session.user) return jsonify_data(content=_css_file_data(self.event))
def add_abstract_files(abstract, files, log_action=True): if not files: return for f in files: filename = secure_filename(f.filename, 'attachment') content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream' abstract_file = AbstractFile(filename=filename, content_type=content_type, abstract=abstract) abstract_file.save(f.stream) db.session.flush() if log_action: logger.info('%d abstract file(s) added to %s by %s', len(files), abstract, session.user) num = len(files) if num == 1: msg = 'Added file to abstract {}'.format(abstract.verbose_title) else: msg = 'Added {} files to abstract {}'.format(num, abstract.verbose_title) abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts', msg, session.user, data={'Files': ', '.join(f.filename for f in abstract.files)})
def _migrate_background(self, old_bg, tpl): storage_backend, storage_path, size = self.importer._get_local_file_info( old_bg) if storage_path is None: self.importer.print_error( '%[red!]File not found on disk; skipping it [{}]'.format( convert_to_unicode(old_bg.fileName)), event_id=self.event_id) return content_type = mimetypes.guess_type( old_bg.fileName)[0] or 'application/octet-stream' filename = secure_filename(convert_to_unicode(old_bg.fileName), 'attachment') return DesignerImageFile(filename=filename, content_type=content_type, size=size, storage_backend=storage_backend, storage_file_id=storage_path)
def _process_icon(self, cat, icon): path = get_archived_file(icon, self.archive_dirs)[1] if path is None: self.print_error( cformat('%{red!}Icon not found on disk; skipping it'), event_id=cat.id) return try: icon_image = Image.open(path) except IOError as e: self.print_warning("Cannot open {}: {}".format(path, e), event_id=cat.id) return if icon_image.mode == 'CMYK': self.print_warning("Icon is a CMYK {}; converting to RGB".format( icon_image.format), always=False, event_id=cat.id) # this may result in wrong colors, but there's not much we can do... icon_image = icon_image.convert('RGB') if icon_image.size != (16, 16): self.print_warning( "Icon is {}x{}; resizing to 16x16".format(*icon_image.size), always=False, event_id=cat.id) icon_image = icon_image.resize((16, 16), Image.ANTIALIAS) icon_bytes = BytesIO() icon_image.save(icon_bytes, 'PNG') icon_bytes.seek(0) icon_content = icon_bytes.read() icon_filename = secure_filename(convert_to_unicode(icon.fileName), 'icon') icon_filename = os.path.splitext(icon_filename)[0] + '.png' cat.icon_metadata = { 'size': len(icon_content), 'hash': crc32(icon_content), 'filename': icon_filename, 'content_type': 'image/png' } cat.icon = icon_content
def submit_attachment(task, attachment): """Sends an attachment's file to the conversion service""" from indico_conversion.plugin import ConversionPlugin if ConversionPlugin.settings.get('maintenance'): task.retry(countdown=900) url = ConversionPlugin.settings.get('server_url') payload = { 'attachment_id': attachment.id } data = { 'converter': 'pdf', 'urlresponse': url_for_plugin('conversion.callback', _external=True), 'dirresponse': secure_serializer.dumps(payload, salt='pdf-conversion') } file = attachment.file name, ext = os.path.splitext(file.filename) # we know ext is safe since it's based on a whitelist. the name part may be fully # non-ascii so we sanitize that to a generic name if necessary filename = secure_filename(name, 'attachment') + ext with file.open() as fd: try: response = requests.post(url, data=data, files={'uploadedfile': (filename, fd, file.content_type)}) response.raise_for_status() if 'ok' not in response.text: raise requests.RequestException(f'Unexpected response from server: {response.text}') except requests.RequestException as exc: attempt = task.request.retries + 1 try: delay = DELAYS[task.request.retries] if not config.DEBUG else 1 except IndexError: # like this we can safely bump MAX_TRIES manually if necessary delay = DELAYS[-1] try: task.retry(countdown=delay, max_retries=(MAX_TRIES - 1)) except MaxRetriesExceededError: ConversionPlugin.logger.error('Could not submit attachment %d (attempt %d/%d); giving up [%s]', attachment.id, attempt, MAX_TRIES, exc) pdf_state_cache.delete(str(attachment.id)) except Retry: ConversionPlugin.logger.warning('Could not submit attachment %d (attempt %d/%d); retry in %ds [%s]', attachment.id, attempt, MAX_TRIES, delay, exc) raise else: ConversionPlugin.logger.info('Submitted %r', attachment)
def _process(self): defaults = FormDefaults(self.attachment, protected=self.attachment.is_protected, skip_attrs={'file'}) if self.attachment.type == AttachmentType.file: file_ = self.attachment.file # file_attrs has to be manually "serialized", since it's going to be converted to JSON file_attrs = { 'url': url_for('attachments.download', self.attachment, filename=self.attachment.file.filename, from_preview='1'), 'filename': file_.filename, 'size': file_.size, 'content_type': file_.content_type } form = EditAttachmentFileForm(linked_object=self.object, obj=defaults, file=file_attrs) else: form = EditAttachmentLinkForm(linked_object=self.object, obj=defaults) if form.validate_on_submit(): folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object) logger.info('Attachment {} edited by {}'.format(self.attachment, session.user)) form.populate_obj(self.attachment, skip={'acl', 'file'}) self.attachment.folder = folder if self.attachment.is_protected: # can't use `=` because of https://bitbucket.org/zzzeek/sqlalchemy/issues/3583 self.attachment.acl |= form.acl.data self.attachment.acl &= form.acl.data # files need special handling; links are already updated in `populate_obj` if self.attachment.type == AttachmentType.file: file = request.files['file'] if request.files else None if file: self.attachment.file = AttachmentFile(user=session.user, content_type=file.mimetype, filename=secure_filename(file.filename, 'attachment')) self.attachment.file.save(file.file) signals.attachments.attachment_updated.send(self.attachment, user=session.user) flash(_("The attachment \"{name}\" has been updated").format(name=self.attachment.title), 'success') return jsonify_data(attachment_list=_render_attachment_list(self.object)) template = ('attachments/upload.html' if self.attachment.type == AttachmentType.file else 'attachments/add_link.html') return jsonify_template(template, form=form, existing_attachment=self.attachment, action=url_for('.modify_attachment', self.attachment), protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def _process(self): f = request.files['file'] filename = secure_filename(f.filename, 'image') data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except IOError: # Invalid image data return jsonify(error="Invalid image data!") data.seek(0) if image_type not in {'jpeg', 'gif', 'png'}: return jsonify(error="File format not accepted!") content_type = 'image/' + image_type image = DesignerImageFile(template=self.template, filename=filename, content_type=content_type) self.template.background_image = image image.save(data) flash(_("The image has been uploaded"), 'success') return jsonify_data(image_url=image.download_url)
def _process(self): f = request.files['file'] filename = secure_filename(f.filename, 'image') data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except OSError: # Invalid image data return jsonify(error="Invalid image data!") data.seek(0) if image_type not in {'jpeg', 'gif', 'png'}: return jsonify(error="File format not accepted!") content_type = 'image/' + image_type image = DesignerImageFile(template=self.template, filename=filename, content_type=content_type) self.template.background_image = image image.save(data) flash(_("The image has been uploaded"), 'success') return jsonify_data(image_url=image.download_url)
def _process_logo(self, logo, event): path = get_archived_file(logo, self.archive_dirs)[1] if path is None: self.print_error( cformat('%{red!}Logo not found on disk; skipping it'), event_id=event.id) return try: logo_image = Image.open(path) except IOError as e: self.print_warning("Cannot open {}: {}".format(path, e), event_id=event.id) return if logo_image.mode == 'CMYK': self.print_warning("Logo is a CMYK {}; converting to RGB".format( logo_image.format), event_id=event.id) # this may result in wrong colors, but there's not much we can do... logo_image = logo_image.convert('RGB') logo_bytes = BytesIO() logo_image.save(logo_bytes, 'PNG') logo_bytes.seek(0) logo_content = logo_bytes.read() logo_filename = secure_filename(convert_to_unicode(logo.fileName), 'logo') logo_filename = os.path.splitext(logo_filename)[0] + '.png' event.logo_metadata = { 'size': len(logo_content), 'hash': crc32(logo_content), 'filename': logo_filename, 'content_type': 'image/png' } event.logo = logo_content if not self.quiet: self.print_success(cformat('- %{cyan}[Logo] {}').format( logo.fileName), event_id=event.id)
def migrate_event_images(self): self.print_step('migrating event images') for event, picture in committing_iterator(self._iter_pictures()): local_file = picture._localFile content_type = mimetypes.guess_type( local_file.fileName)[0] or 'application/octet-stream' storage_backend, storage_path, size = self._get_local_file_info( local_file) if storage_path is None: self.print_warning(cformat( '%{yellow}[{}]%{reset} -> %{red!}Not found in filesystem'). format(local_file.id), event_id=event.id) continue filename = secure_filename(convert_to_unicode(local_file.fileName), 'image') image = ImageFile(event_id=event.id, filename=filename, content_type=content_type, created_dt=now_utc(), size=size, storage_backend=storage_backend, storage_file_id=storage_path) db.session.add(image) db.session.flush() map_entry = LegacyImageMapping(event_id=event.id, legacy_image_id=local_file.id, image_id=image.id) db.session.add(map_entry) if not self.quiet: self.print_success( cformat('%{cyan}[{}]%{reset} -> %{blue!}{}').format( local_file.id, image), event_id=event.id)
def _attachment_from_resource(self, folder, material, resource, base_object=None): modified_dt = (getattr(material, '_modificationDS', None) or getattr(base_object, 'startDate', None) or getattr(base_object, '_modificationDS', None) or now_utc()) data = {'id': self._get_id(Attachment), 'folder_id': folder['id'], 'user_id': self.janitor_user_id, 'title': convert_to_unicode(resource.name).strip() or folder['title'], 'description': convert_to_unicode(resource.description), 'modified_dt': modified_dt} if resource.__class__.__name__ == 'Link': data['type'] = AttachmentType.link data['link_url'] = convert_to_unicode(resource.url).strip() if not data['link_url']: self.print_error(cformat('%{red!}[{}] Skipping link, missing URL').format(data['title']), event_id=base_object.id) return None else: data['type'] = AttachmentType.file storage_backend, storage_path, size = self._get_local_file_info(resource) if storage_path is None: self.print_error(cformat('%{red!}File {} not found on disk').format(resource._LocalFile__archivedId), event_id=base_object.id) return None filename = secure_filename(convert_to_unicode(resource.fileName), 'attachment') file_data = {'id': self._get_id(AttachmentFile), 'attachment_id': data['id'], 'user_id': self.janitor_user_id, 'created_dt': modified_dt, 'filename': filename, 'content_type': mimetypes.guess_type(filename)[0] or 'application/octet-stream', 'size': size, 'storage_backend': storage_backend, 'storage_file_id': storage_path} self.todo[AttachmentFile].append(file_data) tmp = ProtectionTarget() protection_from_ac(tmp, resource._Resource__ac) self.todo[AttachmentPrincipal] += tmp.make_principal_rows(attachment_id=data['id']) data['protection_mode'] = tmp.protection_mode self.todo[Attachment].append(data) return data
def _process(self): form = AddAttachmentFilesForm(linked_object=self.object) if form.validate_on_submit(): files = form.files.data folder = form.folder.data or AttachmentFolder.get_or_create_default( linked_object=self.object) for f in files: filename = secure_filename(f.filename, 'attachment') attachment = Attachment( folder=folder, user=session.user, title=to_unicode(f.filename), type=AttachmentType.file, protection_mode=form.protection_mode.data) if attachment.is_self_protected: attachment.acl = form.acl.data content_type = mimetypes.guess_type( f.filename)[0] or f.mimetype or 'application/octet-stream' attachment.file = AttachmentFile(user=session.user, filename=filename, content_type=content_type) attachment.file.save(f.file) db.session.add(attachment) db.session.flush() logger.info('Attachment %s uploaded by %s', attachment, session.user) signals.attachments.attachment_created.send(attachment, user=session.user) flash( ngettext("The attachment has been uploaded", "{count} attachments have been uploaded", len(files)).format(count=len(files)), 'success') return jsonify_data( attachment_list=_render_attachment_list(self.object)) return jsonify_template( 'attachments/upload.html', form=form, action=url_for('.upload', self.object), protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def _process_POST(self): f = request.files[self.IMAGE_TYPE] try: img = Image.open(f) except IOError: flash(_('You cannot upload this file as an icon/logo.'), 'error') return jsonify_data(content=None) if img.format.lower() not in {'jpeg', 'png', 'gif'}: flash( _('The file has an invalid format ({format})').format( format=img.format), 'error') return jsonify_data(content=None) if img.mode == 'CMYK': flash( _('The image you uploaded is using the CMYK colorspace and has been converted to RGB. ' 'Please check if the colors are correct and convert it manually if necessary.' ), 'warning') img = img.convert('RGB') img = self._resize(img) image_bytes = BytesIO() img.save(image_bytes, 'PNG') image_bytes.seek(0) content = image_bytes.read() metadata = { 'hash': crc32(content), 'size': len(content), 'filename': os.path.splitext(secure_filename(f.filename, self.IMAGE_TYPE))[0] + '.png', 'content_type': 'image/png' } self._set_image(content, metadata) flash(self.SAVED_FLASH_MSG, 'success') logger.info("New {} '%s' uploaded by %s (%s)".format(self.IMAGE_TYPE), f.filename, session.user, self.category) return jsonify_data( content=get_image_data(self.IMAGE_TYPE, self.category))
def _process(self): files = request.files.getlist('image') num = 0 for f in files: filename = secure_filename(f.filename, 'image') data = BytesIO() shutil.copyfileobj(f, data) data.seek(0) try: image_type = Image.open(data).format.lower() except IOError: # Invalid image data continue data.seek(0) # XXX: mpo is basically JPEG and JPEGs from some cameras are (wrongfully) detected as mpo if image_type == 'mpo': image_type = 'jpeg' elif image_type not in {'jpeg', 'gif', 'png'}: flash( _("The image '{name}' has an invalid type ({type}); only JPG, GIF and PNG are allowed." ).format(name=f.filename, type=image_type), 'error') continue content_type = 'image/' + image_type image = ImageFile(event=self.event, filename=filename, content_type=content_type) image.save(data) num += 1 db.session.flush() logger.info('Image %s uploaded by %s', image, session.user) signals.event_management.image_created.send(image, user=session.user) flash( ngettext("The image has been uploaded", "{count} images have been uploaded", num).format(count=len(files)), 'success') if (self._dlg): return jsonify_data(image_list=_render_image_list_dlg(self.event)) return jsonify_data(image_list=_render_image_list(self.event))
def _create_material(self, logs): folder = AttachmentFolder.find_first(object=self.event, is_default=False, title='Chat Logs', is_deleted=False) if folder is None: folder = AttachmentFolder(protection_mode=ProtectionMode.protected, linked_object=self.event, title='Chat Logs', description='Chat logs for this event') db.session.add(folder) filename = '{}.html'.format(secure_filename(self.material_name, 'logs')) attachment = Attachment( folder=folder, user=session.user, title=self.material_name, type=AttachmentType.file, description="Chat logs for the chat room '{}'".format( self.chatroom.name)) attachment.file = AttachmentFile(user=session.user, filename=filename, content_type='text/html') attachment.file.save(logs.encode('utf-8')) db.session.flush() signals.attachments.attachment_created.send(attachment, user=session.user) log_data = [ ('Range', 'Everything' if not self.date_filter else '{} - {}'.format( format_date(self.start_date), format_date(self.end_date))), ] self.event.log(EventLogRealm.management, EventLogKind.positive, 'Chat', 'Created material: {}'.format(filename), session.user, data=log_data)
def build_storage_path( self, obj, _new_path_re=re.compile( r'^(event/\d+/registrations/\d+/\d+/\d+-)(\d+)(-.*)$')): old_filename = obj.filename new_filename = secure_filename(obj.filename, None) assert new_filename obj.filename = new_filename new_storage_path = obj._build_storage_path()[1] obj.filename = old_filename assert new_storage_path if not isinstance(obj, RegistrationData): return new_storage_path, new_filename match = _new_path_re.match(obj.storage_file_id) if match: # already in the current format assert obj.storage_file_id == new_storage_path.replace( '-0-', '-{}-'.format(match.group(2))) return obj.storage_file_id, new_filename else: match = _new_path_re.match(new_storage_path) return '{}{}{}'.format(match.group(1), crc32(obj.storage_file_id), match.group(3)), new_filename
def _migrate_templates(self): for __, old_tpl in self.pr._templates.viewitems(): old_filename = convert_to_unicode(old_tpl._Template__file.name) storage_backend, storage_path, size = self._get_local_file_info( old_tpl._Template__file) if storage_path is None: self.print_error( '%[red!]File not found on disk; skipping it [{}]'.format( old_filename)) continue filename = secure_filename(old_filename, 'attachment') content_type = mimetypes.guess_type( old_filename)[0] or 'application/octet-stream' tpl = PaperTemplate( filename=filename, content_type=content_type, size=size, storage_backend=storage_backend, storage_file_id=storage_path, name=convert_to_unicode(old_tpl._Template__name) or old_filename, description=convert_to_unicode(old_tpl._Template__description)) self.event.paper_templates.append(tpl)
def build_storage_path(self, obj, _new_path_re=re.compile(r'^(event/\d+/registrations/\d+/\d+/\d+-)(\d+)(-.*)$')): if isinstance(obj, File): # ``File``` was added in 2.3 and thus always has the correct paths # we cannot re-generate the storage path for it since it uses # a __context attribute which is only present during the initial # `save()` call and not stored anywhere. return obj.storage_file_id, obj.filename old_filename = obj.filename new_filename = secure_filename(obj.filename, None) assert new_filename obj.filename = new_filename new_storage_path = obj._build_storage_path()[1] obj.filename = old_filename assert new_storage_path if not isinstance(obj, RegistrationData): return new_storage_path, new_filename match = _new_path_re.match(obj.storage_file_id) if match: # already in the current format assert obj.storage_file_id == new_storage_path.replace('-0-', f'-{match.group(2)}-') return obj.storage_file_id, new_filename else: match = _new_path_re.match(new_storage_path) return f'{match.group(1)}{crc32(obj.storage_file_id)}{match.group(3)}', new_filename
def locator(self): return dict(self.revision.locator, file_id=self.file_id, filename=secure_filename(self.file.filename, f'file-{self.file_id}'))
def _prepare_folder_structure(self, item): file_name = secure_filename( '{}_{}'.format(unicode(item.id), item.filename), item.filename) return os.path.join(*self._adjust_path_length([file_name]))
def _process(self): filename = '{}-category.ics'.format(secure_filename(self.category.title, str(self.category.id))) buf = serialize_categories_ical([self.category.id], session.user, Event.end_dt >= (now_utc() - timedelta(weeks=4))) return send_file(filename, buf, 'text/calendar')
def _process(self): filename = secure_filename('{}-Ticket.pdf'.format(self.event.title), 'ticket.pdf') return send_file(filename, generate_ticket(self.registration), 'application/pdf')
def _prepare_folder_structure(self, item): abstract_title = secure_filename('{}_{}'.format(unicode(item.abstract.friendly_id), item.abstract.title), 'abstract') file_name = secure_filename('{}_{}'.format(unicode(item.id), item.filename), item.filename) return os.path.join(*self._adjust_path_length([abstract_title, file_name]))