def __auto_table_args(cls): return ( db.Index('ix_events_start_dt_desc', cls.start_dt.desc()), db.Index('ix_events_end_dt_desc', cls.end_dt.desc()), db.Index('ix_events_not_deleted_category', cls.is_deleted, cls.category_id), db.Index('ix_events_not_deleted_category_dates', cls.is_deleted, cls.category_id, cls.start_dt, cls.end_dt), db.Index('ix_uq_events_url_shortcut', db.func.lower(cls.url_shortcut), unique=True, postgresql_where=db.text('NOT is_deleted')), db.CheckConstraint("category_id IS NOT NULL OR is_deleted", 'category_data_set'), db.CheckConstraint( "(logo IS NULL) = (logo_metadata::text = 'null')", 'valid_logo'), db.CheckConstraint( "(stylesheet IS NULL) = (stylesheet_metadata::text = 'null')", 'valid_stylesheet'), db.CheckConstraint("end_dt >= start_dt", 'valid_dates'), db.CheckConstraint("url_shortcut != ''", 'url_shortcut_not_empty'), db.CheckConstraint("cloned_from_id != id", 'not_cloned_from_self'), db.CheckConstraint('visibility IS NULL OR visibility >= 0', 'valid_visibility'), { 'schema': 'events' })
def __auto_table_args(cls): uniques = () if cls.unique_columns: uniques = [db.Index('ix_uq_{}_user'.format(cls.__tablename__), 'user_id', *cls.unique_columns, unique=True, postgresql_where=db.text('type = {}'.format(PrincipalType.user))), db.Index('ix_uq_{}_local_group'.format(cls.__tablename__), 'local_group_id', *cls.unique_columns, unique=True, postgresql_where=db.text('type = {}'.format(PrincipalType.local_group))), db.Index('ix_uq_{}_mp_group'.format(cls.__tablename__), 'mp_group_provider', 'mp_group_name', *cls.unique_columns, unique=True, postgresql_where=db.text('type = {}'.format(PrincipalType.multipass_group)))] if cls.allow_emails: uniques.append(db.Index('ix_uq_{}_email'.format(cls.__tablename__), 'email', *cls.unique_columns, unique=True, postgresql_where=db.text('type = {}'.format(PrincipalType.email)))) indexes = [db.Index(None, 'mp_group_provider', 'mp_group_name')] checks = [_make_check(PrincipalType.user, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'user_id'), _make_check(PrincipalType.local_group, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'local_group_id'), _make_check(PrincipalType.multipass_group, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'mp_group_provider', 'mp_group_name')] if cls.allow_emails: checks.append(_make_check(PrincipalType.email, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'email')) checks.append(db.CheckConstraint('email IS NULL OR email = lower(email)', 'lowercase_email')) if cls.allow_networks: checks.append(_make_check(PrincipalType.network, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'ip_network_group_id')) if cls.allow_event_roles: checks.append(_make_check(PrincipalType.event_role, cls.allow_emails, cls.allow_networks, cls.allow_event_roles, 'event_role_id')) return tuple(uniques + indexes + checks)
def __auto_table_args(cls): return ( db.Index(None, 'category_chain', postgresql_using='gin'), db.Index('ix_events_title_fts', db.func.to_tsvector('simple', cls.title), postgresql_using='gin'), db.Index('ix_events_start_dt_desc', cls.start_dt.desc()), db.Index('ix_events_end_dt_desc', cls.end_dt.desc()), db.CheckConstraint( "(category_id IS NOT NULL AND category_chain IS NOT NULL) OR is_deleted", 'category_data_set'), db.CheckConstraint("category_id = category_chain[1]", 'category_id_matches_chain'), db.CheckConstraint( "category_chain[array_length(category_chain, 1)] = 0", 'category_chain_has_root'), db.CheckConstraint( "(logo IS NULL) = (logo_metadata::text = 'null')", 'valid_logo'), db.CheckConstraint( "(stylesheet IS NULL) = (stylesheet_metadata::text = 'null')", 'valid_stylesheet'), db.CheckConstraint("end_dt >= start_dt", 'valid_dates'), db.CheckConstraint("title != ''", 'valid_title'), db.CheckConstraint("cloned_from_id != id", 'not_cloned_from_self'), { 'schema': 'events' })
def __auto_table_args(cls): return (db.Index('ix_events_start_dt_desc', cls.start_dt.desc()), db.Index('ix_events_end_dt_desc', cls.end_dt.desc()), db.Index('ix_events_not_deleted_category', cls.is_deleted, cls.category_id), db.Index('ix_events_not_deleted_category_dates', cls.is_deleted, cls.category_id, cls.start_dt, cls.end_dt), db.CheckConstraint("category_id IS NOT NULL OR is_deleted", 'category_data_set'), db.CheckConstraint("(logo IS NULL) = (logo_metadata::text = 'null')", 'valid_logo'), db.CheckConstraint("(stylesheet IS NULL) = (stylesheet_metadata::text = 'null')", 'valid_stylesheet'), db.CheckConstraint("end_dt >= start_dt", 'valid_dates'), db.CheckConstraint("cloned_from_id != id", 'not_cloned_from_self'), db.CheckConstraint('visibility IS NULL OR visibility >= 0', 'valid_visibility'), {'schema': 'events'})
class Setting(SettingsBase, db.Model): __table_args__ = (db.Index(None, 'module', 'name'), db.UniqueConstraint('module', 'name'), db.CheckConstraint('module = lower(module)', 'lowercase_module'), db.CheckConstraint('name = lower(name)', 'lowercase_name'), {'schema': 'indico'}) @return_ascii def __repr__(self): return '<Setting({}, {}, {!r})>'.format(self.module, self.name, self.value)
class EventSetting(SettingsBase, db.Model): __table_args__ = (db.Index(None, 'event_id', 'module', 'name'), db.Index(None, 'event_id', 'module'), db.UniqueConstraint('event_id', 'module', 'name'), db.CheckConstraint('module = lower(module)', 'lowercase_module'), db.CheckConstraint('name = lower(name)', 'lowercase_name'), {'schema': 'events'}) event_id = db.Column( db.String, index=True, nullable=False ) @return_ascii def __repr__(self): return '<EventSetting({}, {}, {}, {!r})>'.format(self.event_id, self.module, self.name, self.value) @classmethod def delete_event(cls, event_id): cls.find(event_id=event_id).delete(synchronize_session='fetch')
class OutlookQueueEntry(db.Model): """Pending calendar updates""" __tablename__ = 'queue' __table_args__ = (db.Index(None, 'user_id', 'event_id', 'action'), { 'schema': 'plugin_outlook' }) #: Entry ID (mainly used to sort by insertion order) id = db.Column(db.Integer, primary_key=True) #: ID of the user user_id = db.Column(db.Integer, db.ForeignKey('users.users.id'), index=True, nullable=False) #: ID of the event event_id = db.Column(db.Integer, db.ForeignKey('events.events.id'), index=True, nullable=False) #: :class:`OutlookAction` to perform action = db.Column(PyIntEnum(OutlookAction), nullable=False) #: The user associated with the queue entry user = db.relationship('User', lazy=False, backref=db.backref('outlook_queue', lazy='dynamic')) #: The Event this queue entry is associated with event = db.relationship('Event', lazy=True, backref=db.backref('outlook_queue_entries', lazy='dynamic')) @return_ascii def __repr__(self): return '<OutlookQueueEntry({}, {}, {}, {})>'.format( self.id, self.event_id, self.user_id, OutlookAction(self.action).name) @classmethod def record(cls, event, user, action): """Records a new calendar action :param event: the event (a :class:`.Event` instance) :param user: the user (a :class:`.User` instance) :param action: the action (an :class:`OutlookAction` member) """ # It would be nice to delete matching records first, but this sometimes results in very weird deadlocks event.outlook_queue_entries.append(cls(user_id=user.id, action=action)) db.session.flush()
class IndexedCategory(db.Model): __tablename__ = 'category_index' __table_args__ = (db.Index(None, 'title_vector', postgresql_using='gin'), { 'schema': 'indico' }) id = db.Column(db.String, primary_key=True) @property def title(self): return self.title_vector @title.setter def title(self, title): self.title_vector = db.func.to_tsvector('simple', title) title_vector = db.Column(TSVECTOR)
class IndexedEvent(db.Model): __tablename__ = 'event_index' __table_args__ = (db.Index(None, 'title_vector', postgresql_using='gin'), { 'schema': 'events' }) id = db.Column(db.Integer, primary_key=True, autoincrement=False) @property def title(self): return self.title_vector @title.setter def title(self, title): self.title_vector = db.func.to_tsvector('simple', title) title_vector = db.Column(TSVECTOR) start_date = db.Column(db.DateTime, nullable=False, index=True) end_date = db.Column(db.DateTime, nullable=False, index=True)
def __auto_table_args(): return (db.Index(None, 'module', 'name'), {'schema': 'indico'})
class EventPerson(PersonMixin, db.Model): """A person inside an event, e.g. a speaker/author etc.""" __tablename__ = 'persons' __table_args__ = (db.UniqueConstraint('event_id', 'user_id'), db.CheckConstraint('email = lower(email)', 'lowercase_email'), db.Index(None, 'event_id', 'email', unique=True, postgresql_where=db.text("email != ''")), { 'schema': 'events' }) id = db.Column(db.Integer, primary_key=True) event_id = db.Column(db.Integer, db.ForeignKey('events.events.id'), nullable=False, index=True) user_id = db.Column(db.Integer, db.ForeignKey('users.users.id'), nullable=True, index=True) first_name = db.Column(db.String, nullable=False, default='') last_name = db.Column(db.String, nullable=False) email = db.Column(db.String, nullable=False, index=True, default='') # the title of the user - you usually want the `title` property! _title = db.Column('title', PyIntEnum(UserTitle), nullable=False, default=UserTitle.none) affiliation = db.Column(db.String, nullable=False, default='') address = db.Column(db.Text, nullable=False, default='') phone = db.Column(db.String, nullable=False, default='') invited_dt = db.Column(UTCDateTime, nullable=True) is_untrusted = db.Column(db.Boolean, nullable=False, default=False) event = db.relationship('Event', lazy=True, backref=db.backref('persons', cascade='all, delete-orphan', cascade_backrefs=False, lazy='dynamic')) user = db.relationship('User', lazy=True, backref=db.backref('event_persons', cascade_backrefs=False, lazy='dynamic')) # relationship backrefs: # - abstract_links (AbstractPersonLink.person) # - contribution_links (ContributionPersonLink.person) # - event_links (EventPersonLink.person) # - session_block_links (SessionBlockPersonLink.person) # - subcontribution_links (SubContributionPersonLink.person) @locator_property def locator(self): return dict(self.event.locator, person_id=self.id) @return_ascii def __repr__(self): return format_repr(self, 'id', is_untrusted=False, _text=self.full_name) @property def principal(self): if self.user is not None: return self.user elif self.email: return EmailPrincipal(self.email) return None @classmethod def create_from_user(cls, user, event=None, is_untrusted=False): return EventPerson(user=user, event=event, first_name=user.first_name, last_name=user.last_name, email=user.email, affiliation=user.affiliation, address=user.address, phone=user.phone, is_untrusted=is_untrusted) @classmethod def for_user(cls, user, event=None, is_untrusted=False): """Return EventPerson for a matching User in Event creating if needed""" person = event.persons.filter_by(user=user).first() if event else None return person or cls.create_from_user( user, event, is_untrusted=is_untrusted) @classmethod def merge_users(cls, target, source): """Merge the EventPersons of two users. :param target: The target user of the merge :param source: The user that is being merged into `target` """ existing_persons = {ep.event_id: ep for ep in target.event_persons} for event_person in source.event_persons: existing = existing_persons.get(event_person.event_id) if existing is None: event_person.user = target else: existing.merge_person_info(event_person) db.session.delete(event_person) db.session.flush() @classmethod def link_user_by_email(cls, user): """ Links all email-based persons matching the user's email addresses with the user. :param user: A User object. """ from indico.modules.events.models.events import Event query = (cls.query.join(EventPerson.event).filter( ~Event.is_deleted, cls.email.in_(user.all_emails), cls.user_id.is_(None))) for event_person in query: existing = (cls.query.filter_by( user_id=user.id, event_id=event_person.event_id).one_or_none()) if existing is None: event_person.user = user else: existing.merge_person_info(event_person) db.session.delete(event_person) db.session.flush() @no_autoflush def merge_person_info(self, other): from indico.modules.events.contributions.models.persons import AuthorType for column_name in { '_title', 'affiliation', 'address', 'phone', 'first_name', 'last_name' }: value = getattr(self, column_name) or getattr(other, column_name) setattr(self, column_name, value) for event_link in other.event_links: existing_event_link = next( (link for link in self.event_links if link.event_id == event_link.event_id), None) if existing_event_link is None: event_link.person = self else: other.event_links.remove(event_link) for abstract_link in other.abstract_links: existing_abstract_link = next( (link for link in self.abstract_links if link.abstract_id == abstract_link.abstract_id), None) if existing_abstract_link is None: abstract_link.person = self else: existing_abstract_link.is_speaker |= abstract_link.is_speaker existing_abstract_link.author_type = AuthorType.get_highest( existing_abstract_link.author_type, abstract_link.author_type) other.abstract_links.remove(abstract_link) for contribution_link in other.contribution_links: existing_contribution_link = next( (link for link in self.contribution_links if link.contribution_id == contribution_link.contribution_id), None) if existing_contribution_link is None: contribution_link.person = self else: existing_contribution_link.is_speaker |= contribution_link.is_speaker existing_contribution_link.author_type = AuthorType.get_highest( existing_contribution_link.author_type, contribution_link.author_type) other.contribution_links.remove(contribution_link) for subcontribution_link in other.subcontribution_links: existing_subcontribution_link = next( (link for link in self.subcontribution_links if link.subcontribution_id == subcontribution_link.subcontribution_id), None) if existing_subcontribution_link is None: subcontribution_link.person = self else: other.subcontribution_links.remove(subcontribution_link) for session_block_link in other.session_block_links: existing_session_block_link = next( (link for link in self.session_block_links if link.session_block_id == session_block_link.session_block_id), None) if existing_session_block_link is None: session_block_link.person = self else: other.session_block_links.remove(session_block_link) db.session.flush() def has_role(self, role, obj): """Whether the person has a role in the ACL list of a given object""" principals = [ x for x in obj.acl_entries if x.has_management_permission(role, explicit=True) ] return any( x for x in principals if ((self.user_id is not None and self.user_id == x.user_id) or ( self.email is not None and self.email == x.email)))
class Setting(db.Model): __tablename__ = 'settings' __table_args__ = (db.Index('ix_settings_module_key', 'module', 'name'), db.UniqueConstraint('module', 'name'), db.CheckConstraint('module = lower(module)'), db.CheckConstraint('name = lower(name)'), { 'schema': 'indico' }) id = db.Column(db.Integer, primary_key=True) module = db.Column(db.String, index=True) name = db.Column(db.String, index=True) value = db.Column(JSON) @return_ascii def __repr__(self): return u'<Setting({}, {}, {!r})>'.format(self.module, self.name, self.value) @classmethod def get_setting(cls, module, name): return cls.find_first(module=module, name=name) @classmethod def get_all_settings(cls, module): return {s.name: s for s in cls.find(module=module)} @classmethod def get_all(cls, module): return {s.name: s.value for s in cls.find(module=module)} @classmethod def get(cls, module, name, default=None): setting = cls.get_setting(module, name) if setting is None: return default return setting.value @classmethod def set(cls, module, name, value): setting = cls.get_setting(module, name) if setting is None: setting = cls(module=module, name=name) db.session.add(setting) setting.value = value @classmethod def set_multi(cls, module, items): existing = cls.get_all_settings(module) for name in items.viewkeys() - existing.viewkeys(): setting = cls(module=module, name=name, value=items[name]) db.session.add(setting) for name in items.viewkeys() & existing.viewkeys(): existing[name].value = items[name] @classmethod def delete(cls, module, *names): if not names: return Setting.find( Setting.name.in_(names), Setting.module == module).delete(synchronize_session='fetch') @classmethod def delete_all(cls, module): Setting.find(module=module).delete()