diff --git a/model.py b/model.py index 8a3c83e..06377e0 100644 --- a/model.py +++ b/model.py @@ -77,6 +77,20 @@ class Account(TimestampMixin, RemoteIDMixin): def post_count(self): return Post.query.with_parent(self).count() + def estimate_eligible_for_delete(self): + """ + this is an estimation because we do not know if favourite status has changed since last time a post was refreshed + and it is unfeasible to refresh every single post every time we need to know how many posts are eligible to delete + """ + latest_n_posts = db.session.query(Post.id).with_parent(self).order_by(db.desc(Post.created_at)).limit(self.policy_keep_latest) + query = Post.query.with_parent(self).\ + filter(Post.created_at + self.policy_keep_younger <= db.func.now()).\ + filter(~Post.id.in_(latest_n_posts)) + if(self.policy_keep_favourites): + query = query.filter_by(favourite = False) + return query.count() + + class Account(Account, db.Model): diff --git a/routes.py b/routes.py index c4b3928..48d085a 100644 --- a/routes.py +++ b/routes.py @@ -1,6 +1,6 @@ from app import app from flask import render_template, url_for, redirect, request, g, Response -from datetime import datetime +from datetime import datetime, timedelta import lib.twitter import lib from lib import require_auth @@ -101,6 +101,20 @@ def enable(): # i.e. about to instantly delete a lot of posts, # or when enabling for the first time (last_delete is >1 year in the past) + risky = False + if not 'confirm' in request.form and not g.viewer.account.policy_enabled: + if g.viewer.account.policy_delete_every == timedelta(0): + approx = g.viewer.account.estimate_eligible_for_delete() + return render_template('warn.html', message=f"""You've set the time between deleting posts to 0. Every post that matches your expiration rules will be deleted within minutes. + { ("That's about " + str(approx) + " posts.") if approx > 0 else "" } + Go ahead?""") + if g.viewer.account.last_delete < datetime.now() - timedelta(days=365): + return render_template('warn.html', message="""Once you enable Forget, posts that match your expiration rules will be deleted permanently. We can't bring them back. Make sure that you won't miss them.""") + + + if not g.viewer.account.policy_enabled: + g.viewer.account.last_delete = db.func.now() + g.viewer.account.policy_enabled = True db.session.commit() diff --git a/static/style.css b/static/style.css index 6e32be5..6a12112 100644 --- a/static/style.css +++ b/static/style.css @@ -106,3 +106,7 @@ body > section > .banner { .banner form { display: inline; } + +label { + display: inline-block; +} diff --git a/tasks.py b/tasks.py index 72a9847..fbbd9d9 100644 --- a/tasks.py +++ b/tasks.py @@ -123,8 +123,8 @@ def delete_from_account(account_id): filter(~Post.id.in_(latest_n_posts)).\ order_by(db.func.random()).limit(100).all() + posts = refresh_account(account_id) if account.service == 'twitter': - posts = lib.twitter.refresh_posts(posts) eligible = list((post for post in posts if not account.policy_keep_favourites or not post.favourite)) if eligible: if account.policy_delete_every == timedelta(0): @@ -139,9 +139,39 @@ def delete_from_account(account_id): db.session.commit() +def refresh_posts(posts): + posts = list(posts) + if len(posts) == 0: + return [] + + if posts[0].service == 'twitter': + return lib.twitter.refresh_posts(posts) + +@app.task +def refresh_account(account_id): + account = Account.query.get(account_id) + + oldest_post = Post.query.with_parent(account).order_by(db.asc(Post.updated_at)).first() + + if not oldest_post: + return [] + + posts = Post.query.with_parent(account).filter(Post.id != oldest_post.id).order_by(db.func.random()).limit(99).all() + posts.append(oldest_post) + + posts = refresh_posts(posts) + db.session.commit() + return posts + +@app.task +def refresh_account_with_oldest_post(): + post = Post.query.options(db.joinedload(Post.author)).order_by(db.asc(Post.updated_at)).first() + return refresh_account(post.author_id) + app.add_periodic_task(6*60*60, periodic_cleanup) app.add_periodic_task(45, queue_fetch_for_most_stale_accounts) app.add_periodic_task(45, queue_deletes) +app.add_periodic_task(30*60, refresh_account_with_oldest_post) if __name__ == '__main__': app.worker_main() diff --git a/templates/logged_in.html b/templates/logged_in.html index 5a388b7..80aae5c 100644 --- a/templates/logged_in.html +++ b/templates/logged_in.html @@ -21,7 +21,7 @@ {% endif %} {% set post_count = g.viewer.account.post_count() %} -

Currently keeping track of {{ post_count }} posts

+

Currently keeping track of {{ post_count }} of your posts, roughly {{ g.viewer.account.estimate_eligible_for_delete() }} of which currently match your expiration rules.

{% if g.viewer.account.service == 'twitter' and post_count < g.viewer.account.reported_post_count * 3/4 and g.viewer.account.reported_post_count > 3200 -%} @@ -37,21 +37,21 @@ {% endif %}
-

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

-

Keep posts less than +

Posts that are less than {{interval_input(g.viewer.account, 'policy_keep_younger', scales)}} - old + old are considered fresh

-

Keep my +

Your latest - latest posts + posts are considered fresh

-

Keep posts that I have favourited +

Posts that you have given a like to stay fresh forever

+

Any post that is not kept fresh by any of these rules is considered expired. One random expired post will be deleted every + {{interval_input(g.viewer.account, 'policy_delete_every', scales)}} +

diff --git a/templates/warn.html b/templates/warn.html new file mode 100644 index 0000000..68aff06 --- /dev/null +++ b/templates/warn.html @@ -0,0 +1,20 @@ +{% extends 'lib/layout.html' %} +{% block body %} +
+

Ahhhh (dats me yellin)

+ + +
+{% endblock %}