Molodetz blogrol volgens DPP-template
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
import logging
|
||||
|
||||
from molodetz import config
|
||||
from molodetz.constants import SETTINGS_DEFAULTS
|
||||
from molodetz.database.core import db, generate_uid, now_iso
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TABLE_EXAMPLES = {
|
||||
"users": {
|
||||
"uid": "x",
|
||||
"username": "x",
|
||||
"email": "x@x.nl",
|
||||
"password_hash": "x",
|
||||
"role": "Member",
|
||||
"api_key": "x",
|
||||
"bio": "",
|
||||
"avatar_seed": None,
|
||||
"is_active": True,
|
||||
"last_seen_at": None,
|
||||
"suspended_until": None,
|
||||
"suspend_reason": None,
|
||||
"terms_version": "1",
|
||||
"created_at": now_iso(),
|
||||
"updated_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"sessions": {
|
||||
"uid": "x",
|
||||
"token": "x",
|
||||
"user_uid": "x",
|
||||
"created_at": now_iso(),
|
||||
"expires_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"posts": {
|
||||
"uid": "x",
|
||||
"slug": "x",
|
||||
"title": "x",
|
||||
"body": "x",
|
||||
"topic": "rol",
|
||||
"status": "draft",
|
||||
"is_placeholder": False,
|
||||
"user_uid": "x",
|
||||
"published_at": None,
|
||||
"created_at": now_iso(),
|
||||
"updated_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"join_requests": {
|
||||
"uid": "x",
|
||||
"name": "x",
|
||||
"contact": "x",
|
||||
"repo_url": None,
|
||||
"message": "",
|
||||
"status": "open",
|
||||
"ip_hash": None,
|
||||
"link_title": None,
|
||||
"link_checked_at": None,
|
||||
"link_status": None,
|
||||
"created_at": now_iso(),
|
||||
"updated_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"media_items": {
|
||||
"uid": "x",
|
||||
"filename": "x.jpg",
|
||||
"kind": "flyer",
|
||||
"caption": "",
|
||||
"position": 0,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"phash": None,
|
||||
"thumb_directory": None,
|
||||
"thumb_name": None,
|
||||
"created_at": now_iso(),
|
||||
"updated_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"notifications": {
|
||||
"uid": "x",
|
||||
"user_uid": "x",
|
||||
"kind": "system.maintenance",
|
||||
"message": "x",
|
||||
"url": "/",
|
||||
"read_at": None,
|
||||
"created_at": now_iso(),
|
||||
"deleted_at": None,
|
||||
"deleted_by": None,
|
||||
},
|
||||
"site_settings": {"uid": "setting_x", "key": "x", "value": "x", "updated_at": now_iso()},
|
||||
"cache_state": {"name": "settings", "version": 0, "updated_at": now_iso()},
|
||||
"service_state": {
|
||||
"name": "backup",
|
||||
"status": "stopped",
|
||||
"last_run": None,
|
||||
"next_run": None,
|
||||
"started_at": None,
|
||||
"heartbeat": None,
|
||||
"logs": "[]",
|
||||
"metrics": "{}",
|
||||
"updated_at": now_iso(),
|
||||
},
|
||||
"audit_log": {
|
||||
"uid": "x",
|
||||
"event_key": "auth.login",
|
||||
"category": "auth",
|
||||
"actor_kind": "user",
|
||||
"actor_uid": None,
|
||||
"origin": "web",
|
||||
"result": "ok",
|
||||
"ip": None,
|
||||
"user_agent": None,
|
||||
"message": None,
|
||||
"payload": "{}",
|
||||
"created_at": now_iso(),
|
||||
},
|
||||
"audit_links": {"audit_uid": "x", "target_type": "user", "target_uid": "x"},
|
||||
"visit_stats": {"day": "2026-01-01", "path": "/", "status": 200, "hits": 0},
|
||||
"backups": {
|
||||
"uid": "x",
|
||||
"target": "database",
|
||||
"status": "pending",
|
||||
"requested_by": "x",
|
||||
"directory": None,
|
||||
"stored_name": None,
|
||||
"size_bytes": None,
|
||||
"error": None,
|
||||
"created_at": now_iso(),
|
||||
"finished_at": None,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _ensure_table(name, example):
|
||||
table = db.get_table(name)
|
||||
for column, value in example.items():
|
||||
table.create_column_by_example(column, value)
|
||||
return table
|
||||
|
||||
|
||||
def _index(sql):
|
||||
try:
|
||||
with db:
|
||||
db.query(sql)
|
||||
except Exception as exc:
|
||||
logger.warning("index ensure failed: %s (%s)", sql, exc)
|
||||
|
||||
|
||||
def _seed_settings():
|
||||
if "site_settings" not in db.tables:
|
||||
return
|
||||
for key, value in SETTINGS_DEFAULTS.items():
|
||||
uid = f"default_{key}"
|
||||
if db["site_settings"].find_one(uid=uid) is None:
|
||||
db["site_settings"].insert({"uid": uid, "key": key, "value": value, "updated_at": now_iso()})
|
||||
|
||||
|
||||
def _seed_notification_key():
|
||||
path = config.NOTIFICATION_KEY_FILE
|
||||
if not path.exists():
|
||||
path.write_text(generate_uid(), encoding="utf-8")
|
||||
path.chmod(0o600)
|
||||
|
||||
|
||||
def _backfill_api_keys():
|
||||
if "users" not in db.tables:
|
||||
return
|
||||
with db:
|
||||
db.query("UPDATE users SET api_key = :key WHERE api_key IS NULL OR api_key = ''", key=generate_uid())
|
||||
|
||||
|
||||
def init_db():
|
||||
for name, example in TABLE_EXAMPLES.items():
|
||||
_ensure_table(name, example)
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_users_uid ON users(uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username ON users(username)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email ON users(email)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_users_api_key ON users(api_key)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_users_trash ON users(deleted_at) WHERE deleted_at IS NOT NULL")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_sessions_uid ON sessions(uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_sessions_token ON sessions(token)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_uid, created_at)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_sessions_trash ON sessions(deleted_at) WHERE deleted_at IS NOT NULL")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_posts_uid ON posts(uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_posts_slug ON posts(slug)")
|
||||
_index(
|
||||
"CREATE INDEX IF NOT EXISTS idx_posts_published ON posts(topic, published_at) "
|
||||
"WHERE deleted_at IS NULL AND status = 'published'"
|
||||
)
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(user_uid, created_at)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_posts_trash ON posts(deleted_at) WHERE deleted_at IS NOT NULL")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_join_requests_uid ON join_requests(uid)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_join_requests_status ON join_requests(status, created_at)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_join_requests_trash ON join_requests(deleted_at) WHERE deleted_at IS NOT NULL")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_media_items_uid ON media_items(uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_media_items_filename ON media_items(filename)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_media_items_kind ON media_items(kind, position)")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_notifications_uid ON notifications(uid)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_uid, created_at)")
|
||||
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_site_settings_uid ON site_settings(uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_site_settings_key ON site_settings(key)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_cache_state_name ON cache_state(name)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_service_state_name ON service_state(name)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_audit_log_uid ON audit_log(uid)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_audit_log_created ON audit_log(created_at)")
|
||||
_index("CREATE INDEX IF NOT EXISTS idx_audit_links_audit ON audit_links(audit_uid)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_visit_stats_day_path ON visit_stats(day, path, status)")
|
||||
_index("CREATE UNIQUE INDEX IF NOT EXISTS idx_backups_uid ON backups(uid)")
|
||||
|
||||
_seed_settings()
|
||||
_seed_notification_key()
|
||||
_backfill_api_keys()
|
||||
|
||||
with db:
|
||||
has_stats = next(iter(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='sqlite_stat1'")), None)
|
||||
if has_stats is None:
|
||||
db.query("ANALYZE")
|
||||
db.query("PRAGMA optimize")
|
||||
Reference in New Issue
Block a user