class MastodonAuth(db.Model): __tablename__ = "mastodon_auths" id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) user = db.relationship("User", back_populates="mastodon_auth") created_at = db.Column(db.DateTime, nullable=False) app_id = db.Column(db.Integer, db.ForeignKey('mastodon_apps.id'), nullable=False) app = db.relationship("MastodonApp", back_populates="auths") generated_on = db.Column(db.DateTime, nullable=True) access_token = db.Column(db.String(255), nullable=True) mastodon_id = db.Column(db.Integer, nullable=True) username = db.Column(db.String(255), nullable=True) def __init__(self, user_id, app_id): self.user_id = user_id self.app_id = app_id self.created_at = datetime.datetime.now() def update_account(self, access_token, mastodon_id, username): self.access_token = access_token self.generated_on = datetime.datetime.now() self.mastodon_id = mastodon_id self.username = username
class AdditiveRule(Rule): __mapper_args__ = {'polymorphic_identity': 'additive'} additive_links = db.relationship("AdditiveRuleLink", back_populates="rule", cascade="delete, delete-orphan") post_associations = db.relationship("PostAdditiveRule", back_populates="rule", cascade="delete, delete-orphan") def __init__(self, creator_user_id, creator_display_name, title, description, long_description, shareable, source, link, level_names): super(AdditiveRule, self).__init__(creator_user_id, creator_display_name, title, description, long_description, shareable, source, link, 'additive') self.level_display_names = level_names def serialize(self): rule_dict = super(AdditiveRule, self).serialize() rule_dict.update({ 'level_display_names': self.level_display_names, }) if self.additive_links: links = [] for link in self.additive_links: if not any(l['name'] == link.display_name for l in links): links.append(link.serialize()) rule_dict.update({'links': links}) return rule_dict
class AdditiveRuleLink(db.Model): __tablename__ = "additive_rule_links" id = db.Column(db.Integer, primary_key=True, autoincrement=True) rule_id = db.Column(db.Integer, db.ForeignKey('rules.id'), nullable=False) source = db.Column(db.String(255), nullable=False) uri = db.Column(db.String(255), nullable=False) display_name = db.Column(db.String(255), nullable=False) display_uri = db.Column(db.String(255)) level = db.Column(db.Integer, nullable=False) created_at = db.Column(db.DateTime, nullable=False) last_modified = db.Column(db.DateTime, nullable=False) rule = db.relationship("AdditiveRule", back_populates="additive_links") db.PrimaryKeyConstraint('rule_id', 'uri') def __init__(self, rule_id, source, uri, level, name, display_uri): self.rule_id = rule_id self.source = source self.uri = uri self.display_name = name self.display_uri = display_uri self.level = level self.created_at = datetime.datetime.now() self.last_modified = datetime.datetime.now() def serialize(self): return { 'id': self.id, 'uri': self.display_uri or self.uri, 'name': self.display_name, 'level': self.level, }
class Rule(db.Model): __tablename__ = "rules" id = db.Column(db.Integer, primary_key=True, autoincrement=True) creator_user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) creator_display_name = db.Column(db.String(255), nullable=False) title = db.Column(db.String(255), nullable=False) description = db.Column(db.String(255), nullable=False) long_description = db.Column(db.String(510)) source = db.Column(db.String(255), nullable=False) shareable = db.Column(db.Boolean, nullable=False) link = db.Column(db.String(255)) exclude_terms = db.Column(ARRAY(db.String(255))) level_display_names = db.Column(ARRAY(db.String(255))) control_display_name = db.Column(db.String(255)) type = db.Column(db.String(255), nullable=False) # e.g. additive, keyword created_at = db.Column(db.DateTime, nullable=False) last_modified = db.Column(db.DateTime, nullable=False) user_associations = db.relationship("UserRule", back_populates="rule", cascade="delete, delete-orphan") __mapper_args__ = { 'polymorphic_on': type, } def __init__(self, creator_user_id, creator_display_name, title, description, long_description, shareable, source, link, rule_type): self.creator_user_id = creator_user_id self.creator_display_name = creator_display_name self.title = title self.description = description self.long_description = long_description self.shareable = shareable self.source = source self.link = link self.created_at = datetime.datetime.now() self.last_modified = datetime.datetime.now() self.type = rule_type def serialize(self): return { 'id': self.id, 'creator_display_name': self.creator_display_name, 'title': self.title, 'description': self.description, 'long_description': self.long_description, 'link': self.link, 'type': self.type, }
class UserRule(db.Model): __tablename__ = "users_rules" id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) rule_id = db.Column(db.Integer, db.ForeignKey('rules.id'), nullable=False) enabled = db.Column(db.Boolean, nullable=False) levels = db.Column(ARRAY(db.Integer)) created_at = db.Column(db.DateTime, nullable=False) last_modified = db.Column(db.DateTime, nullable=False) rule = db.relationship("Rule", back_populates="user_associations") user = db.relationship("User", back_populates="rule_associations") db.UniqueConstraint('user_id', 'rule_id') def __init__(self, user_id, rule_id, enabled=False, levels=None): self.user_id = user_id self.rule_id = rule_id self.levels = levels self.enabled = enabled self.created_at = datetime.datetime.now() self.last_modified = datetime.datetime.now()
class TwitterAuth(db.Model): __tablename__ = "twitter_auths" id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) user = db.relationship("User", back_populates="twitter_auth") generated_on = db.Column(db.DateTime, nullable=False) oauth_token = db.Column(db.String(255), nullable=False) oauth_token_secret = db.Column(db.String(255), nullable=False) def __init__(self, user_id, oauth_token, oauth_token_secret): self.user_id = user_id self.generated_on = datetime.datetime.now() self.oauth_token = oauth_token self.oauth_token_secret = oauth_token_secret
class PostAdditiveRule(db.Model): __tablename__ = "posts_additive_rules" id = db.Column(db.Integer, primary_key=True, autoincrement=True) rule_id = db.Column(db.Integer, db.ForeignKey('rules.id', ondelete='CASCADE'), nullable=False) post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False) level = db.Column(db.Integer, nullable=False) created_at = db.Column(db.DateTime, nullable=False) last_modified = db.Column(db.DateTime, nullable=False) db.PrimaryKeyConstraint('rule_id', 'post_id') post = db.relationship("Post", back_populates="rule_associations") rule = db.relationship("AdditiveRule", back_populates="post_associations") def __init__(self, rule_id, post_id, level): self.rule_id = rule_id self.post_id = post_id self.level = level self.created_at = datetime.datetime.now() self.last_modified = datetime.datetime.now()
class Settings(db.Model): __tablename__ = "user_settings" id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) user = db.relationship("User", back_populates="settings") rudeness_min = db.Column(db.Float, db.CheckConstraint('rudeness_min>=0'), default=0) rudeness_max = db.Column(db.Float, db.CheckConstraint('rudeness_max<=1'), default=1) gender_filter_on = db.Column(db.Boolean, default=False) gender_female_per = db.Column( db.Integer, db.CheckConstraint('gender_female_per>=0 AND gender_female_per<=100'), default=50) include_corporate = db.Column(db.Boolean, default=True) virality_min = db.Column(db.Float, db.CheckConstraint('virality_min>=0'), default=0) virality_max = db.Column(db.Float, db.CheckConstraint('virality_max<=1'), default=1) seriousness_min = db.Column(db.Float, db.CheckConstraint('seriousness_min>=0'), default=0) seriousness_max = db.Column(db.Float, db.CheckConstraint('seriousness_max<=1'), default=1) rudeness_ck = db.CheckConstraint('rudeness_max>rudeness_min') virality_ck = db.CheckConstraint('virality_max>virality_min') seriousness_ck = db.CheckConstraint('seriousness_max>seriousness_min') def as_dict(self): d = {c.name: getattr(self, c.name) for c in self.__table__.columns} return d def update(self, settings_dict): self.rudeness_min = settings_dict['rudeness_min'] self.rudeness_max = settings_dict['rudeness_max'] self.gender_filter_on = settings_dict['gender_filter_on'] self.gender_female_per = settings_dict['gender_female_per'] self.include_corporate = settings_dict['include_corporate'] self.virality_min = settings_dict['virality_min'] self.virality_max = settings_dict['virality_max'] self.seriousness_min = settings_dict['seriousness_min'] self.seriousness_max = settings_dict['seriousness_max']
class FacebookAuth(db.Model): __tablename__ = "facebook_auths" id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) user = db.relationship("User", back_populates="facebook_auth") generated_on = db.Column(db.DateTime, nullable=False) access_token = db.Column(db.String(255), nullable=False) token_type = db.Column(db.String(255), nullable=False) expires_in = db.Column(db.DateTime, nullable=False) def __init__(self, user_id, facebook_auth_data): self.user_id = user_id self.generated_on = datetime.datetime.now() self.access_token = facebook_auth_data['access_token'] self.token_type = facebook_auth_data['token_type'] self.expires_in = self.generated_on + datetime.timedelta(seconds=int(facebook_auth_data['expires_in']))
class MastodonApp(db.Model): __tablename__ = "mastodon_apps" id = db.Column(db.Integer, primary_key=True, autoincrement=True) domain = db.Column(db.String(255), nullable=False) client_id = db.Column(db.String(255), nullable=False) client_secret = db.Column(db.String(255), nullable=False) created_at = db.Column(db.DateTime, nullable=False) auths = db.relationship("MastodonAuth", back_populates="app") def __init__(self, domain, client_id, client_secret): self.domain = domain self.client_id = client_id self.client_secret = client_secret self.created_at = datetime.datetime.now() def base_url(self): return 'https://{domain}'.format(domain=self.domain)
class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.String(255), unique=True, nullable=False) password = db.Column(db.String(255), nullable=False) registered_on = db.Column(db.DateTime, nullable=False) completed_registration = db.Column(db.Boolean, default=False) facebook_name = db.Column(db.String(255)) facebook_picture_url = db.Column(db.String(255)) facebook_id = db.Column(db.String(255)) facebook_email = db.Column(db.String(255)) twitter_name = db.Column(db.String(255)) twitter_id = db.Column(db.String(255)) facebook_auth = db.relationship("FacebookAuth", uselist=False, back_populates="user", cascade="delete, delete-orphan") twitter_auth = db.relationship("TwitterAuth", uselist=False, back_populates="user", cascade="delete, delete-orphan") twitter_authorized = db.Column(db.Boolean, nullable=False, default=False) facebook_authorized = db.Column(db.Boolean, nullable=False, default=False) twitter_data = db.Column(db.JSON) facebook_data = db.Column(db.JSON) political_affiliation = db.Column(db.Enum(PoliticsEnum), default=PoliticsEnum.center) posts = db.relationship("Post", secondary=post_associations_table, lazy='dynamic') settings = db.relationship("Settings", uselist=False, back_populates="user") def __init__(self, email, password): self.email = email self.password = bcrypt.generate_password_hash(password) self.registered_on = datetime.datetime.now() settings = Settings() self.settings = settings def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id def get_names(self): d = {c.name: getattr(self, c.name) for c in self.__table__.columns if c.name not in [ 'password', 'id', 'political_affiliation', 'posts', 'settings', 'facebook_data']} d['political_affiliation'] = self.political_affiliation.value d['avatar'] = self.twitter_data['profile_image_url_https'] if self.twitter_data else self.facebook_picture_url return d def set_facebook_data(self, data): self.facebook_name = data['name'] if 'name' in data else '' self.facebook_email = data['email'] if 'email' in data else '' self.facebook_id = data['id'] if 'picture' in data: if 'data' in data['picture']: if 'url' in data['picture']['data']: self.facebook_picture_url = data['picture']['data']['url'] self.facebook_data = data self.facebook_authorized = True db.session.commit() def set_twitter_data(self, id, name, data): self.twitter_name = name self.twitter_id = id self.twitter_data = data self.twitter_authorized = True db.session.commit() def set_political_affiliation(self, political_affiliation): self.political_affiliation = PoliticsEnum(int(political_affiliation)) db.session.commit() def complete_registration(self): self.completed_registration = True db.session.commit() def __repr__(self): return '<User {0}>'.format(self.email)
class Post(db.Model): __tablename__ = "posts" id = db.Column(db.Integer, primary_key=True, autoincrement=True) original_id = db.Column(db.String(40), nullable=False) content = db.Column(db.JSON, nullable=False) source = db.Column(db.String(255), nullable=False) retrieved_at = db.Column(db.DateTime, nullable=False) created_at = db.Column(db.DateTime) # filters toxicity = db.Column(db.Float) gender = db.Column(db.Enum(GenderEnum)) is_corporate = db.Column(db.Boolean) virality_count = db.Column(db.Integer) has_link = db.Column(db.Boolean) news_score = db.Column(db.Float) db.UniqueConstraint('source_id', 'source', name='post_id') rule_associations = db.relationship("PostAdditiveRule", back_populates="post", cascade="delete, delete-orphan") rules = None __mapper_args__ = { 'polymorphic_on': source, } def __init__(self, original_id, source, content): self.original_id = original_id self.source = source self.content = content self.retrieved_at = datetime.datetime.now() self.rules = None if source == 'twitter': self.created_at = datetime.datetime.strptime( content['created_at'], '%a %b %d %H:%M:%S +0000 %Y') # TODO: fix this eventually # pylint: disable=len-as-condition self.has_link = len(content['entities']['urls'] ) > 0 # 'possibly_sensitive' in content elif source == 'facebook': self.created_at = datetime.datetime.strptime( content['created_time'], '%Y-%m-%dT%H:%M:%S+0000') self.has_link = content['type'] == 'link' elif source == 'mastodon': self.created_at = content['created_at'] if content['card'] and content['card']['type']: self.has_link = content['card']['type'].lower() == 'link' else: self.has_link = False def as_dict(self): d = { c.name: getattr(self, c.name) for c in self.__table__.columns if c.name not in ['gender'] } d['gender'] = str(self.gender) # using the cache saves time over db lookups if self.rules: d['rules'] = self.rules return d def cache_rule(self, rule): """Cache a list of rule dicts that this post has associated with it for serializing later.""" if self.rules is None: self.rules = [] self.rules.append(rule) def get_text(self): raise NotImplementedError def has_toxicity_rate(self): return self.toxicity is not None def update_content(self, content): self.content.update(content) def update_toxicity(self, score): self.toxicity = score db.session.commit() def update_gender_corporate(self, gender, corporate): self.gender = gender self.is_corporate = corporate db.session.commit() def has_gender_corporate(self): return (self.gender is not None) and (self.is_corporate is not None) def get_precomputed_gender(self): return None def has_precomputed_corporate(self): return None def has_virality(self): return self.virality_count is not None def has_news_score(self): return self.news_score is not None def has_already_been_analyzed(self): return self.has_virality() and self.has_news_score() and self.has_gender_corporate()\ and self.has_toxicity_rate() def get_urls(self): raise NotImplementedError def get_author_name(self): raise NotImplementedError def get_likes_count(self): raise NotImplementedError def get_comments_count(self): raise NotImplementedError def get_shares_count(self): raise NotImplementedError
class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.String(255), unique=True, nullable=False) _password = db.Column('password', db.String(255), nullable=False) registered_on = db.Column(db.DateTime, nullable=False) last_login = db.Column(db.DateTime, nullable=True) last_post_fetch = db.Column(db.DateTime, nullable=True) last_active = db.Column(db.DateTime, nullable=True) facebook_name = db.Column(db.String(255)) facebook_picture_url = db.Column(db.String(255)) facebook_id = db.Column(db.String(255)) facebook_email = db.Column(db.String(255)) twitter_name = db.Column(db.String(255)) twitter_id = db.Column(db.String(255)) facebook_auth = db.relationship("FacebookAuth", uselist=False, back_populates="user", cascade="delete, delete-orphan") twitter_auth = db.relationship("TwitterAuth", uselist=False, back_populates="user", cascade="delete, delete-orphan") mastodon_auth = db.relationship("MastodonAuth", uselist=False, back_populates="user", cascade="delete, delete-orphan") twitter_authorized = db.Column(db.Boolean, nullable=False, default=False) facebook_authorized = db.Column(db.Boolean, nullable=False, default=False) mastodon_authorized = db.Column(db.Boolean, nullable=False, default=False, server_default='f') twitter_data = db.Column(db.JSON) facebook_data = db.Column(db.JSON) hide_tracking = db.Column(db.Boolean, nullable=True, default=False) posts = db.relationship("Post", secondary=post_associations_table, lazy='dynamic') settings = db.relationship("Settings", uselist=False, back_populates="user") rule_associations = db.relationship("UserRule", back_populates="user", cascade="delete, delete-orphan") def __init__(self, email, password): self.email = email self.password = password self.registered_on = datetime.datetime.now() self.last_login = datetime.datetime.now() settings = Settings() self.settings = settings @hybrid_property def password(self): # pylint: disable=method-hidden return self._password @password.setter def password(self, plaintext): self._password = bcrypt.generate_password_hash(plaintext).decode( 'utf-8') def check_password(self, plaintext): return bcrypt.check_password_hash(self.password, plaintext) def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id def get_last_login(self): return self.last_login def get_last_post_fetch(self): return self.last_post_fetch def serialize(self): d = { c.name: getattr(self, c.name) for c in self.__table__.columns if c.name not in ['password', 'id', 'posts', 'settings', 'facebook_data'] } d['mastodon_name'] = '' d['mastodon_domain'] = '' if self.mastodon_auth: d['mastodon_name'] = self.mastodon_auth.username d['mastodon_domain'] = self.mastodon_auth.app.domain d['avatar'] = self.twitter_data[ 'profile_image_url_https'] if self.twitter_data else self.facebook_picture_url d['hide_tracking'] = False if self.hide_tracking is None else self.hide_tracking return d def update_last_login(self): self.last_login = datetime.datetime.now() db.session.commit() def update_last_post_fetch(self): self.last_post_fetch = datetime.datetime.now() db.session.commit() def update_last_active(self): self.last_active = datetime.datetime.now() db.session.commit() def set_facebook_data(self, data): self.facebook_name = data['name'] if 'name' in data else '' self.facebook_email = data['email'] if 'email' in data else '' self.facebook_id = data['id'] if 'picture' in data: if 'data' in data['picture']: if 'url' in data['picture']['data']: self.facebook_picture_url = data['picture']['data']['url'] self.facebook_data = data self.facebook_authorized = True db.session.commit() def set_twitter_data(self, twitter_id, name, data): self.twitter_name = name self.twitter_id = twitter_id self.twitter_data = data self.twitter_authorized = True db.session.commit() def __repr__(self): return '<User {0}>'.format(self.email)