This commit is contained in:
parent
503aab26ac
commit
c826096843
@ -168,6 +168,7 @@ def store_attachment(file_bytes, original_filename, user_uid):
|
|||||||
"image_width": image_width,
|
"image_width": image_width,
|
||||||
"image_height": image_height,
|
"image_height": image_height,
|
||||||
"has_thumbnail": 1 if thumbnail else 0,
|
"has_thumbnail": 1 if thumbnail else 0,
|
||||||
|
"thumbnail_name": thumbnail,
|
||||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
@ -183,43 +184,66 @@ def store_attachment(file_bytes, original_filename, user_uid):
|
|||||||
|
|
||||||
|
|
||||||
def link_attachments(uids, target_type, target_uid):
|
def link_attachments(uids, target_type, target_uid):
|
||||||
if not uids:
|
flat = [uid.strip() for raw in uids or [] for uid in str(raw).split(",") if uid.strip()]
|
||||||
|
if not flat:
|
||||||
return
|
return
|
||||||
attachments = get_table("attachments")
|
placeholders = ",".join(f":p{i}" for i in range(len(flat)))
|
||||||
for raw in uids:
|
params = {f"p{i}": uid for i, uid in enumerate(flat)}
|
||||||
for uid in str(raw).split(","):
|
db.query(
|
||||||
uid = uid.strip()
|
f"UPDATE attachments SET target_type=:tt, target_uid=:tu WHERE uid IN ({placeholders})",
|
||||||
if not uid:
|
tt=target_type, tu=target_uid, **params,
|
||||||
continue
|
)
|
||||||
existing = attachments.find_one(uid=uid)
|
|
||||||
if existing:
|
|
||||||
attachments.update({"id": existing["id"], "target_type": target_type, "target_uid": target_uid}, ["id"])
|
def _unlink_attachment_files(row):
|
||||||
|
stored_name = row.get("stored_name", "")
|
||||||
|
directory = row.get("directory", "")
|
||||||
|
if not (stored_name and directory):
|
||||||
|
return
|
||||||
|
file_path = ATTACHMENTS_DIR / directory / stored_name
|
||||||
|
try:
|
||||||
|
file_path.unlink(missing_ok=True)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to delete attachment file {file_path}: {e}")
|
||||||
|
for thumb_path in (ATTACHMENTS_DIR / directory).glob(f"{Path(stored_name).stem}_thumb.*"):
|
||||||
|
try:
|
||||||
|
thumb_path.unlink(missing_ok=True)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to delete thumbnail {thumb_path}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_attachment_row(row):
|
||||||
|
_unlink_attachment_files(row)
|
||||||
|
get_table("attachments").delete(id=row["id"])
|
||||||
|
|
||||||
|
|
||||||
def delete_attachment(uid):
|
def delete_attachment(uid):
|
||||||
attachments = get_table("attachments")
|
row = get_table("attachments").find_one(uid=uid)
|
||||||
attachment = attachments.find_one(uid=uid)
|
if row:
|
||||||
if not attachment:
|
_delete_attachment_row(row)
|
||||||
return
|
|
||||||
stored_name = attachment.get("stored_name", "")
|
|
||||||
directory = attachment.get("directory", "")
|
|
||||||
if stored_name and directory:
|
|
||||||
file_path = ATTACHMENTS_DIR / directory / stored_name
|
|
||||||
try:
|
|
||||||
file_path.unlink(missing_ok=True)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Failed to delete attachment file {file_path}: {e}")
|
|
||||||
for thumb_path in (ATTACHMENTS_DIR / directory).glob(f"{Path(stored_name).stem}_thumb.*"):
|
|
||||||
try:
|
|
||||||
thumb_path.unlink(missing_ok=True)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Failed to delete thumbnail {thumb_path}: {e}")
|
|
||||||
attachments.delete(id=attachment["id"])
|
|
||||||
|
|
||||||
|
|
||||||
def delete_target_attachments(target_type, target_uid):
|
def delete_target_attachments(target_type, target_uid):
|
||||||
for attachment in get_table("attachments").find(target_type=target_type, target_uid=target_uid):
|
for row in get_table("attachments").find(target_type=target_type, target_uid=target_uid):
|
||||||
delete_attachment(attachment["uid"])
|
_delete_attachment_row(row)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_attachments_for(target_type, target_uids):
|
||||||
|
uids = [uid for uid in target_uids if uid]
|
||||||
|
if not uids or "attachments" not in db.tables:
|
||||||
|
return
|
||||||
|
placeholders = ",".join(f":p{i}" for i in range(len(uids)))
|
||||||
|
params = {f"p{i}": uid for i, uid in enumerate(uids)}
|
||||||
|
rows = list(db.query(
|
||||||
|
f"SELECT * FROM attachments WHERE target_type=:tt AND target_uid IN ({placeholders})",
|
||||||
|
tt=target_type, **params,
|
||||||
|
))
|
||||||
|
if not rows:
|
||||||
|
return
|
||||||
|
for row in rows:
|
||||||
|
_unlink_attachment_files(row)
|
||||||
|
ids = ",".join(str(row["id"]) for row in rows)
|
||||||
|
db.query(f"DELETE FROM attachments WHERE id IN ({ids})")
|
||||||
|
|
||||||
|
|
||||||
def get_attachments(target_type, target_uid):
|
def get_attachments(target_type, target_uid):
|
||||||
@ -252,9 +276,11 @@ def _row_to_attachment(row):
|
|||||||
directory = row.get("directory", "")
|
directory = row.get("directory", "")
|
||||||
thumb_name = None
|
thumb_name = None
|
||||||
if row.get("has_thumbnail"):
|
if row.get("has_thumbnail"):
|
||||||
stem = Path(stored_name).stem
|
thumb_name = row.get("thumbnail_name")
|
||||||
matches = sorted((ATTACHMENTS_DIR / directory).glob(f"{stem}_thumb.*"))
|
if not thumb_name:
|
||||||
thumb_name = matches[0].name if matches else f"{stem}_thumb.jpg"
|
stem = Path(stored_name).stem
|
||||||
|
png = f"{stem}_thumb.png"
|
||||||
|
thumb_name = png if (ATTACHMENTS_DIR / directory / png).exists() else f"{stem}_thumb.jpg"
|
||||||
return {
|
return {
|
||||||
"uid": row["uid"],
|
"uid": row["uid"],
|
||||||
"original_filename": row.get("original_filename", ""),
|
"original_filename": row.get("original_filename", ""),
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from devplacepy.database import (
|
|||||||
load_comments,
|
load_comments,
|
||||||
db,
|
db,
|
||||||
)
|
)
|
||||||
from devplacepy.attachments import delete_target_attachments, delete_inline_image, get_attachments, link_attachments
|
from devplacepy.attachments import delete_attachments_for, delete_inline_image, get_attachments, link_attachments
|
||||||
from devplacepy.utils import time_ago, generate_uid, make_combined_slug, award_rewards, create_mention_notifications
|
from devplacepy.utils import time_ago, generate_uid, make_combined_slug, award_rewards, create_mention_notifications
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -74,13 +74,12 @@ def delete_content_item(table_name: str, target_type: str, user: dict, slug: str
|
|||||||
table = get_table(table_name)
|
table = get_table(table_name)
|
||||||
item = resolve_by_slug(table, slug)
|
item = resolve_by_slug(table, slug)
|
||||||
if is_owner(item, user):
|
if is_owner(item, user):
|
||||||
delete_target_attachments(target_type, item["uid"])
|
delete_attachments_for(target_type, [item["uid"]])
|
||||||
comment_uids = []
|
comment_uids = []
|
||||||
if "comments" in db.tables:
|
if "comments" in db.tables:
|
||||||
comments = get_table("comments")
|
comments = get_table("comments")
|
||||||
for comment in comments.find(target_uid=item["uid"]):
|
comment_uids = [comment["uid"] for comment in comments.find(target_uid=item["uid"])]
|
||||||
comment_uids.append(comment["uid"])
|
delete_attachments_for("comment", comment_uids)
|
||||||
delete_target_attachments("comment", comment["uid"])
|
|
||||||
comments.delete(target_uid=item["uid"])
|
comments.delete(target_uid=item["uid"])
|
||||||
if "votes" in db.tables:
|
if "votes" in db.tables:
|
||||||
votes = get_table("votes")
|
votes = get_table("votes")
|
||||||
|
|||||||
@ -278,15 +278,17 @@ def award_xp(user_uid: str, amount: int) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
def check_milestone_badges(user_uid: str) -> list:
|
def check_milestone_badges(user_uid: str) -> list:
|
||||||
|
held = {row["badge_name"] for row in get_table("badges").find(user_uid=user_uid)}
|
||||||
awarded = []
|
awarded = []
|
||||||
if get_table("posts").count(user_uid=user_uid) >= 10 and award_badge(user_uid, "Prolific"):
|
if "Prolific" not in held and get_table("posts").count(user_uid=user_uid) >= 10 and award_badge(user_uid, "Prolific"):
|
||||||
awarded.append("Prolific")
|
awarded.append("Prolific")
|
||||||
stars = get_user_stars(user_uid)
|
if {"Star Author", "Rising Star"} - held:
|
||||||
if stars >= 100 and award_badge(user_uid, "Star Author"):
|
stars = get_user_stars(user_uid)
|
||||||
awarded.append("Star Author")
|
if "Star Author" not in held and stars >= 100 and award_badge(user_uid, "Star Author"):
|
||||||
if stars >= 25 and award_badge(user_uid, "Rising Star"):
|
awarded.append("Star Author")
|
||||||
awarded.append("Rising Star")
|
if "Rising Star" not in held and stars >= 25 and award_badge(user_uid, "Rising Star"):
|
||||||
if get_table("follows").count(following_uid=user_uid) >= 10 and award_badge(user_uid, "Popular"):
|
awarded.append("Rising Star")
|
||||||
|
if "Popular" not in held and get_table("follows").count(following_uid=user_uid) >= 10 and award_badge(user_uid, "Popular"):
|
||||||
awarded.append("Popular")
|
awarded.append("Popular")
|
||||||
for badge_name in awarded:
|
for badge_name in awarded:
|
||||||
notify_badge(user_uid, badge_name)
|
notify_badge(user_uid, badge_name)
|
||||||
@ -301,7 +303,7 @@ def award_rewards(user_uid: str, amount: int, first_badge: str | None = None) ->
|
|||||||
|
|
||||||
|
|
||||||
def create_mention_notifications(content: str, actor_uid: str, target_url: str) -> None:
|
def create_mention_notifications(content: str, actor_uid: str, target_url: str) -> None:
|
||||||
usernames = extract_mentions(content)
|
usernames = list(dict.fromkeys(extract_mentions(content)))
|
||||||
if not usernames:
|
if not usernames:
|
||||||
return
|
return
|
||||||
users = get_table("users")
|
users = get_table("users")
|
||||||
@ -309,13 +311,8 @@ def create_mention_notifications(content: str, actor_uid: str, target_url: str)
|
|||||||
if not actor:
|
if not actor:
|
||||||
return
|
return
|
||||||
actor_username = actor["username"]
|
actor_username = actor["username"]
|
||||||
seen = set()
|
for mentioned in users.find(users.table.columns.username.in_(usernames)):
|
||||||
for username in usernames:
|
if mentioned["uid"] != actor_uid:
|
||||||
if username in seen:
|
|
||||||
continue
|
|
||||||
seen.add(username)
|
|
||||||
mentioned = users.find_one(username=username)
|
|
||||||
if mentioned and mentioned["uid"] != actor_uid:
|
|
||||||
create_notification(mentioned["uid"], "mention", f"@{actor_username} mentioned you", actor_uid, target_url)
|
create_notification(mentioned["uid"], "mention", f"@{actor_username} mentioned you", actor_uid, target_url)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user