class LegacyCategoryMapping(db.Model): """Legacy category ID mapping Legacy categories have non-numeric IDs which are not supported by any new code. This mapping maps them to proper integer IDs to avoid breaking things. """ __tablename__ = 'legacy_id_map' __table_args__ = {'schema': 'categories'} legacy_category_id = db.Column(db.String, primary_key=True, index=True) category_id = db.Column(db.Integer, db.ForeignKey('categories.categories.id'), index=True, primary_key=True, autoincrement=False) category = db.relationship('Category', lazy=True, backref=db.backref('legacy_mapping', uselist=False, lazy=True)) @return_ascii def __repr__(self): return '<LegacyCategoryMapping({}, {})>'.format( self.legacy_category_id, self.category_id)
class SessionPrincipal(PrincipalRolesMixin, db.Model): __tablename__ = 'session_principals' principal_backref_name = 'in_session_acls' principal_for = 'Session' unique_columns = ('session_id', ) disallowed_protection_modes = frozenset() allow_emails = True @declared_attr def __table_args__(cls): return auto_table_args(cls, schema='events') #: The ID of the acl entry id = db.Column(db.Integer, primary_key=True) #: The ID of the associated session session_id = db.Column(db.Integer, db.ForeignKey('events.sessions.id'), nullable=False, index=True) # relationship backrefs: # - session (Session.acl_entries) @return_ascii def __repr__(self): return format_repr(self, 'id', 'session_id', 'principal', read_access=False, full_access=False, roles=[])
class ReferenceType(db.Model): __tablename__ = 'reference_types' @declared_attr def __table_args__(cls): return (db.Index('ix_uq_reference_types_name_lower', db.func.lower(cls.name), unique=True), { 'schema': 'fossir' }) #: The unique ID of the reference type id = db.Column(db.Integer, primary_key=True) #: The name of the referenced system name = db.Column(db.String, nullable=False) #: The scheme used to build an URN for the reference scheme = db.Column(db.String, nullable=False, default='') #: A URL template to build a link to a referenced entity url_template = db.Column(db.String, nullable=False, default='') # relationship backrefs: # - contribution_references (ContributionReference.reference_type) # - event_references (EventReference.reference_type) # - subcontribution_references (SubContributionReference.reference_type) @locator_property def locator(self): return {'reference_type_id': self.id} @return_ascii def __repr__(self): return format_repr(self, 'id', 'url_template', _text=self.name)
class SuggestedCategory(db.Model): __tablename__ = 'suggested_categories' __table_args__ = {'schema': 'users'} user_id = db.Column( db.Integer, db.ForeignKey('users.users.id'), primary_key=True, index=True, autoincrement=False ) category_id = db.Column( db.Integer, db.ForeignKey('categories.categories.id'), primary_key=True, index=True, autoincrement=False ) is_ignored = db.Column( db.Boolean, nullable=False, default=False ) score = db.Column( db.Float, nullable=False, default=0 ) category = db.relationship( 'Category', lazy=False, backref=db.backref( 'suggestions', lazy=True, cascade='all, delete-orphan' ) ) # relationship backrefs: # - user (User.suggested_categories) @return_ascii def __repr__(self): return format_repr(self, 'user_id', 'category_id', 'score', is_ignored=False) @classmethod def merge_users(cls, target, source): """Merge the suggestions for two users. :param target: The target user of the merge. :param source: The user that is being merged into `target`. """ target_suggestions = {x.category: x for x in target.suggested_categories} for suggestion in source.suggested_categories: new_suggestion = target_suggestions.get(suggestion.category) or cls(user=target, category=suggestion.category) new_suggestion.score = max(new_suggestion.score, suggestion.score) new_suggestion.is_ignored = new_suggestion.is_ignored or suggestion.is_ignored db.session.flush()
class EquipmentType(db.Model): __tablename__ = 'equipment_types' __table_args__ = (db.UniqueConstraint('name', 'location_id'), { 'schema': 'roombooking' }) id = db.Column(db.Integer, primary_key=True) parent_id = db.Column(db.Integer, db.ForeignKey('roombooking.equipment_types.id')) name = db.Column(db.String, nullable=False, index=True) location_id = db.Column(db.Integer, db.ForeignKey('roombooking.locations.id'), nullable=False) children = db.relationship('EquipmentType', backref=db.backref('parent', remote_side=[id])) # relationship backrefs: # - location (Location.equipment_types) # - parent (EquipmentType.children) # - reservations (Reservation.used_equipment) # - rooms (Room.available_equipment) @return_ascii def __repr__(self): return u'<EquipmentType({0}, {1}, {2})>'.format( self.id, self.name, self.location_id)
class EventPrincipal(PrincipalRolesMixin, db.Model): __tablename__ = 'principals' principal_backref_name = 'in_event_acls' principal_for = 'Event' unique_columns = ('event_id', ) allow_emails = True allow_networks = True @declared_attr def __table_args__(cls): return auto_table_args(cls, schema='events') #: The ID of the acl entry id = db.Column(db.Integer, primary_key=True) #: The ID of the associated event event_id = db.Column(db.Integer, db.ForeignKey('events.events.id'), nullable=False, index=True) # relationship backrefs: # - event (Event.acl_entries) @return_ascii def __repr__(self): return format_repr(self, 'id', 'event_id', 'principal', read_access=False, full_access=False, roles=[])
class DesignerImageFile(StoredFileMixin, db.Model): __tablename__ = 'designer_image_files' __table_args__ = {'schema': 'fossir'} # Image files are not version-controlled version_of = None #: The ID of the file id = db.Column( db.Integer, primary_key=True ) #: The designer template the image belongs to template_id = db.Column( db.Integer, db.ForeignKey('fossir.designer_templates.id'), nullable=False, index=True ) template = db.relationship( 'DesignerTemplate', lazy=False, foreign_keys=template_id, backref=db.backref( 'images', cascade='all, delete-orphan', lazy=True ) ) @property def download_url(self): return url_for('designer.download_image', self) @property def locator(self): return dict(self.template.locator, image_id=self.id, filename=self.filename) def _build_storage_path(self): path_segments = ['designer_templates', strict_unicode(self.template.id), 'images'] self.assign_id() filename = '{}-{}'.format(self.id, self.filename) path = posixpath.join(*(path_segments + [filename])) return config.ATTACHMENT_STORAGE, path @return_ascii def __repr__(self): return '<DesignerImageFile({}, {}, {}, {})>'.format( self.id, self.template_id, self.filename, self.content_type )
class StaticSite(StoredFileMixin, db.Model): """Static site for an fossir event.""" __tablename__ = 'static_sites' __table_args__ = {'schema': 'events'} # StoredFileMixin settings add_file_date_column = False file_required = False #: Entry ID id = db.Column(db.Integer, primary_key=True) #: ID of the event event_id = db.Column(db.Integer, db.ForeignKey('events.events.id'), index=True, nullable=False) #: The state of the static site (a :class:`StaticSiteState` member) state = db.Column(PyIntEnum(StaticSiteState), default=StaticSiteState.pending, nullable=False) #: The date and time the static site was requested requested_dt = db.Column(UTCDateTime, default=now_utc, nullable=False) #: ID of the user who created the static site creator_id = db.Column(db.Integer, db.ForeignKey('users.users.id'), index=True, nullable=False) #: The user who created the static site creator = db.relationship('User', lazy=False, backref=db.backref('static_sites', lazy='dynamic')) #: The Event this static site is associated with event = db.relationship('Event', lazy=True, backref=db.backref('static_sites', lazy='dynamic')) @property def locator(self): return {'confId': self.event_id, 'id': self.id} def _build_storage_path(self): path_segments = ['event', strict_unicode(self.event.id), 'static'] self.assign_id() filename = '{}-{}'.format(self.id, self.filename) path = posixpath.join(*(path_segments + [filename])) return config.STATIC_SITE_STORAGE, path @return_ascii def __repr__(self): return format_repr(self, 'id', 'event_id', 'state')
class SettingsBase(object): """Base class for any kind of setting tables""" id = db.Column(db.Integer, primary_key=True) module = db.Column(db.String, index=True, nullable=False) name = db.Column(db.String, index=True, nullable=False) @strict_classproperty @staticmethod def __auto_table_args(): return (db.CheckConstraint('module = lower(module)', 'lowercase_module'), db.CheckConstraint('name = lower(name)', 'lowercase_name')) @classmethod def delete(cls, module, *names, **kwargs): if not names: return cls.find(cls.name.in_(names), cls.module == module, **kwargs).delete(synchronize_session='fetch') db.session.flush() cls._clear_cache() @classmethod def delete_all(cls, module, **kwargs): cls.find(module=module, **kwargs).delete() db.session.flush() cls._clear_cache() @classmethod def _get_cache(cls, kwargs): if not has_request_context(): # disable the cache by always returning an empty one return defaultdict(dict), False key = (cls, frozenset(kwargs.viewitems())) try: return g.global_settings_cache[key], True except AttributeError: # no cache at all g.global_settings_cache = cache = dict() cache[key] = rv = defaultdict(dict) return rv, False except KeyError: # no cache for this settings class / kwargs return g.global_settings_cache.setdefault(key, defaultdict(dict)), False @staticmethod def _clear_cache(): if has_request_context(): g.pop('global_settings_cache', None)
class RoomAttribute(db.Model): __tablename__ = 'room_attributes' __table_args__ = (db.UniqueConstraint('name', 'location_id'), { 'schema': 'roombooking' }) id = db.Column(db.Integer, primary_key=True) parent_id = db.Column(db.Integer, db.ForeignKey('roombooking.room_attributes.id')) name = db.Column(db.String, nullable=False, index=True) title = db.Column(db.String, nullable=False) location_id = db.Column(db.Integer, db.ForeignKey('roombooking.locations.id'), nullable=False) type = db.Column(db.String, nullable=False) is_required = db.Column(db.Boolean, nullable=False) is_hidden = db.Column(db.Boolean, nullable=False) children = db.relationship('RoomAttribute', backref=db.backref('parent', remote_side=[id])) # relationship backrefs: # - location (Location.attributes) # - parent (RoomAttribute.children) # - room_associations (RoomAttributeAssociation.attribute) @return_ascii def __repr__(self): return u'<RoomAttribute({}, {}, {})>'.format(self.id, self.name, self.location.name)
class Photo(db.Model): __tablename__ = 'photos' __table_args__ = {'schema': 'roombooking'} id = db.Column(db.Integer, primary_key=True) thumbnail = db.Column(db.LargeBinary, nullable=True) data = db.Column(db.LargeBinary, nullable=True) # relationship backrefs: # - room (Room.photo) @return_ascii def __repr__(self): return u'<Photo({0})>'.format(self.id)
class Break(DescriptionMixin, ColorMixin, LocationMixin, db.Model): __tablename__ = 'breaks' __auto_table_args = {'schema': 'events'} location_backref_name = 'breaks' default_colors = ColorTuple('#202020', '#90c0f0') possible_render_modes = {RenderMode.markdown} default_render_mode = RenderMode.markdown @declared_attr def __table_args__(cls): return auto_table_args(cls) id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String, nullable=False) duration = db.Column(db.Interval, nullable=False) # relationship backrefs: # - timetable_entry (TimetableEntry.break_) def can_access(self, user): parent = self.timetable_entry.parent if parent: return parent.object.can_access(user) else: return self.event.can_access(user) @property def event(self): return self.timetable_entry.event if self.timetable_entry else None @property def location_parent(self): return (self.event if self.timetable_entry.parent_id is None else self.timetable_entry.parent.session_block) @property def start_dt(self): return self.timetable_entry.start_dt if self.timetable_entry else None @property def end_dt(self): return self.timetable_entry.start_dt + self.duration if self.timetable_entry else None @return_ascii def __repr__(self): return format_repr(self, 'id', _text=self.title) @locator_property def locator(self): return dict(self.event.locator, break_id=self.id)
class PaperCompetence(db.Model): __tablename__ = 'competences' __table_args__ = (db.UniqueConstraint('user_id', 'event_id'), {'schema': 'event_paper_reviewing'}) id = db.Column( db.Integer, primary_key=True ) user_id = db.Column( db.Integer, db.ForeignKey('users.users.id'), index=True, nullable=False ) event_id = db.Column( db.Integer, db.ForeignKey('events.events.id'), index=True, nullable=False ) competences = db.Column( ARRAY(db.String), nullable=False, default=[] ) event = db.relationship( 'Event', lazy=True, backref=db.backref( 'paper_competences', cascade='all, delete-orphan', lazy=True ) ) user = db.relationship( 'User', lazy=True, backref=db.backref( 'paper_competences', lazy='dynamic' ) ) @return_ascii def __repr__(self): return format_repr(self, 'id', 'user_id', 'event_id', _text=', '.join(self.competences))
def contribution_field_id(cls): return db.Column( db.Integer, db.ForeignKey('events.contribution_fields.id', name='fk_{}_contribution_field'.format(cls.__tablename__)), primary_key=True, index=True )
def revision_id(cls): return db.Column( db.Integer, db.ForeignKey('event_paper_reviewing.revisions.id'), index=True, nullable=False )
def access_key(cls): if cls.allow_access_key: return db.Column( db.String, nullable=False, default='' )
def event_id(cls): return db.Column( db.Integer, db.ForeignKey('events.events.id'), nullable=False, index=True )
def abstract_id(cls): return db.Column( db.Integer, db.ForeignKey('event_abstracts.abstracts.id'), index=True, nullable=False )
class CategorySetting(JSONSettingsBase, db.Model): @strict_classproperty @staticmethod def __auto_table_args(): return (db.Index(None, 'category_id', 'module', 'name'), db.Index(None, 'category_id', 'module'), db.UniqueConstraint('category_id', 'module', 'name'), { 'schema': 'categories' }) @declared_attr def __table_args__(cls): return auto_table_args(cls) category_id = db.Column(db.Integer, db.ForeignKey('categories.categories.id'), index=True, nullable=False) category = db.relationship('Category', lazy=True, backref=db.backref('settings', lazy='dynamic')) @return_ascii def __repr__(self): return '<CategorySetting({}, {}, {}, {!r})>'.format( self.category_id, self.module, self.name, self.value)
class IPNetwork(db.Model): __tablename__ = 'ip_networks' __table_args__ = {'schema': 'fossir'} group_id = db.Column(db.Integer, db.ForeignKey('fossir.ip_network_groups.id'), primary_key=True, autoincrement=False) network = db.Column(PyIPNetwork, primary_key=True, nullable=False) # relationship backrefs: # - group (IPNetworkGroup._networks) @return_ascii def __repr__(self): return format_repr(self, 'group_id', 'network')
class UserSetting(JSONSettingsBase, db.Model): """User-specific settings""" __table_args__ = (db.Index(None, 'user_id', 'module', 'name'), db.Index(None, 'user_id', 'module'), db.UniqueConstraint('user_id', 'module', 'name'), db.CheckConstraint('module = lower(module)', 'lowercase_module'), db.CheckConstraint('name = lower(name)', 'lowercase_name'), { 'schema': 'users' }) user_id = db.Column(db.Integer, db.ForeignKey('users.users.id'), nullable=False, index=True) user = db.relationship('User', lazy=True, backref=db.backref('_all_settings', lazy='dynamic', cascade='all, delete-orphan')) @return_ascii def __repr__(self): return '<UserSetting({}, {}, {}, {!r})>'.format( self.user_id, self.module, self.name, self.value)
class ContributionFieldValueBase(db.Model): __abstract__ = True #: The name of the backref on the `ContributionField` contribution_field_backref_name = None data = db.Column( JSON, nullable=False ) @declared_attr def contribution_field_id(cls): return db.Column( db.Integer, db.ForeignKey('events.contribution_fields.id', name='fk_{}_contribution_field'.format(cls.__tablename__)), primary_key=True, index=True ) @declared_attr def contribution_field(cls): return db.relationship( 'ContributionField', lazy=False, backref=db.backref( cls.contribution_field_backref_name, cascade='all, delete-orphan', lazy=True ) ) @property def friendly_data(self): return self.contribution_field.field.get_friendly_value(self.data)
def own_no_access_contact(cls): if cls.allow_no_access_contact: return db.Column( 'no_access_contact', db.String, nullable=False, default='' )
class LocalGroup(db.Model): __tablename__ = 'groups' @declared_attr def __table_args__(cls): return (db.Index('ix_uq_groups_name_lower', db.func.lower(cls.name), unique=True), { 'schema': 'users' }) #: the unique id of the group id = db.Column(db.Integer, primary_key=True) #: the name of the group name = db.Column(db.String, nullable=False, index=True) #: the local groups this user belongs to members = db.relationship( 'User', secondary='users.group_members', lazy=True, collection_class=set, backref=db.backref('local_groups', lazy=True, collection_class=set), ) # relationship backrefs: # - in_attachment_acls (AttachmentPrincipal.local_group) # - in_attachment_folder_acls (AttachmentFolderPrincipal.local_group) # - in_blocking_acls (BlockingPrincipal.local_group) # - in_category_acls (CategoryPrincipal.local_group) # - in_contribution_acls (ContributionPrincipal.local_group) # - in_event_acls (EventPrincipal.local_group) # - in_event_settings_acls (EventSettingPrincipal.local_group) # - in_session_acls (SessionPrincipal.local_group) # - in_settings_acls (SettingPrincipal.local_group) @return_ascii def __repr__(self): return '<LocalGroup({}, {})>'.format(self.id, self.name) @property def proxy(self): """Returns a GroupProxy wrapping this group""" from fossir.modules.groups import GroupProxy return GroupProxy(self.id, _group=self)
class ReferenceModelBase(db.Model): __abstract__ = True #: The name of the backref on the `ReferenceType` reference_backref_name = None id = db.Column(db.Integer, primary_key=True) value = db.Column(db.String, nullable=False) @declared_attr def reference_type_id(cls): return db.Column(db.Integer, db.ForeignKey('fossir.reference_types.id'), nullable=False, index=True) @declared_attr def reference_type(cls): return db.relationship('ReferenceType', lazy=False, backref=db.backref(cls.reference_backref_name, cascade='all, delete-orphan', lazy=True)) @property def url(self): """The URL of the referenced entity. ``None`` if no URL template is defined. """ template = self.reference_type.url_template if not template: return None # XXX: Should the value be urlencoded? return template.replace('{value}', self.value) @property def urn(self): """The URN of the referenced entity. ``None`` if no scheme is defined. """ scheme = self.reference_type.scheme if not scheme: return None return '{}:{}'.format(scheme, self.value)
def created_dt(cls): """The date/time when the file was uploaded""" if not cls.add_file_date_column: return None return db.Column( UTCDateTime, nullable=not cls.file_required, default=now_utc )
def render_mode(cls): # Only add the column if there's a choice # between several alternatives if len(cls.possible_render_modes) > 1: return db.Column(PyIntEnum(RenderMode), default=cls.default_render_mode, nullable=False) else: return cls.default_render_mode
class BlockingPrincipal(PrincipalMixin, db.Model): __tablename__ = 'blocking_principals' __table_args__ = {'schema': 'roombooking'} principal_backref_name = 'in_blocking_acls' unique_columns = ('blocking_id', ) id = db.Column(db.Integer, primary_key=True) blocking_id = db.Column(db.Integer, db.ForeignKey('roombooking.blockings.id'), nullable=False) # relationship backrefs: # - blocking (Blocking._allowed) @return_ascii def __repr__(self): return '<BlockingPrincipal({}, {}, {})>'.format( self.id, self.blocking_id, self.principal)
class LegacyImageMapping(db.Model): """Legacy image id mapping Legacy images had event-unique numeric ids. Using this mapping we can resolve old ones to their new id. """ __tablename__ = 'legacy_image_id_map' __table_args__ = {'schema': 'events'} event_id = db.Column( db.Integer, db.ForeignKey('events.events.id'), primary_key=True, index=True, autoincrement=False ) legacy_image_id = db.Column( db.Integer, primary_key=True, index=True, autoincrement=False ) image_id = db.Column( db.Integer, db.ForeignKey('events.image_files.id'), nullable=False, index=True ) image = db.relationship( 'ImageFile', lazy=False, backref=db.backref( 'legacy_mapping', cascade='all, delete-orphan', uselist=False, lazy=True ) ) @return_ascii def __repr__(self): return format_repr(self, 'legacy_image_id', 'image_id')
class AbstractFile(StoredFileMixin, db.Model): __tablename__ = 'files' __table_args__ = {'schema': 'event_abstracts'} # StoredFileMixin settings add_file_date_column = False id = db.Column(db.Integer, primary_key=True) abstract_id = db.Column(db.Integer, db.ForeignKey('event_abstracts.abstracts.id'), nullable=False, index=True) abstract = db.relationship('Abstract', lazy=True, backref=db.backref( 'files', lazy=True, cascade='all, delete-orphan')) @property def locator(self): return dict(self.abstract.locator, file_id=self.id, filename=self.filename) def _build_storage_path(self): self.abstract.assign_id() path_segments = [ 'event', strict_unicode(self.abstract.event.id), 'abstracts', strict_unicode(self.abstract.id) ] self.assign_id() filename = '{}-{}'.format(self.id, self.filename) path = posixpath.join(*(path_segments + [filename])) return config.ATTACHMENT_STORAGE, path @return_ascii def __repr__(self): return format_repr(self, 'id', 'abstract_id', content_type=None, _text=text_to_repr(self.filename))