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 _copy_person_link_data(link_data): # Copy person link data since we would otherwise end up # adding the EventPersons of the first event in all other # events of the series. for link, submitter in link_data.iteritems(): link_copy = EventPersonLink(**{col: getattr(link, col) for col in get_simple_column_attrs(EventPersonLink)}) link_copy.person = EventPerson(**{col: getattr(link.person, col) for col in get_simple_column_attrs(EventPerson)}) yield link_copy, submitter
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_fields(self, fields): attrs = get_simple_column_attrs(ContributionFieldValue) for old_field_value in fields: field_value = ContributionFieldValue() field_value.contribution_field = self._contrib_field_map[old_field_value.contribution_field] field_value.populate_from_attrs(old_field_value, attrs) yield field_value
def _clone_person_links(self, cls, person_links): attrs = get_simple_column_attrs(cls) for old_link in person_links: link = cls() link.populate_from_attrs(old_link, attrs) link.person = self._person_map[old_link.person] yield link
def _clone_persons(self, new_event): attrs = get_simple_column_attrs(EventPerson) | {"user"} for old_person in self.old_event.persons: person = EventPerson(event_new=new_event) person.populate_from_attrs(old_person, attrs) assert person not in db.session self._person_map[old_person] = person
def _clone_person_links(self, new_event): attrs = get_simple_column_attrs(EventPersonLink) for old_link in self.old_event.person_links: link = EventPersonLink() link.populate_from_attrs(old_link, attrs) link.person = self._person_map[old_link.person] new_event.person_links.append(link)
def _clone_timetable(self, new_event): offset = new_event.start_dt - self.old_event.start_dt # no need to copy the type; it's set automatically based on the object attrs = get_simple_column_attrs(TimetableEntry) - {'type', 'start_dt'} break_strategy = defaultload('break_') break_strategy.joinedload('own_venue') break_strategy.joinedload('own_room').lazyload('*') query = (self.old_event.timetable_entries .options(joinedload('parent').lazyload('*'), break_strategy) .order_by(TimetableEntry.parent_id.is_(None).desc())) # iterate over all timetable entries; start with top-level # ones so we can build a mapping that can be used once we # reach nested entries entry_map = {} for old_entry in query: entry = TimetableEntry() entry.start_dt = old_entry.start_dt + offset entry.populate_from_attrs(old_entry, attrs) if old_entry.parent is not None: entry.parent = entry_map[old_entry.parent] if old_entry.session_block is not None: entry.session_block = self._session_block_map[old_entry.session_block] if old_entry.contribution is not None: entry.contribution = self._contrib_map[old_entry.contribution] if old_entry.break_ is not None: entry.break_ = self._clone_break(old_entry.break_) new_event.timetable_entries.append(entry) entry_map[old_entry] = entry
def _clone_tracks(self, new_event): attrs = get_simple_column_attrs(Track) | {'abstract_reviewers', 'conveners'} for old_track in self.old_event.tracks: track = Track() track.populate_from_attrs(old_track, attrs) new_event.tracks.append(track) self._track_map[old_track] = track
def _clone_email_templates(self, new_event): attrs = get_simple_column_attrs(AbstractEmailTemplate) - {'rules'} for old_tpl in self.old_event.abstract_email_templates: tpl = AbstractEmailTemplate() tpl.populate_from_attrs(old_tpl, attrs) tpl.rules = filter(None, map(self._clone_email_template_rule, old_tpl.rules)) new_event.abstract_email_templates.append(tpl)
def _clone_person_links(self, person_links): attrs = get_simple_column_attrs(SessionBlockPersonLink) for old_link in person_links: link = SessionBlockPersonLink() link.populate_from_attrs(old_link, attrs) link.person = self._person_map[old_link.person] yield link
def _clone_contribs(self, new_event): attrs = (get_simple_column_attrs(Contribution) | {'own_room', 'own_venue'}) - {'abstract_id'} query = (Contribution.query.with_parent(self.old_event) .options(undefer('_last_friendly_subcontribution_id'), joinedload('own_venue'), joinedload('own_room').lazyload('*'), joinedload('session'), joinedload('session_block').lazyload('session'), joinedload('type'), subqueryload('acl_entries'), subqueryload('subcontributions').joinedload('references'), subqueryload('references'), subqueryload('person_links'), subqueryload('field_values'))) for old_contrib in query: contrib = Contribution() contrib.populate_from_attrs(old_contrib, attrs) contrib.subcontributions = list(self._clone_subcontribs(old_contrib.subcontributions)) contrib.acl_entries = clone_principals(ContributionPrincipal, old_contrib.acl_entries) contrib.references = list(self._clone_references(ContributionReference, old_contrib.references)) contrib.person_links = list(self._clone_person_links(ContributionPersonLink, old_contrib.person_links)) contrib.field_values = list(self._clone_fields(old_contrib.field_values)) if old_contrib.type is not None: contrib.type = self._contrib_type_map[old_contrib.type] if old_contrib.session is not None: contrib.session = self._session_map[old_contrib.session] if old_contrib.session_block is not None: contrib.session_block = self._session_block_map[old_contrib.session_block] new_event.contributions.append(contrib) self._contrib_map[old_contrib] = contrib
def _clone_contrib_types(self, new_event): attrs = get_simple_column_attrs(ContributionType) for old_contrib_type in self.old_event.contribution_types: contrib_type = ContributionType() contrib_type.populate_from_attrs(old_contrib_type, attrs) new_event.contribution_types.append(contrib_type) self._contrib_type_map[old_contrib_type] = contrib_type
def _clone_session_blocks(self, blocks): attrs = get_simple_column_attrs(SessionBlock) | {'own_room', 'own_venue'} for old_block in blocks: block = SessionBlock() block.populate_from_attrs(old_block, attrs) block.person_links = list(self._clone_person_links(old_block.person_links)) self._session_block_map[old_block] = block yield block
def _clone_contrib_fields(self, new_event): attrs = get_simple_column_attrs(ContributionField) - {'field_data'} for old_contrib_field in self.old_event.contribution_fields: contrib_field = ContributionField() contrib_field.populate_from_attrs(old_contrib_field, attrs) contrib_field.field_data = deepcopy(old_contrib_field.field_data) new_event.contribution_fields.append(contrib_field) self._contrib_field_map[old_contrib_field] = contrib_field
def _clone_registrations(self, old_form, new_form, field_data_map): registration_attrs = get_simple_column_attrs(Registration) - {'uuid', 'ticket_uuid'} for old_registration in old_form.registrations: if old_registration.is_deleted: continue new_registration = Registration(user=old_registration.user, registration_form=new_form, **{attr: getattr(old_registration, attr) for attr in registration_attrs}) reg_data_attrs = get_simple_column_attrs(RegistrationData) - {'storage_file_id', 'storage_backend', 'size'} for old_registration_data in old_registration.data: new_registration_data = RegistrationData(registration=new_registration, **{attr: getattr(old_registration_data, attr) for attr in reg_data_attrs}) new_registration_data.field_data = field_data_map[old_registration_data.field_data] if old_registration_data.storage_file_id is not None: with old_registration_data.open() as fd: new_registration_data.save(fd) db.session.flush() signals.event.registration_state_updated.send(new_registration)
def _clone_subcontribs(self, subcontribs): attrs = get_simple_column_attrs(SubContribution) for old_subcontrib in subcontribs: subcontrib = SubContribution() subcontrib.populate_from_attrs(old_subcontrib, attrs) subcontrib.references = list(self._clone_references(SubContributionReference, old_subcontrib.references)) subcontrib.person_links = list(self._clone_person_links(SubContributionPersonLink, old_subcontrib.person_links)) self._subcontrib_map[old_subcontrib] = subcontrib yield subcontrib
def _copy_menu_entry(self, menu_entry, new_event, container, include_children=True): base_columns = get_simple_column_attrs(MenuEntry) new_menu_entry = MenuEntry(**{col: getattr(menu_entry, col) for col in base_columns}) if menu_entry.is_page: with db.session.no_autoflush: # menu_entry.page is lazy-loaded page = EventPage(event_new=new_event, html=menu_entry.page.html) new_menu_entry.page = page if menu_entry.page.is_default: new_event.default_page = new_menu_entry.page container.append(new_menu_entry) if include_children: for child in menu_entry.children: self._copy_menu_entry(child, new_event, new_menu_entry.children, include_children=False)
def clone(self, new_event, options): if not options: return self._clone_with_registrations = 'registrations' in options attrs = get_simple_column_attrs(RegistrationForm) - {'start_dt', 'end_dt', 'modification_end_dt'} with db.session.no_autoflush: for old_form in self._find_registration_forms(): new_form = RegistrationForm(event_new=new_event.as_event, **{attr: getattr(old_form, attr) for attr in attrs}) self._clone_form_items(old_form, new_form) if self._clone_with_registrations: self._clone_registrations(old_form, new_form, new_event) db.session.add(new_form) db.session.flush()
def _clone_sessions(self, new_event): attrs = get_simple_column_attrs(Session) | {'own_room', 'own_venue'} query = (Session.query.with_parent(self.old_event) .options(joinedload('blocks'), joinedload('own_venue'), joinedload('own_room').lazyload('*'), subqueryload('acl_entries'))) for old_sess in query: sess = Session() sess.populate_from_attrs(old_sess, attrs) sess.blocks = list(self._clone_session_blocks(old_sess.blocks)) sess.acl_entries = clone_principals(SessionPrincipal, old_sess.acl_entries) new_event.sessions.append(sess) self._session_map[old_sess] = sess
def run(self, new_event, cloners, shared_data): # if the registration cloner is also enabled, we have to keep # all revisions since they are likely to be in use clone_all_revisions = 'registrations' in cloners attrs = get_simple_column_attrs(RegistrationForm) - {'start_dt', 'end_dt', 'modification_end_dt'} self._field_data_map = {} self._form_map = {} for old_form in self.old_event.registration_forms: new_form = RegistrationForm(**{attr: getattr(old_form, attr) for attr in attrs}) self._clone_form_items(old_form, new_form, clone_all_revisions) new_event.registration_forms.append(new_form) db.session.flush() self._form_map[old_form] = new_form return {'form_map': self._form_map, 'field_data_map': self._field_data_map}
def clone_principals(cls, principals): """Clone a list of principals. :param cls: the principal type to use (a `PrincipalMixin` subclass) :param principals: a collection of these principals :return: A new set of principals that can be added to an object """ rv = set() assert all(isinstance(x, cls) for x in principals) attrs = get_simple_column_attrs(cls) | {'user', 'local_group', 'ip_network_group', 'event_role'} for old_principal in principals: principal = cls() principal.populate_from_dict({attr: getattr(old_principal, attr) for attr in attrs}) rv.add(principal) return rv
def run(self, new_event, cloners, shared_data): attrs = get_simple_column_attrs(db.m.EventReminder) - {'created_dt', 'scheduled_dt', 'is_sent'} attrs |= {'creator_id'} for old_reminder in self._find_reminders(): scheduled_dt = new_event.start_dt - old_reminder.event_start_delta # Skip anything that's would have been sent on a past date. # We ignore the time on purpose so cloning an event shortly before will # still trigger a reminder that's just a few hours overdue. if scheduled_dt.date() < now_utc().date(): logger.info('Not cloning reminder %s which would trigger at %s', old_reminder, scheduled_dt) continue reminder = db.m.EventReminder(**{attr: getattr(old_reminder, attr) for attr in attrs}) reminder.scheduled_dt = scheduled_dt new_event.reminders.append(reminder) db.session.flush() logger.info('Added reminder during event cloning: %s', reminder)
def _clone_form_items(self, old_form, new_form, clone_all_revisions): old_sections = RegistrationFormSection.find(RegistrationFormSection.registration_form_id == old_form.id) items_attrs = get_simple_column_attrs(RegistrationFormSection) for old_section in old_sections: new_section = RegistrationFormSection(**{attr: getattr(old_section, attr) for attr in items_attrs}) for old_item in old_section.children: new_item = RegistrationFormItem(parent=new_section, registration_form=new_form, **{attr: getattr(old_item, attr) for attr in items_attrs}) if new_item.is_field: if clone_all_revisions: self._clone_all_field_versions(old_item, new_item) else: field_data = RegistrationFormFieldData(field=new_item, versioned_data=old_item.versioned_data) new_item.current_data = field_data self._field_data_map[old_item.current_data] = field_data new_section.children.append(new_item) new_form.form_items.append(new_section) db.session.flush()
def _clone_form_items(self, old_form, new_form, clone_all_revisions): old_sections = RegistrationFormSection.find(RegistrationFormSection.registration_form_id == old_form.id) items_attrs = get_simple_column_attrs(RegistrationFormSection) for old_section in old_sections: new_section = RegistrationFormSection(**{attr: getattr(old_section, attr) for attr in items_attrs}) for old_item in old_section.children: new_item = RegistrationFormItem(parent=new_section, registration_form=new_form, **{attr: getattr(old_item, attr) for attr in items_attrs}) if new_item.is_field: if clone_all_revisions: self._clone_all_field_versions(old_item, new_item) else: field_data = RegistrationFormFieldData(field=new_item, versioned_data=old_item.versioned_data) new_item.current_data = field_data self._field_data_map[old_item.current_data] = field_data new_section.children.append(new_item) new_form.form_items.append(new_section) db.session.flush()
def clone(self, new_event, options): from indico.modules.events.reminders.models.reminders import EventReminder if 'reminders' not in options: return attrs = get_simple_column_attrs(EventReminder) - {'created_dt', 'scheduled_dt', 'is_sent'} attrs |= {'creator_id'} for old_reminder in self.find_reminders(): scheduled_dt = new_event.getStartDate() - old_reminder.event_start_delta # Skip anything that's would have been sent on a past date. # We ignore the time on purpose so cloning an event shortly before will # still trigger a reminder that's just a few hours overdue. if scheduled_dt.date() < now_utc().date(): logger.info('Not cloning reminder {} which would trigger at {}'.format(old_reminder, scheduled_dt)) continue reminder = EventReminder(event=new_event, **{attr: getattr(old_reminder, attr) for attr in attrs}) reminder.scheduled_dt = scheduled_dt db.session.add(reminder) db.session.flush() logger.info('Added reminder during event cloning: {}'.format(reminder))
def clone_principals(cls, principals): """Clone a list of principals. :param cls: the principal type to use (a `PrincipalMixin` subclass) :param principals: a collection of these principals :return: A new set of principals that can be added to an object """ rv = set() assert all(isinstance(x, cls) for x in principals) attrs = get_simple_column_attrs(cls) | { 'user', 'local_group', 'ip_network_group' } for old_principal in principals: principal = cls() principal.populate_from_dict( {attr: getattr(old_principal, attr) for attr in attrs}) rv.add(principal) return rv
def _create_new_contribution(self, event, old_contrib, preserve_session=True, excluded_attrs=None): attrs = (get_simple_column_attrs(Contribution) | {'own_room', 'own_venue'}) - {'abstract_id'} if excluded_attrs is not None: attrs -= excluded_attrs new_contrib = Contribution() new_contrib.populate_from_attrs(old_contrib, attrs) new_contrib.subcontributions = list(self._clone_subcontribs(old_contrib.subcontributions)) new_contrib.acl_entries = clone_principals(ContributionPrincipal, old_contrib.acl_entries) new_contrib.references = list(self._clone_references(ContributionReference, old_contrib.references)) new_contrib.person_links = list(self._clone_person_links(ContributionPersonLink, old_contrib.person_links)) new_contrib.field_values = list(self._clone_fields(old_contrib.field_values)) if old_contrib.type is not None: new_contrib.type = self._contrib_type_map[old_contrib.type] if preserve_session: if old_contrib.session is not None: new_contrib.session = self._session_map[old_contrib.session] if old_contrib.session_block is not None: new_contrib.session_block = self._session_block_map[old_contrib.session_block] event.contributions.append(new_contrib) return new_contrib
def run(self, new_event, cloners, shared_data): # if the registration cloner is also enabled, we have to keep # all revisions since they are likely to be in use clone_all_revisions = 'registrations' in cloners attrs = get_simple_column_attrs(RegistrationForm) - { 'start_dt', 'end_dt', 'modification_end_dt' } self._field_data_map = {} self._form_map = {} for old_form in self.old_event.registration_forms: new_form = RegistrationForm( **{attr: getattr(old_form, attr) for attr in attrs}) self._clone_form_items(old_form, new_form, clone_all_revisions) new_event.registration_forms.append(new_form) db.session.flush() self._form_map[old_form] = new_form return { 'form_map': self._form_map, 'field_data_map': self._field_data_map }
def run(self, new_event, cloners, shared_data, event_exists=False): attrs = get_simple_column_attrs( db.m.EventReminder) - {'created_dt', 'scheduled_dt', 'is_sent'} attrs |= {'creator_id'} for old_reminder in self._find_reminders(self.old_event): scheduled_dt = new_event.start_dt - old_reminder.event_start_delta # Skip anything that's would have been sent on a past date. # We ignore the time on purpose so cloning an event shortly before will # still trigger a reminder that's just a few hours overdue. if scheduled_dt.date() < now_utc().date(): logger.info( 'Not cloning reminder %s which would trigger at %s', old_reminder, scheduled_dt) continue reminder = db.m.EventReminder( **{attr: getattr(old_reminder, attr) for attr in attrs}) reminder.scheduled_dt = scheduled_dt new_event.reminders.append(reminder) db.session.flush() logger.info('Added reminder during event cloning: %s', reminder)
def _clone_timetable(self, new_event): offset = new_event.start_dt - self.old_event.start_dt # no need to copy the type; it's set automatically based on the object attrs = get_simple_column_attrs(TimetableEntry) - {'type', 'start_dt'} break_strategy = defaultload('break_') break_strategy.joinedload('own_venue') break_strategy.joinedload('own_room').lazyload('*') entry_key_order = db.case( { TimetableEntryType.SESSION_BLOCK: db.func.concat('s', TimetableEntry.id), TimetableEntryType.CONTRIBUTION: db.func.concat('c', TimetableEntry.id), TimetableEntryType.BREAK: db.func.concat('b', TimetableEntry.id), }, value=TimetableEntry.type) query = (self.old_event.timetable_entries.options( joinedload('parent').lazyload('*'), break_strategy).order_by( TimetableEntry.parent_id.is_(None).desc(), entry_key_order)) # iterate over all timetable entries; start with top-level # ones so we can build a mapping that can be used once we # reach nested entries entry_map = {} for old_entry in query: entry = TimetableEntry() entry.start_dt = old_entry.start_dt + offset entry.populate_from_attrs(old_entry, attrs) if old_entry.parent is not None: entry.parent = entry_map[old_entry.parent] if old_entry.session_block is not None: entry.session_block = self._session_block_map[ old_entry.session_block] if old_entry.contribution is not None: entry.contribution = self._contrib_map[old_entry.contribution] if old_entry.break_ is not None: entry.break_ = self._clone_break(old_entry.break_) new_event.timetable_entries.append(entry) entry_map[old_entry] = entry
def _copy_menu_entry(self, menu_entry, new_event, container, include_children=True): base_columns = get_simple_column_attrs(MenuEntry) new_menu_entry = MenuEntry( **{col: getattr(menu_entry, col) for col in base_columns}) if menu_entry.is_page: with db.session.no_autoflush: # menu_entry.page is lazy-loaded page = EventPage(event_id=new_event.id, html=menu_entry.page.html) new_menu_entry.page = page if menu_entry.page.is_default: new_event.as_event.default_page = new_menu_entry.page container.append(new_menu_entry) if include_children: for child in menu_entry.children: self._copy_menu_entry(child, new_event, new_menu_entry.children, include_children=False)
def clone_principals(cls, principals, event_role_map=None, regform_map=None): """Clone a list of principals. :param cls: the principal type to use (a `PrincipalMixin` subclass) :param principals: a collection of these principals :param event_role_map: the mapping from old to new event roles. if omitted, event roles are skipped :param regform_map: if omitted, registration forms are skipped :return: A new set of principals that can be added to an object """ rv = set() assert all(isinstance(x, cls) for x in principals) attrs = get_simple_column_attrs(cls) | { 'user', 'local_group', 'ip_network_group', 'category_role' } for old_principal in principals: event_role = None registration_form = None if old_principal.type == PrincipalType.event_role: if event_role_map is None: continue event_role = event_role_map[old_principal.event_role] elif old_principal.type == PrincipalType.registration_form: if regform_map is None: continue registration_form = regform_map[old_principal.registration_form] principal = cls() principal.populate_from_dict( {attr: getattr(old_principal, attr) for attr in attrs}) if event_role: principal.event_role = event_role elif registration_form: principal.registration_form = registration_form rv.add(principal) return rv
def _clone_contribs(self, new_event): attrs = (get_simple_column_attrs(Contribution) | {'own_room', 'own_venue'}) - {'abstract_id'} query = (Contribution.query.with_parent(self.old_event).options( undefer('_last_friendly_subcontribution_id'), joinedload('own_venue'), joinedload('own_room').lazyload('*'), joinedload('session'), joinedload('session_block').lazyload('session'), joinedload('type'), subqueryload('acl_entries'), subqueryload('subcontributions').joinedload('references'), subqueryload('references'), subqueryload('person_links'), subqueryload('field_values'))) for old_contrib in query: contrib = Contribution() contrib.populate_from_attrs(old_contrib, attrs) contrib.subcontributions = list( self._clone_subcontribs(old_contrib.subcontributions)) contrib.acl_entries = clone_principals(ContributionPrincipal, old_contrib.acl_entries) contrib.references = list( self._clone_references(ContributionReference, old_contrib.references)) contrib.person_links = list( self._clone_person_links(ContributionPersonLink, old_contrib.person_links)) contrib.field_values = list( self._clone_fields(old_contrib.field_values)) if old_contrib.type is not None: contrib.type = self._contrib_type_map[old_contrib.type] if old_contrib.session is not None: contrib.session = self._session_map[old_contrib.session] if old_contrib.session_block is not None: contrib.session_block = self._session_block_map[ old_contrib.session_block] new_event.contributions.append(contrib) self._contrib_map[old_contrib] = contrib
def _clone_references(self, cls, references): attrs = get_simple_column_attrs(cls) | {'reference_type'} for old_ref in references: ref = cls() ref.populate_from_attrs(old_ref, attrs) yield ref
def _clone_review_questions(self, new_event): attrs = get_simple_column_attrs(AbstractReviewQuestion) for old_question in self.old_event.abstract_review_questions: question = AbstractReviewQuestion() question.populate_from_attrs(old_question, attrs) new_event.abstract_review_questions.append(question)
def _clone_break(self, old_break): attrs = get_simple_column_attrs(Break) | {'own_room', 'own_venue'} break_ = Break() break_.populate_from_attrs(old_break, attrs) return break_
def _clone_break(self, old_break): attrs = get_simple_column_attrs(Break) | {'own_room', 'own_venue'} break_ = Break() break_.populate_from_attrs(old_break, attrs) return break_
def _clone_item(self, survey, old_item): item_cls = type(old_item) item = item_cls(survey=survey) item.populate_from_attrs(old_item, get_simple_column_attrs(item_cls)) return item
def _clone_tags(self, new_event): attrs = get_simple_column_attrs(EditingTag) for old_tag in self.old_event.editing_tags: tag = EditingTag() tag.populate_from_attrs(old_tag, attrs) new_event.editing_tags.append(tag)
def _clone_review_questions(self, new_event): attrs = get_simple_column_attrs(AbstractReviewQuestion) for old_question in self.old_event.abstract_review_questions: question = AbstractReviewQuestion() question.populate_from_attrs(old_question, attrs) new_event.abstract_review_questions.append(question)
def _clone_references(self, cls, references): attrs = get_simple_column_attrs(cls) | {'reference_type'} for old_ref in references: ref = cls() ref.populate_from_attrs(old_ref, attrs) yield ref