Translate the whole site to English: English routes with 301 redirects from the Dutch paths, English UI, docs, seeds and captions, one-time live content migration
This commit is contained in:
+14
-14
@@ -160,17 +160,17 @@ async def process_backup_async(row, codec):
|
||||
|
||||
class BackupService(BaseService):
|
||||
name = "backup"
|
||||
title = "Back-ups"
|
||||
description = "Verwerkt de back-upwachtrij, plant automatische back-ups en snoeit oude archieven."
|
||||
title = "Backups"
|
||||
description = "Works through the backup queue, schedules automatic backups and prunes old archives."
|
||||
default_interval = 10
|
||||
min_interval = 5
|
||||
metrics_interval = 30
|
||||
config_fields = [
|
||||
ConfigField("schedule_hours", "int", 24, "Automatisch elke N uur (0 = uit)", minimum=0, maximum=720, group="Planning"),
|
||||
ConfigField("schedule_target", "select", "database", "Automatisch doel", options=list(TARGETS), group="Planning"),
|
||||
ConfigField("keep_last", "int", 14, "Bewaar laatste N", minimum=1, maximum=1000, group="Bewaren"),
|
||||
ConfigField("codec", "select", "zstd", "Compressie", options=["zstd", "brotli"], group="Archief"),
|
||||
ConfigField("offload", "bool", "0", "Offload via rclone", group="Archief"),
|
||||
ConfigField("schedule_hours", "int", 24, "Automatic every N hours (0 = off)", minimum=0, maximum=720, group="Schedule"),
|
||||
ConfigField("schedule_target", "select", "database", "Automatic target", options=list(TARGETS), group="Schedule"),
|
||||
ConfigField("keep_last", "int", 14, "Keep last N", minimum=1, maximum=1000, group="Retention"),
|
||||
ConfigField("codec", "select", "zstd", "Compression", options=["zstd", "brotli"], group="Archive"),
|
||||
ConfigField("offload", "bool", "0", "Offload via rclone", group="Archive"),
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
@@ -190,30 +190,30 @@ class BackupService(BaseService):
|
||||
cfg = self.get_config()
|
||||
if self._schedule_due(int(cfg["schedule_hours"])):
|
||||
enqueue_backup(cfg["schedule_target"], "system")
|
||||
self.log(f"automatische back-up ingepland: {cfg['schedule_target']}")
|
||||
self.log(f"automatic backup scheduled: {cfg['schedule_target']}")
|
||||
for row in pending_backups():
|
||||
update_backup(row["uid"], status="running")
|
||||
ok = await process_backup_async(row, cfg["codec"])
|
||||
self.processed += 1
|
||||
self.log(f"back-up {row['target']} {'klaar' if ok else 'mislukt'}")
|
||||
self.log(f"backup {row['target']} {'finished' if ok else 'failed'}")
|
||||
primary = admin_uids_ordered()[:1]
|
||||
for uid in primary:
|
||||
create_notification(uid, "backup.finished" if ok else "backup.failed", f"Back-up {row['target']} {'klaar' if ok else 'mislukt'}", "/admin/backups")
|
||||
create_notification(uid, "backup.finished" if ok else "backup.failed", f"Backup {row['target']} {'finished' if ok else 'failed'}", "/admin/backups")
|
||||
if ok and cfg["offload"] == "1":
|
||||
done = [item for item in list_backups(limit=5) if item["uid"] == row["uid"]]
|
||||
if done:
|
||||
self.log(f"offload: {offload(backup_path(done[0]))}")
|
||||
pruned = prune_backups(int(cfg["keep_last"]))
|
||||
if pruned:
|
||||
self.log(f"{pruned} oude back-ups gesnoeid")
|
||||
self.log(f"{pruned} old backups pruned")
|
||||
|
||||
def collect_metrics(self):
|
||||
rows = list_backups(limit=200)
|
||||
return {
|
||||
"cards": [
|
||||
{"label": "Archieven", "value": sum(1 for row in rows if row["status"] == "done")},
|
||||
{"label": "Wachtrij", "value": sum(1 for row in rows if row["status"] == "pending")},
|
||||
{"label": "Verwerkt sinds start", "value": self.processed},
|
||||
{"label": "Archives", "value": sum(1 for row in rows if row["status"] == "done")},
|
||||
{"label": "Queue", "value": sum(1 for row in rows if row["status"] == "pending")},
|
||||
{"label": "Processed since start", "value": self.processed},
|
||||
],
|
||||
"table": None,
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ FIELD_TYPES = ("int", "str", "url", "text", "password", "bool", "select")
|
||||
|
||||
|
||||
class ConfigField:
|
||||
def __init__(self, key, type="str", default="", label="", help="", minimum=None, maximum=None, options=None, secret=False, group="Algemeen"):
|
||||
def __init__(self, key, type="str", default="", label="", help="", minimum=None, maximum=None, options=None, secret=False, group="General"):
|
||||
if type not in FIELD_TYPES:
|
||||
raise ValueError(f"unknown field type {type}")
|
||||
self.key = key
|
||||
@@ -109,10 +109,10 @@ class BaseService:
|
||||
|
||||
def fields(self):
|
||||
framework = [
|
||||
ConfigField("enabled", "bool", "1" if self.default_enabled else "0", "Ingeschakeld", group="Algemeen"),
|
||||
ConfigField("interval", "int", self.default_interval, "Interval (s)", minimum=self.min_interval, group="Algemeen"),
|
||||
ConfigField("enabled", "bool", "1" if self.default_enabled else "0", "Enabled", group="General"),
|
||||
ConfigField("interval", "int", self.default_interval, "Interval (s)", minimum=self.min_interval, group="General"),
|
||||
]
|
||||
tail = [ConfigField("log_size", "int", 200, "Logregels", minimum=10, maximum=5000, group="Logs")]
|
||||
tail = [ConfigField("log_size", "int", 200, "Log lines", minimum=10, maximum=5000, group="Logs")]
|
||||
return framework + list(self.config_fields) + tail
|
||||
|
||||
def field(self, key):
|
||||
@@ -196,7 +196,7 @@ class BaseService:
|
||||
try:
|
||||
await self.run_once()
|
||||
except Exception as exc:
|
||||
self.log(f"fout: {exc}")
|
||||
self.log(f"error: {exc}")
|
||||
logger.exception("service %s failed", self.name)
|
||||
self._next_run = datetime.now(timezone.utc) + timedelta(seconds=self.current_interval())
|
||||
write_service_state(self._row_id, last_run=now_iso())
|
||||
|
||||
@@ -8,7 +8,7 @@ from molodetz.services.base import BaseService
|
||||
class HousekeepingService(BaseService):
|
||||
name = "housekeeping"
|
||||
title = "Housekeeping"
|
||||
description = "Ruimt verlopen sessies op en snoeit het auditlog volgens de bewaartermijn."
|
||||
description = "Clears expired sessions and prunes the audit log to the retention period."
|
||||
default_interval = 3600
|
||||
min_interval = 60
|
||||
metrics_interval = 300
|
||||
@@ -23,14 +23,14 @@ class HousekeepingService(BaseService):
|
||||
days = max(1, get_int_setting("audit_retention_days", 365))
|
||||
cutoff = (datetime.now(timezone.utc) - timedelta(days=days)).isoformat()
|
||||
self.last_audit = prune_audit(cutoff)
|
||||
self.log(f"sessies verwijderd: {self.last_sessions}, auditregels gesnoeid: {self.last_audit}")
|
||||
self.log(f"sessions removed: {self.last_sessions}, audit rows pruned: {self.last_audit}")
|
||||
|
||||
def collect_metrics(self):
|
||||
return {
|
||||
"cards": [
|
||||
{"label": "Auditregels", "value": count_audit()},
|
||||
{"label": "Laatste sessie-opruiming", "value": self.last_sessions},
|
||||
{"label": "Laatste auditsnoei", "value": self.last_audit},
|
||||
{"label": "Audit rows", "value": count_audit()},
|
||||
{"label": "Last session cleanup", "value": self.last_sessions},
|
||||
{"label": "Last audit prune", "value": self.last_audit},
|
||||
],
|
||||
"table": None,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ from molodetz.utils.presence import compute_roster
|
||||
class PresenceService(BaseService):
|
||||
name = "presence"
|
||||
title = "Presence"
|
||||
description = "Publiceert de online-set uit de laatste activiteit van accounts."
|
||||
description = "Publishes the online set from recent account activity."
|
||||
default_interval = 5
|
||||
min_interval = 2
|
||||
metrics_interval = 5
|
||||
@@ -24,7 +24,7 @@ class PresenceService(BaseService):
|
||||
"roster": self.roster,
|
||||
"cards": [
|
||||
{"label": "Online", "value": len(self.roster[: config.PRESENCE_ONLINE_LIMIT])},
|
||||
{"label": "Gevolgd", "value": len(self.roster)},
|
||||
{"label": "Tracked", "value": len(self.roster)},
|
||||
],
|
||||
"table": None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user