diff --git a/lib/__init__.py b/lib/__init__.py index 96e2497..4b0da44 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -1 +1,3 @@ from .auth import require_auth +from .interval import decompose_interval +from .interval import SCALES as interval_scales diff --git a/lib/interval.py b/lib/interval.py new file mode 100644 index 0000000..e222650 --- /dev/null +++ b/lib/interval.py @@ -0,0 +1,50 @@ +from datetime import timedelta + +SCALES = [ + ('seconds', timedelta(seconds=1)), + ('minutes', timedelta(minutes=1)), + ('hours', timedelta(hours=1)), + ('days', timedelta(days=1)), + ('months', timedelta(days=30)), + ('years', timedelta(days=365)), +] + +def decompose_interval(attrname): + scales = [scale[1] for scale in SCALES] + scales.reverse() + + def decorator(cls): + scl_name = '{}_scale'.format(attrname) + sig_name = '{}_significand'.format(attrname) + + @property + def scale(self): + for m in scales: + if getattr(self, attrname) % m == timedelta(0): + return m + + return timedelta(seconds=1) + + @scale.setter + def scale(self, value): + print(value) + if(type(value) != timedelta): + value = timedelta(seconds=float(value)) + print(value) + setattr(self, attrname, getattr(self, sig_name) * value) + + @property + def significand(self): + return int(getattr(self, attrname) / getattr(self, scl_name)) + + @significand.setter + def significand(self, value): + setattr(self, attrname, int(value) * getattr(self, scl_name)) + + + setattr(cls, scl_name, scale) + setattr(cls, sig_name, significand) + + return cls + + return decorator diff --git a/migrations/versions/9fab742962ef_.py b/migrations/versions/9fab742962ef_.py new file mode 100644 index 0000000..af79f73 --- /dev/null +++ b/migrations/versions/9fab742962ef_.py @@ -0,0 +1,32 @@ +"""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 ### diff --git a/model.py b/model.py index fc64403..e59263b 100644 --- a/model.py +++ b/model.py @@ -4,6 +4,7 @@ from app import db from twitter import Twitter, OAuth import secrets +from lib import decompose_interval class TimestampMixin(object): created_at = db.Column(db.DateTime, server_default=db.func.now()) @@ -33,15 +34,17 @@ class RemoteIDMixin(object): -class Account(db.Model, TimestampMixin, RemoteIDMixin): +@decompose_interval('policy_delete_every') +@decompose_interval('policy_keep_younger') +class Account(TimestampMixin, RemoteIDMixin): __tablename__ = 'accounts' id = db.Column(db.String, primary_key=True) policy_enabled = db.Column(db.Boolean, server_default='FALSE', nullable=False) - # policy_keep_younger = db.Column(db.Interval) - # policy_keep_latest = db.Column(db.Integer) - # policy_delete_every = db.Column(db.Interval) + policy_keep_latest = db.Column(db.Integer, server_default='0') policy_ignore_favourites = db.Column(db.Boolean, server_default='TRUE') + policy_delete_every = db.Column(db.Interval, server_default='0', default=0) + policy_keep_younger = db.Column(db.Interval, server_default='0', default=0) remote_display_name = db.Column(db.String) remote_screen_name = db.Column(db.String) @@ -61,6 +64,11 @@ class Account(db.Model, TimestampMixin, RemoteIDMixin): def post_count(self): return Post.query.filter(Post.author_id == self.id).count() + +class Account(Account, db.Model): + pass + + class OAuthToken(db.Model, TimestampMixin): __tablename__ = 'oauth_tokens' diff --git a/routes.py b/routes.py index 2f22d40..12ec85b 100644 --- a/routes.py +++ b/routes.py @@ -2,6 +2,7 @@ from app import app from flask import render_template, url_for, redirect, request, g, Response from datetime import datetime import lib.twitter +import lib from lib import require_auth from model import Account, Session, Post, TwitterArchive from app import db @@ -46,7 +47,7 @@ def twitter_login_step2(): db.session.add(session) db.session.commit() - tasks.fetch_acc.s(token.account_id).delay() + tasks.fetch_acc.s(token.account_id).apply_async(routing_key='high') resp = Response(status=302, headers={"location": url_for('index')}) resp.set_cookie('forget_sid', session.id, @@ -63,7 +64,7 @@ def upload_tweet_archive(): db.session.add(ta) db.session.commit() - tasks.import_twitter_archive.s(ta.id).apply_async() + tasks.import_twitter_archive.s(ta.id).apply_async(routing_key='high') return render_template('upload_tweet_archive.html') @@ -71,13 +72,20 @@ def upload_tweet_archive(): @require_auth def settings(): if request.method == 'POST': - for attr in ('policy_enabled', 'policy_ignore_favourites'): + for attr in ('policy_enabled', + 'policy_ignore_favourites', + 'policy_keep_latest', + 'policy_delete_every_significand', + 'policy_delete_every_scale', + 'policy_keep_younger_significand', + 'policy_keep_younger_scale', + ): if attr in request.form: setattr(g.viewer.account, attr, request.form[attr]) db.session.commit() - return render_template('settings.html') + return render_template('settings.html', scales=lib.interval_scales) diff --git a/tasks.py b/tasks.py index 92083f0..2a7f0ce 100644 --- a/tasks.py +++ b/tasks.py @@ -10,8 +10,17 @@ from datetime import timedelta, datetime from zipfile import ZipFile from io import BytesIO, TextIOWrapper import json +from kombu import Queue app = Celery('tasks', broker=flaskapp.config['CELERY_BROKER'], task_serializer='pickle') +app.conf.task_queues = ( + Queue('default', routing_key='celery'), + Queue('high_prio', routing_key='high'), + Queue('higher_prio', routing_key='higher'), +) +app.conf.task_default_queue = 'default' +app.conf.task_default_exchange = 'celery' +app.conf.task_default_exchange_type = 'direct' @app.task(autoretry_for=(TwitterError, URLError)) def fetch_acc(id, cursor=None): diff --git a/templates/lib/interval.html b/templates/lib/interval.html new file mode 100644 index 0000000..18e709c --- /dev/null +++ b/templates/lib/interval.html @@ -0,0 +1,15 @@ +{% macro interval_input(obj, attrname, scales) -%} + + + + + +{%- endmacro %} diff --git a/templates/settings.html b/templates/settings.html index c935f64..36d4c19 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -9,21 +9,19 @@

- {# + {%- from 'lib/interval.html' import interval_input %} +

Delete one post every + {{interval_input(g.viewer.account, 'policy_delete_every', scales)}} +

Keep posts less than - - + {{interval_input(g.viewer.account, 'policy_keep_younger', scales)}} old

- #} -

Keep posts that you have favourited: +

Keep my + + latest posts +

+

Keep posts that I have favourited