RESPONSIBILTIY'S COOL
This commit is contained in:
parent
fffb38bc9a
commit
0f80fc74a0
|
@ -1 +1,3 @@
|
||||||
from .auth import require_auth
|
from .auth import require_auth
|
||||||
|
from .interval import decompose_interval
|
||||||
|
from .interval import SCALES as interval_scales
|
||||||
|
|
|
@ -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
|
|
@ -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 ###
|
16
model.py
16
model.py
|
@ -4,6 +4,7 @@ from app import db
|
||||||
|
|
||||||
from twitter import Twitter, OAuth
|
from twitter import Twitter, OAuth
|
||||||
import secrets
|
import secrets
|
||||||
|
from lib import decompose_interval
|
||||||
|
|
||||||
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())
|
||||||
|
@ -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'
|
__tablename__ = 'accounts'
|
||||||
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_younger = db.Column(db.Interval)
|
policy_keep_latest = db.Column(db.Integer, server_default='0')
|
||||||
# policy_keep_latest = db.Column(db.Integer)
|
|
||||||
# policy_delete_every = db.Column(db.Interval)
|
|
||||||
policy_ignore_favourites = db.Column(db.Boolean, server_default='TRUE')
|
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_display_name = db.Column(db.String)
|
||||||
remote_screen_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):
|
def post_count(self):
|
||||||
return Post.query.filter(Post.author_id == self.id).count()
|
return Post.query.filter(Post.author_id == self.id).count()
|
||||||
|
|
||||||
|
|
||||||
|
class Account(Account, db.Model):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OAuthToken(db.Model, TimestampMixin):
|
class OAuthToken(db.Model, TimestampMixin):
|
||||||
__tablename__ = 'oauth_tokens'
|
__tablename__ = 'oauth_tokens'
|
||||||
|
|
||||||
|
|
16
routes.py
16
routes.py
|
@ -2,6 +2,7 @@ from app import app
|
||||||
from flask import render_template, url_for, redirect, request, g, Response
|
from flask import render_template, url_for, redirect, request, g, Response
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import lib.twitter
|
import lib.twitter
|
||||||
|
import lib
|
||||||
from lib import require_auth
|
from lib import require_auth
|
||||||
from model import Account, Session, Post, TwitterArchive
|
from model import Account, Session, Post, TwitterArchive
|
||||||
from app import db
|
from app import db
|
||||||
|
@ -46,7 +47,7 @@ def twitter_login_step2():
|
||||||
db.session.add(session)
|
db.session.add(session)
|
||||||
db.session.commit()
|
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 = Response(status=302, headers={"location": url_for('index')})
|
||||||
resp.set_cookie('forget_sid', session.id,
|
resp.set_cookie('forget_sid', session.id,
|
||||||
|
@ -63,7 +64,7 @@ def upload_tweet_archive():
|
||||||
db.session.add(ta)
|
db.session.add(ta)
|
||||||
db.session.commit()
|
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')
|
return render_template('upload_tweet_archive.html')
|
||||||
|
|
||||||
|
@ -71,13 +72,20 @@ def upload_tweet_archive():
|
||||||
@require_auth
|
@require_auth
|
||||||
def settings():
|
def settings():
|
||||||
if request.method == 'POST':
|
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:
|
if attr in request.form:
|
||||||
setattr(g.viewer.account, attr, request.form[attr])
|
setattr(g.viewer.account, attr, request.form[attr])
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return render_template('settings.html')
|
return render_template('settings.html', scales=lib.interval_scales)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
9
tasks.py
9
tasks.py
|
@ -10,8 +10,17 @@ from datetime import timedelta, datetime
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
from io import BytesIO, TextIOWrapper
|
from io import BytesIO, TextIOWrapper
|
||||||
import json
|
import json
|
||||||
|
from kombu import Queue
|
||||||
|
|
||||||
app = Celery('tasks', broker=flaskapp.config['CELERY_BROKER'], task_serializer='pickle')
|
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))
|
@app.task(autoretry_for=(TwitterError, URLError))
|
||||||
def fetch_acc(id, cursor=None):
|
def fetch_acc(id, cursor=None):
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% macro interval_input(obj, attrname, scales) -%}
|
||||||
|
|
||||||
|
<input type=number name={{attrname}}_significand
|
||||||
|
value={{obj[attrname + '_significand']}}
|
||||||
|
style='max-width:8ch' min=0 step=1>
|
||||||
|
<select name={{attrname}}_scale>
|
||||||
|
{%- for scale in scales %}
|
||||||
|
<option value="{{scale[1].total_seconds()}}"
|
||||||
|
{{- ' selected' if scale[1] == obj[attrname + '_scale'] -}}
|
||||||
|
>{{scale[0]}}</option>
|
||||||
|
{% endfor -%}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
{%- endmacro %}
|
|
@ -9,21 +9,19 @@
|
||||||
<label><input type=radio name=policy_enabled value=true {{ "checked" if g.viewer.account.policy_enabled }}> Enabled</label>
|
<label><input type=radio name=policy_enabled value=true {{ "checked" if g.viewer.account.policy_enabled }}> Enabled</label>
|
||||||
<label><input type=radio name=policy_enabled value=false {{ "checked" if not g.viewer.account.policy_enabled }}> Disabled</label>
|
<label><input type=radio name=policy_enabled value=false {{ "checked" if not g.viewer.account.policy_enabled }}> Disabled</label>
|
||||||
</p>
|
</p>
|
||||||
{#
|
{%- from 'lib/interval.html' import interval_input %}
|
||||||
|
<p>Delete one post every
|
||||||
|
{{interval_input(g.viewer.account, 'policy_delete_every', scales)}}
|
||||||
|
</p>
|
||||||
<p>Keep posts less than
|
<p>Keep posts less than
|
||||||
<input type=number name=policy_keep_younger min=0 step=1 max=30>
|
{{interval_input(g.viewer.account, 'policy_keep_younger', scales)}}
|
||||||
<select name=policy_keep_younger_multiplier>
|
|
||||||
<option name=1>seconds</option>
|
|
||||||
<option name=60>minutes</option>
|
|
||||||
<option name=3600>hours</option>
|
|
||||||
<option name=86400>days</option>
|
|
||||||
<option name=2635200>months</option>
|
|
||||||
<option name=31536000>years</option>
|
|
||||||
</select>
|
|
||||||
old
|
old
|
||||||
</p>
|
</p>
|
||||||
#}
|
<p>Keep my
|
||||||
<p>Keep posts that you have favourited:
|
<input type=number name=policy_keep_latest min=0 step=1 style='max-width:8ch' value={{g.viewer.account.policy_keep_latest}}>
|
||||||
|
latest posts
|
||||||
|
</p>
|
||||||
|
<p>Keep posts that I have favourited
|
||||||
<label><input type=radio name=policy_ignore_favourites value=true {{ "checked" if g.viewer.account.policy_ignore_favourites }}> Yes</label>
|
<label><input type=radio name=policy_ignore_favourites value=true {{ "checked" if g.viewer.account.policy_ignore_favourites }}> Yes</label>
|
||||||
<label><input type=radio name=policy_ignore_favourites value=false {{ "checked" if not g.viewer.account.policy_ignore_favourites }}> No</label>
|
<label><input type=radio name=policy_ignore_favourites value=false {{ "checked" if not g.viewer.account.policy_ignore_favourites }}> No</label>
|
||||||
</p>
|
</p>
|
||||||
|
|
Loading…
Reference in New Issue