feat: add soft delete and media tab for user attachments with admin restore

This commit is contained in:
2026-06-11 18:52:56 +00:00
parent c74228bc6c
commit 3862958fae
40 changed files with 1549 additions and 81 deletions
+27 -2
View File
@@ -219,6 +219,7 @@ def store_attachment(file_bytes, original_filename, user_uid):
"has_thumbnail": 1 if thumbnail else 0,
"thumbnail_name": thumbnail,
"created_at": datetime.now(timezone.utc).isoformat(),
"deleted_at": None,
}
)
return {
@@ -383,6 +384,24 @@ def delete_attachment(uid):
_delete_attachment_row(row)
def soft_delete_attachment(uid):
row = get_table("attachments").find_one(uid=uid)
if not row or row.get("deleted_at"):
return None
get_table("attachments").update(
{"uid": uid, "deleted_at": datetime.now(timezone.utc).isoformat()}, ["uid"]
)
return row
def restore_attachment(uid):
row = get_table("attachments").find_one(uid=uid)
if not row or not row.get("deleted_at"):
return False
get_table("attachments").update({"uid": uid, "deleted_at": None}, ["uid"])
return True
def delete_target_attachments(target_type, target_uid):
for row in get_table("attachments").find(
target_type=target_type, target_uid=target_uid
@@ -416,7 +435,10 @@ def get_attachments(target_type, target_uid):
return []
rows = list(
get_table("attachments").find(
target_type=target_type, target_uid=target_uid, order_by=["created_at"]
target_type=target_type,
target_uid=target_uid,
deleted_at=None,
order_by=["created_at"],
)
)
return [_row_to_attachment(r) for r in rows]
@@ -430,7 +452,7 @@ def get_attachments_batch(target_type, uids):
placeholders = ",".join(f":p{i}" for i in range(len(uids)))
params = {f"p{i}": uid for i, uid in enumerate(uids)}
rows = db.query(
f"SELECT * FROM attachments WHERE target_type=:tt AND target_uid IN ({placeholders}) ORDER BY created_at",
f"SELECT * FROM attachments WHERE target_type=:tt AND target_uid IN ({placeholders}) AND deleted_at IS NULL ORDER BY created_at",
tt=target_type,
**params,
)
@@ -467,6 +489,9 @@ def _row_to_attachment(row):
"has_thumbnail": bool(row.get("has_thumbnail")),
"is_image": row.get("mime_type", "").startswith("image/"),
"is_video": row.get("mime_type", "").startswith("video/"),
"target_type": row.get("target_type", ""),
"target_uid": row.get("target_uid", ""),
"created_at": row.get("created_at", ""),
}