diff --git a/backend/main.py b/backend/main.py index 9708b72..78c5666 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1522,27 +1522,29 @@ def my_contribution(user=Depends(get_current_user)): return {"adopted_count": 0, "shared_count": 0, "adopted_names": [], "pending_names": []} conn = get_db() display = user.get("display_name") or user.get("username") - # adopted: recipes adopted from this user + # adopted: unique recipe names adopted from this user adopted_rows = conn.execute( - "SELECT target_name FROM audit_log WHERE action = 'adopt_recipe' AND detail LIKE ?", + "SELECT DISTINCT target_name FROM audit_log WHERE action = 'adopt_recipe' AND detail LIKE ?", (f'%"from_user": "{display}"%',) ).fetchall() - adopted_names = [r["target_name"] for r in adopted_rows if r["target_name"]] + adopted_names = list(set(r["target_name"] for r in adopted_rows if r["target_name"])) # pending: recipes still owned by user in public library pending_rows = conn.execute( "SELECT name FROM recipes WHERE owner_id = ?", (user["id"],) ).fetchall() pending_names = [r["name"] for r in pending_rows] - # rejected: count recipes rejected from this user (they were deleted but logged) - rejected_count = conn.execute( - "SELECT COUNT(*) FROM audit_log WHERE action = 'reject_recipe' AND detail LIKE ?", + # rejected: unique recipe names rejected (not already adopted or pending) + rejected_rows = conn.execute( + "SELECT DISTINCT target_name FROM audit_log WHERE action = 'reject_recipe' AND detail LIKE ?", (f'%"from_user": "{display}"%',) - ).fetchone()[0] + ).fetchall() + rejected_names = set(r["target_name"] for r in rejected_rows if r["target_name"]) + # Unique names across all: same recipe rejected then re-submitted counts as 1 + all_names = set(adopted_names) | set(pending_names) | rejected_names conn.close() - total = len(adopted_names) + len(pending_names) + rejected_count return { "adopted_count": len(adopted_names), - "shared_count": total, + "shared_count": len(all_names), "adopted_names": adopted_names, "pending_names": pending_names, } diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 3410f93..54ebaaf 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -1181,8 +1181,21 @@ function openRecipeDetail(recipe) { } function getDiaryShareStatus(d) { - if (sharedCount.value.adoptedNames.includes(d.name)) return 'shared' + // Check pending first (exact name match in public library owned by user) if (sharedCount.value.pendingNames.includes(d.name)) return 'pending' + // Check adopted — but if diary content was modified, allow re-sharing + if (sharedCount.value.adoptedNames.includes(d.name)) { + // Compare with the public recipe to see if content changed + const pub = recipeStore.recipes.find(r => r.name === d.name) + if (pub) { + const dIngs = (d.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) + const pIngs = (pub.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) + const same = dIngs.length === pIngs.length && dIngs.every((ing, i) => ing.oil === pIngs[i].oil && ing.drops === pIngs[i].drops) + if (same) return 'shared' + } + // Content changed or public recipe not found — can re-share + return null + } return null }