clean up and sanitise model for release

This commit is contained in:
codl 2017-08-03 11:51:37 +02:00
parent 3537bd34ab
commit 1562182e33
No known key found for this signature in database
GPG Key ID: 6CD7C8891ED1233A
14 changed files with 111 additions and 328 deletions

View File

@ -37,9 +37,9 @@ def receive_verifier(oauth_token, oauth_verifier, consumer_key=None, consumer_se
acct = Account(twitter_id = remote_acct['id_str']) acct = Account(twitter_id = remote_acct['id_str'])
acct = db.session.merge(acct) acct = db.session.merge(acct)
acct.remote_display_name = remote_acct['name'] acct.display_name = remote_acct['name']
acct.remote_screen_name = remote_acct['screen_name'] acct.screen_name = remote_acct['screen_name']
acct.remote_avatar_url = remote_acct['profile_image_url_https'] acct.avatar_url = remote_acct['profile_image_url_https']
new_token.account = acct new_token.account = acct
db.session.commit() db.session.commit()

View File

@ -1,32 +0,0 @@
"""add twitter archives
Revision ID: 0cb99099c2dd
Revises: 92ffc9941fd9
Create Date: 2017-07-30 23:13:48.949949
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '0cb99099c2dd'
down_revision = '92ffc9941fd9'
branch_labels = None
depends_on = None
def upgrade():
op.create_table('twitter_archives',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('account_id', sa.String(), nullable=False),
sa.Column('body', sa.LargeBinary(), nullable=False),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_twitter_archives_account_id_accounts')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_twitter_archives'))
)
def downgrade():
op.drop_table('twitter_archives')

View File

@ -1,28 +0,0 @@
"""empty message
Revision ID: 711770097f06
Revises: e46c5fd68037
Create Date: 2017-07-31 17:54:11.215759
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '711770097f06'
down_revision = 'e46c5fd68037'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('policy_ignore_favourites', sa.Boolean(), server_default='TRUE', nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('accounts', 'policy_ignore_favourites')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""empty message
Revision ID: 7379bfac4379
Revises: 995890c26959
Create Date: 2017-08-01 23:35:17.924428
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '7379bfac4379'
down_revision = '995890c26959'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('posts', sa.Column('favourite', sa.Boolean(), server_default='FALSE', nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('posts', 'favourite')
# ### end Alembic commands ###

View File

@ -0,0 +1,82 @@
"""init
Revision ID: 7afc95e24778
Revises:
Create Date: 2017-08-03 11:51:08.190298
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '7afc95e24778'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table('accounts',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('id', sa.String(), nullable=False),
sa.Column('policy_enabled', sa.Boolean(), server_default='FALSE', nullable=False),
sa.Column('policy_keep_latest', sa.Integer(), server_default='0', nullable=False),
sa.Column('policy_keep_favourites', sa.Boolean(), server_default='TRUE', nullable=False),
sa.Column('policy_delete_every', sa.Interval(), server_default='0', nullable=False),
sa.Column('policy_keep_younger', sa.Interval(), server_default='0', nullable=False),
sa.Column('display_name', sa.String(), nullable=True),
sa.Column('screen_name', sa.String(), nullable=True),
sa.Column('avatar_url', sa.String(), nullable=True),
sa.Column('last_fetch', sa.DateTime(), server_default='epoch', nullable=True),
sa.Column('last_delete', sa.DateTime(), server_default='epoch', nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('pk_accounts'))
)
op.create_table('oauth_tokens',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('token', sa.String(), nullable=False),
sa.Column('token_secret', sa.String(), nullable=False),
sa.Column('account_id', sa.String(), nullable=True),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_oauth_tokens_account_id_accounts'), onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('token', name=op.f('pk_oauth_tokens'))
)
op.create_table('posts',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('id', sa.String(), nullable=False),
sa.Column('body', sa.String(), nullable=True),
sa.Column('author_id', sa.String(), nullable=False),
sa.Column('favourite', sa.Boolean(), server_default='FALSE', nullable=False),
sa.ForeignKeyConstraint(['author_id'], ['accounts.id'], name=op.f('fk_posts_author_id_accounts'), onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_posts'))
)
op.create_table('sessions',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('id', sa.String(), nullable=False),
sa.Column('account_id', sa.String(), nullable=False),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_sessions_account_id_accounts'), onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_sessions'))
)
op.create_table('twitter_archives',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('account_id', sa.String(), nullable=False),
sa.Column('body', sa.LargeBinary(), nullable=False),
sa.Column('chunks', sa.Integer(), nullable=True),
sa.Column('chunks_successful', sa.Integer(), server_default='0', nullable=False),
sa.Column('chunks_failed', sa.Integer(), server_default='0', nullable=False),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_twitter_archives_account_id_accounts'), onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_twitter_archives'))
)
def downgrade():
op.drop_table('twitter_archives')
op.drop_table('sessions')
op.drop_table('posts')
op.drop_table('oauth_tokens')
op.drop_table('accounts')

View File

@ -1,66 +0,0 @@
"""empty message
Revision ID: 92ffc9941fd9
Revises:
Create Date: 2017-07-29 12:31:47.687234
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '92ffc9941fd9'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('accounts',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('id', sa.String(), nullable=False),
sa.Column('remote_display_name', sa.String(), nullable=True),
sa.Column('remote_screen_name', sa.String(), nullable=True),
sa.Column('remote_avatar_url', sa.String(), nullable=True),
sa.Column('last_fetch', sa.DateTime(), server_default='epoch', nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('pk_accounts'))
)
op.create_table('oauth_tokens',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('token', sa.String(), nullable=False),
sa.Column('token_secret', sa.String(), nullable=False),
sa.Column('account_id', sa.String(), nullable=True),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_oauth_tokens_account_id_accounts')),
sa.PrimaryKeyConstraint('token', name=op.f('pk_oauth_tokens'))
)
op.create_table('posts',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('id', sa.String(), nullable=False),
sa.Column('body', sa.String(), nullable=True),
sa.Column('author_id', sa.String(), nullable=True),
sa.ForeignKeyConstraint(['author_id'], ['accounts.id'], name=op.f('fk_posts_author_id_accounts')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_posts'))
)
op.create_table('sessions',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('id', sa.String(), nullable=False),
sa.Column('account_id', sa.String(), nullable=True),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], name=op.f('fk_sessions_account_id_accounts')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_sessions'))
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('sessions')
op.drop_table('posts')
op.drop_table('oauth_tokens')
op.drop_table('accounts')
# ### end Alembic commands ###

View File

@ -1,30 +0,0 @@
"""empty message
Revision ID: 995890c26959
Revises: e036b007017c
Create Date: 2017-08-01 23:24:22.223674
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '995890c26959'
down_revision = 'e036b007017c'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('policy_keep_favourites', sa.Boolean(), server_default='TRUE', nullable=True))
op.drop_column('accounts', 'policy_ignore_favourites')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('policy_ignore_favourites', sa.BOOLEAN(), server_default=sa.text('true'), autoincrement=False, nullable=True))
op.drop_column('accounts', 'policy_keep_favourites')
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""empty message
Revision ID: 9fab742962ef
Revises: 711770097f06
Create Date: 2017-08-01 00:33:59.183437
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '9fab742962ef'
down_revision = '711770097f06'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('policy_delete_every', sa.Interval(), server_default='0', nullable=True))
op.add_column('accounts', sa.Column('policy_keep_latest', sa.Integer(), server_default='0', nullable=True))
op.add_column('accounts', sa.Column('policy_keep_younger', sa.Interval(), server_default='0', nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('accounts', 'policy_keep_younger')
op.drop_column('accounts', 'policy_keep_latest')
op.drop_column('accounts', 'policy_delete_every')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""empty message
Revision ID: e036b007017c
Revises: 9fab742962ef
Create Date: 2017-08-01 22:45:28.450097
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e036b007017c'
down_revision = '9fab742962ef'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('last_delete', sa.DateTime(), server_default='epoch', nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('accounts', 'last_delete')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""empty message
Revision ID: e46c5fd68037
Revises: f11fe22d6169
Create Date: 2017-07-31 17:10:09.833883
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e46c5fd68037'
down_revision = 'f11fe22d6169'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('policy_enabled', sa.Boolean(), server_default='FALSE', nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('accounts', 'policy_enabled')
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""empty message
Revision ID: f11fe22d6169
Revises: 0cb99099c2dd
Create Date: 2017-07-31 01:07:39.741008
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'f11fe22d6169'
down_revision = '0cb99099c2dd'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('twitter_archives', sa.Column('chunks', sa.Integer(), nullable=True))
op.add_column('twitter_archives', sa.Column('chunks_failed', sa.Integer(), server_default='0', nullable=True))
op.add_column('twitter_archives', sa.Column('chunks_successful', sa.Integer(), server_default='0', nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('twitter_archives', 'chunks_successful')
op.drop_column('twitter_archives', 'chunks_failed')
op.drop_column('twitter_archives', 'chunks')
# ### end Alembic commands ###

View File

@ -8,8 +8,8 @@ from lib import decompose_interval
from datetime import timedelta from datetime import timedelta
class TimestampMixin(object): class TimestampMixin(object):
created_at = db.Column(db.DateTime, server_default=db.func.now()) created_at = db.Column(db.DateTime, server_default=db.func.now(), nullable=False)
updated_at = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now()) updated_at = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now(), nullable=False)
def touch(self): def touch(self):
self.updated_at=db.func.now() self.updated_at=db.func.now()
@ -26,7 +26,7 @@ class RemoteIDMixin(object):
if not self.id: if not self.id:
return None return None
if self.service != "twitter": if self.service != "twitter":
raise Exception("wrong service bucko") raise Exception("tried to get twitter id for a {} {}".format(self.service, type(self)))
return self.id.split(":")[1] return self.id.split(":")[1]
@twitter_id.setter @twitter_id.setter
@ -42,14 +42,14 @@ class Account(TimestampMixin, RemoteIDMixin):
id = db.Column(db.String, primary_key=True) id = db.Column(db.String, primary_key=True)
policy_enabled = db.Column(db.Boolean, server_default='FALSE', nullable=False) policy_enabled = db.Column(db.Boolean, server_default='FALSE', nullable=False)
policy_keep_latest = db.Column(db.Integer, server_default='0') policy_keep_latest = db.Column(db.Integer, server_default='0', nullable=False)
policy_keep_favourites = db.Column(db.Boolean, server_default='TRUE') policy_keep_favourites = db.Column(db.Boolean, server_default='TRUE', nullable=False)
policy_delete_every = db.Column(db.Interval, server_default='0') policy_delete_every = db.Column(db.Interval, server_default='0', nullable=False)
policy_keep_younger = db.Column(db.Interval, server_default='0') policy_keep_younger = db.Column(db.Interval, server_default='0', nullable=False)
remote_display_name = db.Column(db.String) display_name = db.Column(db.String)
remote_screen_name = db.Column(db.String) screen_name = db.Column(db.String)
remote_avatar_url = db.Column(db.String) avatar_url = db.Column(db.String)
last_fetch = db.Column(db.DateTime, server_default='epoch') last_fetch = db.Column(db.DateTime, server_default='epoch')
last_delete = db.Column(db.DateTime, server_default='epoch') last_delete = db.Column(db.DateTime, server_default='epoch')
@ -57,6 +57,9 @@ class Account(TimestampMixin, RemoteIDMixin):
def touch_fetch(self): def touch_fetch(self):
self.last_fetch = db.func.now() self.last_fetch = db.func.now()
def touch_delete(self):
self.last_delete = db.func.now()
@db.validates('policy_keep_younger', 'policy_delete_every') @db.validates('policy_keep_younger', 'policy_delete_every')
def validate_intervals(self, key, value): def validate_intervals(self, key, value):
if not (value == timedelta(0) or value >= timedelta(minutes=1)): if not (value == timedelta(0) or value >= timedelta(minutes=1)):
@ -68,7 +71,7 @@ class Account(TimestampMixin, RemoteIDMixin):
# backref: posts # backref: posts
def __repr__(self): def __repr__(self):
return f"<Account({self.id}, {self.remote_screen_name}, {self.remote_display_name})>" return f"<Account({self.id}, {self.screen_name}, {self.display_name})>"
def post_count(self): def post_count(self):
return Post.query.with_parent(self).count() return Post.query.with_parent(self).count()
@ -84,15 +87,17 @@ class OAuthToken(db.Model, TimestampMixin):
token = db.Column(db.String, primary_key=True) token = db.Column(db.String, primary_key=True)
token_secret = db.Column(db.String, nullable=False) token_secret = db.Column(db.String, nullable=False)
account_id = db.Column(db.String, db.ForeignKey('accounts.id')) account_id = db.Column(db.String, db.ForeignKey('accounts.id', ondelete='CASCADE', onupdate='CASCADE'), nullable=True)
account = db.relationship(Account, backref=db.backref('tokens', order_by=lambda: db.desc(OAuthToken.created_at))) account = db.relationship(Account, backref=db.backref('tokens', order_by=lambda: db.desc(OAuthToken.created_at)))
# note: account_id is nullable here because we don't know what account a token is for
# until we call /account/verify_credentials with it
class Session(db.Model, TimestampMixin): class Session(db.Model, TimestampMixin):
__tablename__ = 'sessions' __tablename__ = 'sessions'
id = db.Column(db.String, primary_key=True, default=lambda: secrets.token_urlsafe()) id = db.Column(db.String, primary_key=True, default=lambda: secrets.token_urlsafe())
account_id = db.Column(db.String, db.ForeignKey('accounts.id')) account_id = db.Column(db.String, db.ForeignKey('accounts.id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
account = db.relationship(Account, lazy='joined') account = db.relationship(Account, lazy='joined')
class Post(db.Model, TimestampMixin, RemoteIDMixin): class Post(db.Model, TimestampMixin, RemoteIDMixin):
@ -101,7 +106,7 @@ class Post(db.Model, TimestampMixin, RemoteIDMixin):
id = db.Column(db.String, primary_key=True) id = db.Column(db.String, primary_key=True)
body = db.Column(db.String) body = db.Column(db.String)
author_id = db.Column(db.String, db.ForeignKey('accounts.id')) author_id = db.Column(db.String, db.ForeignKey('accounts.id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
author = db.relationship(Account, author = db.relationship(Account,
backref=db.backref('posts', order_by=lambda: db.desc(Post.created_at))) backref=db.backref('posts', order_by=lambda: db.desc(Post.created_at)))
@ -110,16 +115,16 @@ class Post(db.Model, TimestampMixin, RemoteIDMixin):
def __repr__(self): def __repr__(self):
snippet = self.body snippet = self.body
if len(snippet) > 20: if len(snippet) > 20:
snippet = snippet[:19] + "" snippet = snippet[:19] + ""
return '<Post ({}, "{}", Author: {})>'.format(self.id, snippet, self.author_id) return '<Post ({}, "{}", Author: {})>'.format(self.id, snippet, self.author_id)
class TwitterArchive(db.Model, TimestampMixin): class TwitterArchive(db.Model, TimestampMixin):
__tablename__ = 'twitter_archives' __tablename__ = 'twitter_archives'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
account_id = db.Column(db.String, db.ForeignKey('accounts.id'), nullable=False) account_id = db.Column(db.String, db.ForeignKey('accounts.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False)
account = db.relationship(Account, backref=db.backref('twitter_archives', order_by=lambda: db.desc(TwitterArchive.id))) account = db.relationship(Account, backref=db.backref('twitter_archives', order_by=lambda: db.desc(TwitterArchive.id)))
body = db.deferred(db.Column(db.LargeBinary, nullable=False)) body = db.deferred(db.Column(db.LargeBinary, nullable=False))
chunks = db.Column(db.Integer) chunks = db.Column(db.Integer)
chunks_successful = db.Column(db.Integer, server_default='0') chunks_successful = db.Column(db.Integer, server_default='0', nullable=False)
chunks_failed = db.Column(db.Integer, server_default='0') chunks_failed = db.Column(db.Integer, server_default='0', nullable=False)

View File

@ -135,7 +135,7 @@ def delete_from_account(account_id):
post = random.choice(list((post for post in posts if not account.policy_keep_favourites or not post.favourite))) post = random.choice(list((post for post in posts if not account.policy_keep_favourites or not post.favourite)))
print("deleting {}".format(post)) print("deleting {}".format(post))
lib.twitter.delete(post) lib.twitter.delete(post)
account.last_delete = db.func.now() account.touch_delete()
db.session.commit() db.session.commit()

View File

@ -2,8 +2,8 @@
{% if g.viewer %} {% if g.viewer %}
<p>Hello, <p>Hello,
<img src="{{g.viewer.account.remote_avatar_url}}" style='height:1.5em; border-radius:100%; transform:translateY(25%);'/> <img src="{{g.viewer.account.avatar_url}}" style='height:1.5em; border-radius:100%; transform:translateY(25%);'/>
{{g.viewer.account.remote_display_name}}! {{g.viewer.account.display_name}}!
<a href="{{url_for('settings')}}">Settings</a> <a href="{{url_for('settings')}}">Settings</a>
<a href="{{url_for('logout')}}">Log out</a> <a href="{{url_for('logout')}}">Log out</a>
</p> </p>