class User(Base): __tablename__ = 'users' user_id = db.Column(db.Integer, db.Sequence('user_id_seq'), primary_key=True, nullable=False) discord_id = db.Column(db.String(24), unique=True, nullable=False) name = db.Column(db.String(Limits.NAME, collation='NOCASE')) aliases = db.relationship('UserAlias', back_populates='user', lazy='joined') group_id = db.Column(db.Integer, nullable=True) records = db.relationship('Record', foreign_keys='Record.user_id', back_populates='user') authorship = db.relationship('Record', foreign_keys='Record.author_id', back_populates='author') def __repr__(self): return ("<User(user_id={:d}, discord_id={!r}, name={!r}, aliases=[{}], " \ "group_id={!s})>") \ .format(self.user_id, self.discord_id, self.name, ', '.join([repr(a) for a in self.aliases]), self.group_id) def __str__(self): return "{1} (*{0:d})".format(self.user_id, self.name)
class User(Base): __tablename__ = 'users' user_id = db.Column(db.Integer, db.Sequence('user_id_seq'), primary_key=True, nullable=False) discord_id = db.Column(db.String(24), unique=True, nullable=False) name = db.Column(db.String(Limits.NAME, collation='NOCASE')) username = db.Column(db.String(Limits.NAME, collation='NOCASE')) quotes = db.relationship('Quote', order_by="Quote.timestamp", foreign_keys='Quote.author_id', back_populates='author') saved_quotes = db.relationship('Quote', order_by='Quote.timestamp', foreign_keys='Quote.saved_by_id', back_populates='saved_by') # not used for now: disallow user from being quoted is_blocked = db.Column(db.Boolean, nullable=False, default=False) def __repr__(self): return "<User(user_id={:d}, discord_id={!r}, name={!r}, username={!r}>" \ .format(self.user_id, self.discord_id, self.name, self.username) def __str__(self): return "{}".format(self.name) @property def mention(self): return user_mention(self.discord_id)
class Record(Base): __tablename__ = 'records' record_id = db.Column(db.Integer, db.Sequence('record_id_seq'), primary_key=True) timestamp = db.Column(db.TIMESTAMP, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) user = db.relationship('User', lazy='joined', foreign_keys=[user_id]) author_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) author = db.relationship('User', lazy='joined', foreign_keys=[author_id]) type = db.Column(db.Enum(RecordType), nullable=False) expires = db.Column(db.DateTime, nullable=True) body = db.Column(db.String(2048), nullable=False) is_removed = db.Column(db.Boolean, nullable=False, default=False, server_default="FALSE") def __repr__(self): return "<Record(record_id={:d}, is_removed={!s})>" \ .format(self.record_id, self.is_removed) def __str__(self): raise NotImplementedError() # TODO
class Badge(Base): __tablename__ = 'badges' MAX_MESSAGE_LEN = 1000 id = db.Column(db.Integer, db.Sequence('badge_id_seq'), primary_key=True) message_id = db.Column(db.String(24), nullable=False, unique=True) timestamp = db.Column(db.TIMESTAMP, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) user = db.relationship('User', lazy='joined', foreign_keys=[user_id]) from_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) from_user = db.relationship('User', lazy='joined', foreign_keys=[from_id]) badge = db.Column(db.Enum(BadgeType), nullable=False) reason = db.Column(db.String(MAX_MESSAGE_LEN), nullable=False) _REPR = "<Badge(id={:d}, message_id={}, timestamp={}, user_id={}, badge={.name}, message={!r})>" def __repr__(self): return self._REPR.format( self.id if self.id is not None else -1, self.message_id, self.timestamp.isoformat(' '), self.user_id, self.badge, (self.reason[:97] + '...') if len(self.reason) > 100 else self.reason ) def __str__(self): raise NotImplementedError()
class Quote(Base): __tablename__ = 'quotes' MAX_MESSAGE_LEN = 1000 quote_id = db.Column(db.Integer, db.Sequence('quote_id_seq'), primary_key=True) timestamp = db.Column(db.TIMESTAMP, nullable=False) author_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) author = db.relationship('User', lazy='joined', foreign_keys=[author_id]) saved_by_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) saved_by = db.relationship('User', lazy='joined', foreign_keys=[saved_by_id]) channel_id = db.Column(db.String(24), nullable=False) message = db.Column(db.String(MAX_MESSAGE_LEN), nullable=False) def get_index(self): return self.author.quotes.index(self) def __repr__(self): return "<Quote(quote_id={:d}, timestamp={}, author_id={}, channel_id={}, message={})>" \ .format(self.quote_id, self.timestamp.isoformat(' '), self.author_id, self.channel_id, self.message[:97] + '...' if len(self.message) > 100 else self.message) def __str__(self): raise NotImplementedError()
class User(Base): __tablename__ = 'users' MAX_ABOUT_WORDS = 70 MAX_TITLE = 256 user_id = db.Column(db.Integer, db.Sequence('user_id_seq'), primary_key=True, nullable=False) discord_id = db.Column(db.String(24), unique=True, nullable=False, index=True) active_project_id = db.Column(db.Integer, db.ForeignKey('projects.project_id'), nullable=True) active_project = db.relationship('Project', foreign_keys=[active_project_id], uselist=False, post_update=True) projects = db.relationship('Project', foreign_keys='Project.user_id', order_by='Project.project_id', back_populates='user') max_projects = db.Column(db.Integer, nullable=True) about = db.Column(db.String(MAX_ABOUT_WORDS), nullable=True) type_id = db.Column(db.Integer, db.ForeignKey('type.id'), nullable=True, index=True) type = db.relationship('ProjectType', lazy='joined') genre_id = db.Column(db.Integer, db.ForeignKey('genre.id'), nullable=True, index=True) genre = db.relationship('Genre', lazy='joined') url = db.Column(db.String(MAX_TITLE), nullable=True) def __repr__(self): return 'User<{:d}, discord_id={}>'.format(self.user_id, self.discord_id) def __str__(self): return repr(self) @property def mention(self): return user_mention(self.discord_id) def find_project(self, search_title) -> 'Project': """ Find a project whose title contains the argument (case-insensitive). :raises KeyError: project not found """ # noinspection PyTypeChecker for project in self.projects: if project.title_contains(search_title): return project else: raise KeyError(search_title) def max_projects_eff(self, default: int=None) -> int: """ Check the maximum projects the user can have. If the user does not have a set maximum, the default value is returned. """ return self.max_projects if self.max_projects is not None else default def can_add_projects(self, default_max: int=None) -> bool: """ Check whether the user can add new projects. If the user does not have a set maximum, the default value is used. """ eff_max = self.max_projects_eff(default_max) # noinspection PyTypeChecker return eff_max is None or len(self.projects) < eff_max
class User(Base): __tablename__ = 'users' user_id = db.Column(db.Integer, db.Sequence('user_id_seq'), primary_key=True, nullable=False) discord_id = db.Column(db.String(24), unique=True, nullable=False, index=True) project_type = db.Column(db.Enum(ProjectType), default=ProjectType.words) check_ins = db.relationship('CheckIn', foreign_keys='CheckIn.user_id', back_populates='user') badges = db.relationship('Badge', foreign_keys='Badge.user_id', back_populates='user') is_exempt = db.Column(db.Boolean, default=False) def __repr__(self): return "<User(user_id={:d}, discord_id={!r}, project_type={}, is_exempt={!s}>" \ .format(self.user_id, self.discord_id, self.project_type.name, self.is_exempt) def __str__(self): return repr(self) @property def mention(self): return user_mention(self.discord_id)
class Project(Base): __tablename__ = 'projects' MAX_TITLE = 256 MAX_SHORT = 32 MAX_FIELD = 1000 MAX_PITCH_WORDS = 70 project_id = db.Column(db.Integer, db.Sequence('project_id_seq'), primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) user = db.relationship('User', lazy='joined', foreign_keys='Project.user_id', back_populates='projects') whois_message_id = db.Column(db.String(24), unique=True, nullable=True, index=True) title = db.Column(db.String(MAX_TITLE, collation='NOCASE'), nullable=False) type_id = db.Column(db.Integer, db.ForeignKey('type.id'), nullable=False, index=True) type = db.relationship('ProjectType', lazy='joined') genre_id = db.Column(db.Integer, db.ForeignKey('genre.id'), nullable=False, index=True) genre = db.relationship('Genre', lazy='joined') subgenre = db.Column(db.String(MAX_SHORT), nullable=True) url = db.Column(db.String(MAX_TITLE), nullable=True) follow_role_id = db.Column(db.String(24), unique=True, nullable=True, index=True) pitch = db.Column(db.String(MAX_FIELD), nullable=False) description = db.Column(db.String(MAX_FIELD), nullable=True) def __repr__(self): return 'Project<{:d}, user_id={:d}, title={!r}>'\ .format(self.project_id, self.user_id, self.title) def __str__(self): raise NotImplementedError() def title_contains(self, query) -> bool: """ Check if the title contains the argument (case-insensitive). """ return query.lower() in self.title.lower()
class ProjectType(Base): __tablename__ = 'type' MAX_NAME = 32 id = db.Column(db.Integer, db.Sequence('type_id_seq'), primary_key=True) name = db.Column(db.String(MAX_NAME, collation='NOCASE'), unique=True, nullable=False, index=True) role_id = db.Column(db.String(24), nullable=True, index=True) projects = db.relationship('Project', back_populates='type') def __repr__(self): return 'ProjectType<{:d}, {}, {}>'.format(self.id, self.name, self.role_id) def __str__(self): return self.name def discord_str(self): return "{} ({})" \ .format(self.name, role_mention(self.role_id) if self.role_id else 'No role')
class UserAlias(Base): __tablename__ = 'aliases' __table_args__ = (db.UniqueConstraint('alias_id', 'name', 'user_id'), ) alias_id = db.Column(db.Integer, db.Sequence('alias_id_seq'), primary_key=True, nullable=False) name = db.Column(db.String(Limits.NAME, collation='NOCASE'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False, index=True) user = db.relationship('User') def __repr__(self): return "<Alias(alias_id={:d}, user_id={:d}, name={!r})>" \ .format(self.alias_id, self.user_id, self.name) def __str__(self): return "{1} (alias *{0:d})".format(self.user_id, self.name)
class CheckIn(Base): __tablename__ = 'check_ins' MAX_MESSAGE_LEN = 1000 id = db.Column(db.Integer, db.Sequence('checkin_id_seq'), primary_key=True) timestamp = db.Column(db.TIMESTAMP, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False) user = db.relationship('User', lazy='joined', foreign_keys=[user_id]) word_count = db.Column(db.Integer, nullable=False) project_type = db.Column(db.Enum(ProjectType), nullable=False) message = db.Column(db.String(MAX_MESSAGE_LEN), nullable=False) def __repr__(self): return ("<CheckIn(id={:d}, timestamp={}, user_id={}, word_count={}, " "project_type={.name}, message={!r})>") \ .format(self.id if self.id is not None else -1, self.timestamp.isoformat(' '), self.user_id, self.word_count, self.project_type, (self.message[:97] + '...') if len(self.message) > 100 else self.message) def __str__(self): raise NotImplementedError()
class JoinRecord(Base): """ Record of guild join/parts. """ __tablename__ = 'guild_joins' join_id = db.Column(db.Integer, db.Sequence('join_id_seq'), primary_key=True) timestamp = db.Column(db.TIMESTAMP, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False, index=True) user = db.relationship('User', lazy='joined', foreign_keys=[user_id]) direction = db.Column(db.Enum(JoinDirection), nullable=False, default=JoinDirection.join) def __repr__(self): return "<JoinRecord(join_id={:d}, timestamp={}, user_id={:d}, direction={.name})>" \ .format(self.join_id, format_timestamp(self.timestamp), self.user_id, self.direction) def __str__(self): raise NotImplementedError() # TODO