def clone(self, new_event, options): if 'attachments' not in options: return folder_mapping = {} attrs = get_simple_column_attrs(AttachmentFolder) for old_folder in self.find_folders(): new_folder = AttachmentFolder(event_id=new_event.id, **{attr: getattr(old_folder, attr) for attr in attrs}) if new_folder.linked_object is None: continue new_folder.acl = old_folder.acl db.session.add(new_folder) folder_mapping[old_folder] = new_folder attrs = get_simple_column_attrs(Attachment) - {'modified_dt'} for old_attachment in self.find_attachments(): folder = folder_mapping.get(old_attachment.folder) if not folder: continue new_attachment = Attachment(folder=folder, user_id=old_attachment.user_id, acl=old_attachment.acl, **{attr: getattr(old_attachment, attr) for attr in attrs}) if new_attachment.type == AttachmentType.file: old_file = old_attachment.file new_attachment.file = AttachmentFile( attachment=new_attachment, user_id=old_file.user_id, filename=old_file.filename, content_type=old_file.content_type ) with old_file.open() as fd: new_attachment.file.save(fd) db.session.add(new_attachment) db.session.flush()
def _merge_users(target, source, **kwargs): from indico.modules.attachments.models.attachments import Attachment, AttachmentFile from indico.modules.attachments.models.principals import AttachmentPrincipal, AttachmentFolderPrincipal Attachment.find(user_id=source.id).update({Attachment.user_id: target.id}) AttachmentFile.find(user_id=source.id).update({AttachmentFile.user_id: target.id}) AttachmentPrincipal.merge_users(target, source, 'attachment') AttachmentFolderPrincipal.merge_users(target, source, 'folder')
def _process(self): from indico_conversion.plugin import ConversionPlugin try: payload = secure_serializer.loads(request.form['directory'], salt='pdf-conversion') except BadData: ConversionPlugin.logger.exception('Received invalid payload (%s)', request.form['directory']) return jsonify(success=False) attachment = Attachment.get(payload['attachment_id']) if not attachment or attachment.is_deleted or attachment.folder.is_deleted: ConversionPlugin.logger.info('Attachment has been deleted: %s', attachment) return jsonify(success=True) elif request.form['status'] != '1': ConversionPlugin.logger.error('Received invalid status %s for %s', request.form['status'], attachment) return jsonify(success=False) name, ext = os.path.splitext(attachment.file.filename) title = get_pdf_title(attachment) pdf_attachment = Attachment(folder=attachment.folder, user=attachment.user, title=title, description=attachment.description, type=AttachmentType.file, protection_mode=attachment.protection_mode, acl=attachment.acl) data = request.files['content'].stream.read() pdf_attachment.file = AttachmentFile(user=attachment.file.user, filename=f'{name}.pdf', content_type='application/pdf') pdf_attachment.file.save(data) db.session.add(pdf_attachment) db.session.flush() pdf_state_cache.set(str(attachment.id), 'finished', timeout=timedelta(minutes=15)) ConversionPlugin.logger.info('Added PDF attachment %s for %s', pdf_attachment, attachment) signals.attachments.attachment_created.send(pdf_attachment, user=None) return jsonify(success=True)
def _process(self): from indico_conversion.plugin import ConversionPlugin try: payload = secure_serializer.loads(request.form['directory'], salt='pdf-conversion') except BadData: ConversionPlugin.logger.exception('Received invalid payload (%s)', request.form['directory']) return jsonify(success=False) attachment = Attachment.get(payload['attachment_id']) if not attachment or attachment.is_deleted or attachment.folder.is_deleted: ConversionPlugin.logger.info('Attachment has been deleted: %s', attachment) return jsonify(success=True) elif request.form['status'] != '1': ConversionPlugin.logger.error('Received invalid status %s for %s', request.form['status'], attachment) return jsonify(success=False) name, ext = os.path.splitext(attachment.file.filename) title = get_pdf_title(attachment) pdf_attachment = Attachment(folder=attachment.folder, user=attachment.user, title=title, description=attachment.description, type=AttachmentType.file, protection_mode=attachment.protection_mode, acl=attachment.acl) # TODO: remove first case when Conversion Server is fully on new version if 'content' in request.form: # handling of legacy API data = BytesIO(base64.decodestring(request.form['content'])) else: filepdf = request.files['content'] data = filepdf.stream.read() pdf_attachment.file = AttachmentFile(user=attachment.file.user, filename='{}.pdf'.format(name), content_type='application/pdf') pdf_attachment.file.save(data) db.session.add(pdf_attachment) db.session.flush() cache.set(unicode(attachment.id), 'finished', timedelta(minutes=15)) ConversionPlugin.logger.info('Added PDF attachment %s for %s', pdf_attachment, attachment) signals.attachments.attachment_created.send(pdf_attachment, user=None) return jsonify(success=True)
def create_contribution_from_abstract(abstract, contrib_session=None): from indico.modules.events.abstracts.settings import abstracts_settings event = abstract.event contrib_person_links = set() author_submission_rights = ( event.cfa.contribution_submitters == SubmissionRightsType.all) person_link_attrs = { '_title', 'address', 'affiliation', 'first_name', 'last_name', 'phone', 'author_type', 'is_speaker', 'display_order' } for abstract_person_link in abstract.person_links: link = ContributionPersonLink(person=abstract_person_link.person) link.populate_from_attrs(abstract_person_link, person_link_attrs) contrib_person_links.add(link) if contrib_session: duration = contrib_session.default_contribution_duration else: duration = contribution_settings.get(event, 'default_duration') custom_fields_data = { f'custom_{field_value.contribution_field.id}': field_value.data for field_value in abstract.field_values } contrib = create_contribution(event, { 'friendly_id': abstract.friendly_id, 'title': abstract.title, 'duration': duration, 'description': abstract.description, 'type': abstract.accepted_contrib_type, 'track': abstract.accepted_track, 'session': contrib_session, 'person_link_data': { link: (author_submission_rights or link.is_speaker) for link in contrib_person_links } }, custom_fields_data=custom_fields_data) if abstracts_settings.get(event, 'copy_attachments') and abstract.files: folder = AttachmentFolder.get_or_create_default(contrib) for abstract_file in abstract.files: attachment = Attachment(user=abstract.submitter, type=AttachmentType.file, folder=folder, title=abstract_file.filename) attachment.file = AttachmentFile( user=abstract.submitter, filename=abstract_file.filename, content_type=abstract_file.content_type) with abstract_file.open() as fd: attachment.file.save(fd) db.session.flush() return contrib
def add_attachment_link(data, linked_object): """Add a link attachment to linked_object""" folder = data.pop('folder', None) if not folder: folder = AttachmentFolder.get_or_create_default(linked_object=linked_object) assert folder.object == linked_object link = Attachment(user=session.user, type=AttachmentType.link, folder=folder) link.populate_from_dict(data, skip={'acl', 'protected'}) if link.is_self_protected: link.acl = data['acl'] db.session.flush() logger.info('Attachment %s added by %s', link, session.user) signals.attachments.attachment_created.send(link, user=session.user)
def add_attachment_link(data, linked_object): """Add a link attachment to linked_object.""" folder = data.pop('folder', None) if not folder: folder = AttachmentFolder.get_or_create_default(linked_object=linked_object) assert folder.object == linked_object link = Attachment(user=session.user, type=AttachmentType.link, folder=folder) link.populate_from_dict(data, skip={'acl', 'protected'}) if link.is_self_protected: link.acl = data['acl'] db.session.flush() logger.info('Attachment %s added by %s', link, session.user) signals.attachments.attachment_created.send(link, user=session.user)
def _clone_attachment_folder(self, old_folder, new_object): folder_attrs = get_simple_column_attrs(AttachmentFolder) | {'acl'} attachment_attrs = (get_simple_column_attrs(Attachment) | {'user', 'acl'}) - {'modified_dt'} folder = AttachmentFolder(object=new_object) folder.populate_from_attrs(old_folder, folder_attrs) for old_attachment in old_folder.attachments: attachment = Attachment(folder=folder) attachment.populate_from_attrs(old_attachment, attachment_attrs) if attachment.type == AttachmentType.file: old_file = old_attachment.file attachment.file = AttachmentFile(attachment=attachment, user=old_file.user, filename=old_file.filename, content_type=old_file.content_type) with old_file.open() as fd: attachment.file.save(fd)
def clone(self, new_event, options): if 'attachments' not in options: return folder_mapping = {} for old_folder in self.find_folders(): new_folder = AttachmentFolder( title=old_folder.title, description=old_folder.description, is_default=old_folder.is_default, is_always_visible=old_folder.is_always_visible, protection_mode=old_folder.protection_mode, link_type=old_folder.link_type, event_id=new_event.id, session_id=old_folder.session_id, contribution_id=old_folder.contribution_id, subcontribution_id=old_folder.subcontribution_id ) if new_folder.linked_object is None: continue new_folder.acl = old_folder.acl db.session.add(new_folder) folder_mapping[old_folder] = new_folder for old_attachment in self.find_attachments(): folder = folder_mapping.get(old_attachment.folder) if not folder: continue new_attachment = Attachment( folder=folder, user_id=old_attachment.user_id, title=old_attachment.title, description=old_attachment.description, type=old_attachment.type, link_url=old_attachment.link_url, protection_mode=old_attachment.protection_mode, acl=old_attachment.acl ) if new_attachment.type == AttachmentType.file: old_file = old_attachment.file new_attachment.file = AttachmentFile( attachment=new_attachment, user_id=old_file.user_id, filename=old_file.filename, content_type=old_file.content_type ) with old_file.open() as fd: new_attachment.file.save(fd) db.session.add(new_attachment) db.session.flush()
def _build_base_query(self, added_since=None): query = Attachment.find(Attachment.type == AttachmentType.file, ~AttachmentFolder.is_deleted, ~Attachment.is_deleted, AttachmentFolder.event == self.event, _join=AttachmentFolder) if added_since is not None: query = query.join(Attachment.file).filter(cast(AttachmentFile.created_dt, Date) >= added_since) return query
def _build_base_query(self, added_since=None): query = Attachment.find(Attachment.type == AttachmentType.file, ~AttachmentFolder.is_deleted, ~Attachment.is_deleted, AttachmentFolder.event_new == self.event_new, _join=AttachmentFolder) if added_since is not None: query = query.join(Attachment.file).filter(cast(AttachmentFile.created_dt, Date) >= added_since) return query
def create_link(indico_id, cds_id, user): from indico_audiovisual.plugin import AVRequestsPlugin obj = parse_indico_id(indico_id) if obj is None: return False url = AVRequestsPlugin.settings.get('recording_cds_url') if not url: return False url = url.format(cds_id=cds_id) if cds_link_exists(obj, url): return True folder = AttachmentFolder.get_or_create_default(obj) attachment = Attachment(folder=folder, user=user, title='Recording', type=AttachmentType.link, link_url=url) db.session.add(attachment) db.session.flush() signals.attachments.attachment_created.send(attachment, user=user) return True
def _getParams(self): super()._getParams() self._attachment = Attachment.get(int(self._pathParams['res'])) if not self._attachment: raise HTTPAPIError("File not found", 404)
def _clone_attachment_folder(self, old_folder, new_object): folder_attrs = get_simple_column_attrs(AttachmentFolder) attachment_attrs = (get_simple_column_attrs(Attachment) | {'user'}) - {'modified_dt'} folder = AttachmentFolder(object=new_object) folder.populate_from_attrs(old_folder, folder_attrs) folder.acl_entries = clone_principals(AttachmentFolderPrincipal, old_folder.acl_entries, self._event_role_map, self._regform_map) for old_attachment in old_folder.attachments: self._attachment_map[old_attachment] = attachment = Attachment( folder=folder) attachment.populate_from_attrs(old_attachment, attachment_attrs) attachment.acl_entries = clone_principals( AttachmentPrincipal, old_attachment.acl_entries, self._event_role_map, self._regform_map) if attachment.type == AttachmentType.file: old_file = old_attachment.file attachment.file = AttachmentFile( attachment=attachment, user=old_file.user, filename=old_file.filename, content_type=old_file.content_type) with old_file.open() as fd: attachment.file.save(fd) return folder
def _getParams(self): super(FileHook, self)._getParams() self._attachment = Attachment.get(int(self._pathParams['res'])) if not self._attachment: raise HTTPAPIError("File not found", 404)
def cds_link_exists(obj, url): query = (Attachment.find(~Attachment.is_deleted, ~AttachmentFolder.is_deleted, AttachmentFolder.object == obj, Attachment.type == AttachmentType.link, Attachment.link_url == url, _join=AttachmentFolder).options(noload('*'))) return db.session.query(query.exists()).scalar()
def _process(self): form = AddAttachmentLinkForm(linked_object=self.object) if form.validate_on_submit(): folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object) link = Attachment(user=session.user, type=AttachmentType.link) form.populate_obj(link, skip={'acl'}) if link.is_protected: link.acl = form.acl.data link.folder = folder db.session.flush() logger.info('Attachment {} added by {}'.format(link, session.user)) signals.attachments.attachment_created.send(link, user=session.user) flash(_("The link has been added"), 'success') return jsonify_data(attachment_list=_render_attachment_list(self.object)) return jsonify_template('attachments/add_link.html', form=form, protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def test_acls(dummy_event, dummy_contribution, dummy_user, create_user, obj_type): from .schemas import ACLSchema class TestSchema(ACLSchema, mm.Schema): pass if obj_type == 'event': obj = dummy_event elif obj_type == 'contrib': obj = dummy_contribution elif obj_type == 'subcontrib': obj = SubContribution(contribution=dummy_contribution, title='Test', duration=timedelta(minutes=10)) elif obj_type == 'attachment': folder = AttachmentFolder(title='Dummy Folder', description='a dummy folder') obj = Attachment(folder=folder, user=dummy_user, title='Dummy Attachment', type=AttachmentType.link, link_url='https://example.com') obj.folder.object = dummy_event elif obj_type == 'note': obj = EventNote(object=dummy_event) obj.create_revision(RenderMode.html, 'this is a dummy note', dummy_user) def assert_acl(expected_read_acl): __tracebackhide__ = True data = schema.dump(obj) read_acl = data['_access'].pop('read', None) assert data == { '_access': { 'delete': ['IndicoAdmin'], 'owner': ['IndicoAdmin'], 'update': ['IndicoAdmin'] } } if read_acl is not None: read_acl = set(read_acl) assert read_acl == expected_read_acl schema = TestSchema() user = create_user(1, email='*****@*****.**') # everything is public assert_acl(None) # event is protected and the acl is empty (nobody has regular access) dummy_event.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin'}) # user on the acl has access dummy_event.update_principal(user, read_access=True) assert_acl({'IndicoAdmin', 'User:1'})
def materialToXMLMarc21(self, obj, out=None): if not out: out = self._XMLGen for attachment in (Attachment.find(~AttachmentFolder.is_deleted, AttachmentFolder.object == obj, is_deleted=False, _join=AttachmentFolder) .options(joinedload(Attachment.legacy_mapping))): if attachment.can_access(self.__aw.getUser().user): self.resourceToXMLMarc21(attachment, out) self._generateAccessList(acl=self._attachment_access_list(attachment), out=out, objId=self._attachment_unique_id(attachment, add_prefix=False))
def dummy_attachment(dummy_user): folder = AttachmentFolder(title='dummy_folder', description='a dummy folder') file_ = AttachmentFile(user=dummy_user, filename='dummy_file.txt', content_type='text/plain') return Attachment(folder=folder, user=dummy_user, title='dummy_attachment', type=AttachmentType.file, file=file_)
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_client_filename(f.filename) attachment = Attachment( folder=folder, user=session.user, title=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.stream) 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), existing_attachment=None)
def _create_material(self, logs): folder = AttachmentFolder.find_first(object=self.event_new, is_default=False, title='Chat Logs', is_deleted=False) if folder is None: folder = AttachmentFolder(protection_mode=ProtectionMode.protected, linked_object=self.event_new, 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 _process(self): ids = request.args.getlist('a') results = {int(id_): cache.get(id_) for id_ in ids} finished = [id_ for id_, status in results.iteritems() if status == 'finished'] pending = [id_ for id_, status in results.iteritems() if status == 'pending'] containers = {} if finished: tpl = get_template_module('attachments/_display.html') for attachment in Attachment.find(Attachment.id.in_(finished)): if not attachment.folder.can_view(session.user): continue containers[attachment.id] = tpl.render_attachments_folders(item=attachment.folder.object) return jsonify(finished=finished, pending=pending, containers=containers)
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 create_contribution_from_abstract(abstract, contrib_session=None): from indico.modules.events.abstracts.settings import abstracts_settings event = abstract.event contrib_person_links = set() person_link_attrs = {'_title', 'address', 'affiliation', 'first_name', 'last_name', 'phone', 'author_type', 'is_speaker', 'display_order'} for abstract_person_link in abstract.person_links: link = ContributionPersonLink(person=abstract_person_link.person) link.populate_from_attrs(abstract_person_link, person_link_attrs) contrib_person_links.add(link) if contrib_session: duration = contrib_session.default_contribution_duration else: duration = contribution_settings.get(event, 'default_duration') custom_fields_data = {'custom_{}'.format(field_value.contribution_field.id): field_value.data for field_value in abstract.field_values} contrib = create_contribution(event, {'friendly_id': abstract.friendly_id, 'title': abstract.title, 'duration': duration, 'description': abstract.description, 'type': abstract.accepted_contrib_type, 'track': abstract.accepted_track, 'session': contrib_session, 'person_link_data': {link: True for link in contrib_person_links}}, custom_fields_data=custom_fields_data) if abstracts_settings.get(event, 'copy_attachments') and abstract.files: folder = AttachmentFolder.get_or_create_default(contrib) for abstract_file in abstract.files: attachment = Attachment(user=abstract.submitter, type=AttachmentType.file, folder=folder, title=abstract_file.filename) attachment.file = AttachmentFile(user=abstract.submitter, filename=abstract_file.filename, content_type=abstract_file.content_type) with abstract_file.open() as fd: attachment.file.save(fd) db.session.flush() return contrib
def _process(self): form = AddAttachmentLinkForm(linked_object=self.object) if form.validate_on_submit(): folder = form.folder.data or AttachmentFolder.get_or_create_default( linked_object=self.object) link = Attachment(user=session.user, type=AttachmentType.link) form.populate_obj(link, skip={'acl'}) if link.is_protected: link.acl = form.acl.data link.folder = folder db.session.flush() logger.info('Attachment {} added by {}'.format(link, session.user)) signals.attachments.attachment_created.send(link, user=session.user) flash(_("The link has been added"), 'success') return jsonify_data( attachment_list=_render_attachment_list(self.object)) return jsonify_template( 'attachments/add_link.html', form=form, protection_message=_render_protection_message(self.object), folders_protection_info=_get_folders_protection_info(self.object))
def _make_attachment(user, obj): folder = AttachmentFolder(title='dummy_folder', description='a dummy folder') file = AttachmentFile(user=user, filename='dummy_file.txt', content_type='text/plain') attachment = Attachment(folder=folder, user=user, title='dummy_attachment', type=AttachmentType.file, file=file) attachment.folder.object = obj attachment.file.save(BytesIO(b'hello world')) return attachment
def _process(self): form = AddAttachmentFilesForm(linked_object=self.object) if form.validate_on_submit(): files = request.files.getlist('file') 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(self): params = self._getRequestParams() if params["title"] == "": params["title"] = "No Title" # change number of dates (lecture) if self._confirm == True: if self._event_type != "simple_event": c = self._createEvent(self._params) self.alertCreation([c]) # lectures else: lectures = [] for i in range(1, int(self._params["nbDates"]) + 1): self._params["sDay"] = self._params.get("sDay_%s" % i, "") self._params["sMonth"] = self._params.get( "sMonth_%s" % i, "") self._params["sYear"] = self._params.get( "sYear_%s" % i, "") self._params["sHour"] = self._params.get( "sHour_%s" % i, "") self._params["sMinute"] = self._params.get( "sMinute_%s" % i, "") self._params["duration"] = int( self._params.get("dur_%s" % i, 60)) lectures.append(self._createEvent(self._params)) self.alertCreation(lectures) lectures.sort(sortByStartDate) # create links for i, source in enumerate(lectures, 1): if len(lectures) > 1: source.setTitle("{} ({}/{})".format( source.getTitle(), i, len(lectures))) for j, target in enumerate(lectures, 1): if j != i: folder = AttachmentFolder(linked_object=source, title="part{}".format(j)) link = Attachment(user=session.user, type=AttachmentType.link, folder=folder, title="Part {}".format(j), link_url=target.getURL()) db.session.add(link) c = lectures[0] self._redirect(urlHandlers.UHConferenceModification.getURL(c)) else: url = urlHandlers.UHCategoryDisplay.getURL(self._target) self._redirect(url)
def obj_deref(ref): """Return the object identified by `ref`.""" from indico_livesync.models.queue import EntryType if ref['type'] == EntryType.category: return Category.get_or_404(ref['category_id']) elif ref['type'] == EntryType.event: return Event.get_or_404(ref['event_id']) elif ref['type'] == EntryType.session: return Session.get_or_404(ref['session_id']) elif ref['type'] == EntryType.contribution: return Contribution.get_or_404(ref['contrib_id']) elif ref['type'] == EntryType.subcontribution: return SubContribution.get_or_404(ref['subcontrib_id']) elif ref['type'] == EntryType.note: return EventNote.get_or_404(ref['note_id']) elif ref['type'] == EntryType.attachment: return Attachment.get_or_404(ref['attachment_id']) else: raise ValueError('Unexpected object type: {}'.format(ref['type']))
def test_dump_attachment(db, dummy_user, dummy_contribution): from indico.modules.search.schemas import AttachmentSchema folder = AttachmentFolder(title='Dummy Folder', description='a dummy folder') file = AttachmentFile(user=dummy_user, filename='dummy_file.txt', content_type='text/plain') attachment = Attachment(folder=folder, user=dummy_user, title='Dummy Attachment', type=AttachmentType.file, file=file) attachment.folder.object = dummy_contribution attachment.file.save(BytesIO(b'hello world')) db.session.flush() category_id = dummy_contribution.event.category_id schema = AttachmentSchema() assert schema.dump(attachment) == { 'filename': 'dummy_file.txt', 'title': 'Dummy Attachment', 'user': { 'affiliation': None, 'name': 'Guinea Pig' }, 'attachment_id': attachment.id, 'attachment_type': 'file', 'category_id': category_id, 'category_path': [ { 'id': 0, 'title': 'Home', 'url': '/' }, { 'id': category_id, 'title': 'dummy', 'url': f'/category/{category_id}/' }, ], 'contribution_id': dummy_contribution.id, 'subcontribution_id': None, 'event_id': 0, 'folder_id': folder.id, 'modified_dt': attachment.modified_dt.isoformat(), 'type': 'attachment', 'url': (f'/event/0/contributions/' f'{dummy_contribution.id}/attachments/{folder.id}/{attachment.id}/dummy_file.txt' ), }
def _count_attachments(cls, obj): return Attachment.find(~AttachmentFolder.is_deleted, AttachmentFolder.linked_object == obj, is_deleted=False, _join=AttachmentFolder).count()
def has_data(self): return AttachmentFolder.has_rows() or Attachment.has_rows()
def find_attachments(self): return Attachment.find(~AttachmentFolder.is_deleted, ~Attachment.is_deleted, AttachmentFolder.event_id == int(self.event.id), _join=AttachmentFolder)
def _process_args(self): self.attachment = Attachment.find_one(id=request.view_args['attachment_id'], is_deleted=False) if self.attachment.folder.is_deleted: raise NotFound
def test_attachment_acls(dummy_event, dummy_user, create_user): from .schemas import ACLSchema class TestSchema(ACLSchema, mm.Schema): pass folder = AttachmentFolder(title='Dummy Folder', description='a dummy folder') attachment = Attachment(folder=folder, user=dummy_user, title='Dummy Attachment', type=AttachmentType.link, link_url='https://example.com') attachment.folder.object = dummy_event def assert_acl(expected_read_acl): __tracebackhide__ = True data = schema.dump(attachment) read_acl = data['_access'].pop('read', None) assert data == { '_access': { 'delete': ['IndicoAdmin'], 'owner': ['IndicoAdmin'], 'update': ['IndicoAdmin'] } } if read_acl is not None: read_acl = set(read_acl) assert read_acl == expected_read_acl schema = TestSchema() u1 = create_user(1, email='*****@*****.**') u2 = create_user(2, email='*****@*****.**') u3 = create_user(3, email='*****@*****.**') # event is inheriting public, so no acl assert_acl(None) # event is protected and the acl is empty (nobody has regular access) dummy_event.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin'}) dummy_event.update_principal(u1, read_access=True) dummy_event.category.update_principal(u2, read_access=True) dummy_event.category.parent.update_principal(u3, read_access=True) # self-protected, so no acl inherited assert_acl({'IndicoAdmin', 'User:1'}) # event is inheriting from public categories, so there is no acl dummy_event.protection_mode = ProtectionMode.inheriting assert_acl(None) # event it itself public, so no acl here as well dummy_event.protection_mode = ProtectionMode.public assert_acl(None) # inheriting, so all parent acl entries dummy_event.protection_mode = ProtectionMode.inheriting dummy_event.category.parent.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin', 'User:1', 'User:2', 'User:3'}) # category protected, so no parent category acl inherited dummy_event.category.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin', 'User:1', 'User:2'}) # parent category acl entry is a manager, that one is inherited dummy_event.category.parent.update_principal(u3, full_access=True) assert_acl({'IndicoAdmin', 'User:1', 'User:2', 'User:3'}) # attachment self-protected, only the category/event manager has access folder.update_principal(u2, read_access=True) attachment.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin', 'User:3'}) # the user in the attachment acl has access as well attachment.update_principal(u1, read_access=True) attachment.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin', 'User:3', 'User:1'}) # attachment inheriting from self-protected folder - only the folder acl is used attachment.protection_mode = ProtectionMode.inheriting folder.protection_mode = ProtectionMode.protected assert_acl({'IndicoAdmin', 'User:3', 'User:2'})
def test_dump_attachment(db, dummy_user, dummy_contribution): from .schemas import AttachmentRecordSchema folder = AttachmentFolder(title='Dummy Folder', description='a dummy folder') file = AttachmentFile(user=dummy_user, filename='dummy_file.txt', content_type='text/plain') attachment = Attachment(folder=folder, user=dummy_user, title='Dummy Attachment', type=AttachmentType.file, file=file) attachment.folder.object = dummy_contribution attachment.file.save(BytesIO(b'hello world')) db.session.flush() category_id = dummy_contribution.event.category_id schema = AttachmentRecordSchema(context={'schema': 'test-attachment'}) assert schema.dump(attachment) == { '$schema': 'test-attachment', '_access': { 'delete': ['IndicoAdmin'], 'owner': ['IndicoAdmin'], 'update': ['IndicoAdmin'], }, '_data': { 'filename': 'dummy_file.txt', 'site': 'http://localhost', 'title': 'Dummy Attachment', 'persons': { 'name': 'Guinea Pig' }, }, 'attachment_id': attachment.id, 'category_id': category_id, 'category_path': [ { 'id': 0, 'title': 'Home', 'url': '/' }, { 'id': category_id, 'title': 'dummy', 'url': f'/category/{category_id}/' }, ], 'contribution_id': dummy_contribution.id, 'event_id': 0, 'folder_id': folder.id, 'modified_dt': attachment.modified_dt.isoformat(), 'type': 'attachment', 'type_format': 'file', 'url': (f'http://localhost/event/0/contributions/' f'{dummy_contribution.id}/attachments/{folder.id}/{attachment.id}/dummy_file.txt' ), }
def search_attachments(self, q, user, page, category_id, event_id, admin_override_enabled): contrib_event = db.aliased(Event) contrib_session = db.aliased(Session) subcontrib_contrib = db.aliased(Contribution) subcontrib_session = db.aliased(Session) subcontrib_event = db.aliased(Event) session_event = db.aliased(Event) attachment_strategy = _apply_acl_entry_strategy( selectinload(Attachment.acl_entries), AttachmentPrincipal) folder_strategy = contains_eager(Attachment.folder) folder_strategy.load_only('id', 'protection_mode', 'link_type', 'category_id', 'event_id', 'linked_event_id', 'contribution_id', 'subcontribution_id', 'session_id') _apply_acl_entry_strategy( folder_strategy.selectinload(AttachmentFolder.acl_entries), AttachmentFolderPrincipal) # event event_strategy = folder_strategy.contains_eager( AttachmentFolder.linked_event) _apply_event_access_strategy(event_strategy) _apply_acl_entry_strategy( event_strategy.selectinload(Event.acl_entries), EventPrincipal) # contribution contrib_strategy = folder_strategy.contains_eager( AttachmentFolder.contribution) _apply_contrib_access_strategy(contrib_strategy) _apply_acl_entry_strategy( contrib_strategy.selectinload(Contribution.acl_entries), ContributionPrincipal) contrib_event_strategy = contrib_strategy.contains_eager( Contribution.event.of_type(contrib_event)) _apply_event_access_strategy(contrib_event_strategy) _apply_acl_entry_strategy( contrib_event_strategy.selectinload(contrib_event.acl_entries), EventPrincipal) contrib_session_strategy = contrib_strategy.contains_eager( Contribution.session.of_type(contrib_session)) contrib_session_strategy.load_only('id', 'event_id', 'protection_mode') _apply_acl_entry_strategy( contrib_session_strategy.selectinload(contrib_session.acl_entries), SessionPrincipal) # subcontribution subcontrib_strategy = folder_strategy.contains_eager( AttachmentFolder.subcontribution) subcontrib_strategy.load_only('id', 'contribution_id', 'title') subcontrib_contrib_strategy = subcontrib_strategy.contains_eager( SubContribution.contribution.of_type(subcontrib_contrib)) _apply_contrib_access_strategy(subcontrib_contrib_strategy) _apply_acl_entry_strategy( subcontrib_contrib_strategy.selectinload( subcontrib_contrib.acl_entries), ContributionPrincipal) subcontrib_event_strategy = subcontrib_contrib_strategy.contains_eager( subcontrib_contrib.event.of_type(subcontrib_event)) _apply_event_access_strategy(subcontrib_event_strategy) _apply_acl_entry_strategy( subcontrib_event_strategy.selectinload( subcontrib_event.acl_entries), EventPrincipal) subcontrib_session_strategy = subcontrib_contrib_strategy.contains_eager( subcontrib_contrib.session.of_type(subcontrib_session)) subcontrib_session_strategy.load_only('id', 'event_id', 'protection_mode') _apply_acl_entry_strategy( subcontrib_session_strategy.selectinload( subcontrib_session.acl_entries), SessionPrincipal) # session session_strategy = folder_strategy.contains_eager( AttachmentFolder.session) session_strategy.load_only('id', 'event_id', 'protection_mode') session_event_strategy = session_strategy.contains_eager( Session.event.of_type(session_event)) _apply_event_access_strategy(session_event_strategy) session_event_strategy.selectinload(session_event.acl_entries) _apply_acl_entry_strategy( session_strategy.selectinload(Session.acl_entries), SessionPrincipal) attachment_filters = [ Attachment.title_matches(q), ~Attachment.is_deleted, ~AttachmentFolder.is_deleted, AttachmentFolder.link_type != LinkType.category, db.or_( AttachmentFolder.link_type != LinkType.event, ~Event.is_deleted, ), db.or_(AttachmentFolder.link_type != LinkType.contribution, ~Contribution.is_deleted & ~contrib_event.is_deleted), db.or_( AttachmentFolder.link_type != LinkType.subcontribution, db.and_( ~SubContribution.is_deleted, ~subcontrib_contrib.is_deleted, ~subcontrib_event.is_deleted, )), db.or_(AttachmentFolder.link_type != LinkType.session, ~Session.is_deleted & ~session_event.is_deleted) ] if category_id is not None: attachment_filters.append( AttachmentFolder.event.has( Event.category_chain_overlaps(category_id))) if event_id is not None: attachment_filters.append(AttachmentFolder.event_id == event_id) query = ( Attachment.query.join( Attachment.folder).filter(*attachment_filters).options( folder_strategy, attachment_strategy, joinedload( Attachment.user).joinedload('_affiliation')).outerjoin( AttachmentFolder.linked_event).outerjoin( AttachmentFolder.contribution).outerjoin( Contribution.event.of_type(contrib_event)). outerjoin(Contribution.session.of_type(contrib_session)).outerjoin( AttachmentFolder.subcontribution).outerjoin( SubContribution.contribution.of_type(subcontrib_contrib)). outerjoin( subcontrib_contrib.event.of_type(subcontrib_event)).outerjoin( subcontrib_contrib.session.of_type( subcontrib_session)).outerjoin( AttachmentFolder.session).outerjoin( Session.event.of_type(session_event))) objs, pagenav = self._paginate(query, page, Attachment.id, user, admin_override_enabled) query = (Attachment.query.filter(Attachment.id.in_( a.id for a in objs)).options( joinedload(Attachment.folder).options( joinedload(AttachmentFolder.subcontribution), joinedload(AttachmentFolder.event).options( undefer(Event.detailed_category_chain))))) attachments_by_id = {a.id: a for a in query} attachments = [attachments_by_id[a.id] for a in objs] res = AttachmentSchema(many=True).dump(attachments) return pagenav, AttachmentResultSchema(many=True).load(res)
def _checkParams(self): self.attachment = Attachment.find_one(id=request.view_args['attachment_id'], is_deleted=False) if self.attachment.folder.is_deleted: raise NotFound