From 03abff5ad80571f1c69a0606c6c7e083a2218fc5 Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Sat, 25 Jan 2025 01:20:55 +0100
Subject: [PATCH] =?UTF-8?q?DSN:=20Expirace=20nedoru=C4=8Denek?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Nemažeme nedoručenky, na které se odkazuje nějaký účet.
Ale o registraci se nestaráme, ta velmi pravděpodobně expiruje dřív.
---
 etc/config.py.example |  3 +++
 mo/util_dsn.py        | 22 ++++++++++++++++++++++
 mo/web/__init__.py    |  3 +++
 3 files changed, 28 insertions(+)

diff --git a/etc/config.py.example b/etc/config.py.example
index 9c02e622..15d62304 100644
--- a/etc/config.py.example
+++ b/etc/config.py.example
@@ -80,6 +80,9 @@ REG_MAX_PER_MINUTE = 10
 # Jak dlouho vydrží tokeny používané při registraci a změnách e-mailu [min]
 REG_TOKEN_VALIDITY = 10
 
+# Jak dlouho si pamatujeme e-mailovou nedoručenku [min]
+DSN_EXPIRATION = 30 * 1440
+
 # Aktuální ročník MO
 CURRENT_YEAR = 71
 
diff --git a/mo/util_dsn.py b/mo/util_dsn.py
index b442e256..64fe8cd7 100644
--- a/mo/util_dsn.py
+++ b/mo/util_dsn.py
@@ -1,7 +1,13 @@
 # Utility na práci s mailovými nedoručenkami
 
+from datetime import timedelta
+from sqlalchemy import select
 from typing import Optional
 
+import mo
+import mo.config as config
+import mo.db as db
+
 
 dsn_explanation = {
     '4.2.2': 'schránka je plná',
@@ -26,3 +32,19 @@ def format_dsn_status(status: Optional[str]) -> str:
             return f'{status} – {explain}'
         else:
             return status
+
+
+def expire_dsns() -> None:
+    expiration = getattr(config, 'DSN_EXPIRATION', None)
+    if expiration is None:
+        return
+
+    sess = db.get_session()
+    conn = sess.connection()
+    user_table = db.User.__table__
+    dsn_table = db.EmailDSN.__table__
+    conn.execute(dsn_table.delete()
+                 .where(dsn_table.c.arrived_at < mo.now - timedelta(days=expiration))
+                 .where(dsn_table.c.dsn_id.not_in(select(user_table.c.dsn_id))))
+
+    sess.commit()
diff --git a/mo/web/__init__.py b/mo/web/__init__.py
index 743333c7..f8ccc040 100644
--- a/mo/web/__init__.py
+++ b/mo/web/__init__.py
@@ -23,6 +23,7 @@ import mo.jobs.submit
 import mo.rights
 import mo.users
 import mo.util
+import mo.util_dsn
 
 
 class MOFlask(Flask):
@@ -210,11 +211,13 @@ app.before_request(init_request)
 #    - projdeme joby pro případ, že by se ztratil signál
 #    - expirujeme zastaralé joby
 #    - expirujeme zastaralé registrační tokeny
+#    - expirujeme zastaralé nedoručenky
 def collect_garbage() -> None:
     mo.now = mo.util.get_now()
     mo.jobs.submit.check_broken_submits()
     mo.jobs.process_jobs()
     mo.users.expire_reg_requests()
+    mo.util_dsn.expire_dsns()
 
 
 @app.cli.command('gc')
-- 
GitLab