fix: build mealie permalink as /g/<group>/r/<slug>, not /recipe/<slug>
Cobb caught it. Mealie's web URL format is: https://recipes.sulkta.com/g/hayes-house/r/dairy-free-bread-recipe Was emitting /recipe/<slug> which 404s. Added _user_group_slug() helper that pulls .group.slug from /api/users/self (handles dict-or-string-or-fallback shapes for cross-version compat), threads the proper URL through both: - /api/recipes/<slug>.json (used by the modal) - /recipes/<slug> server-rendered detail (used as fallback for direct links) Falls back to the old /recipe/<slug> path if we can't resolve a group slug (won't break, will just 404 in Mealie if that ever happens).
This commit is contained in:
parent
3c4c0c027d
commit
8e53a84121
3 changed files with 40 additions and 6 deletions
|
|
@ -482,8 +482,20 @@ def create_app() -> Flask:
|
|||
recipe = client.get_recipe(slug)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 502
|
||||
recipe["picked"] = slug in db.list_household_pick_slugs(current_household_id() or 0) if current_household_id() else False
|
||||
return jsonify({"recipe": recipe, "public_url": cfg.mealie_public_url})
|
||||
hid = current_household_id()
|
||||
recipe["picked"] = slug in db.list_household_pick_slugs(hid) if hid else False
|
||||
# Mealie's web URL: <public>/g/<group-slug>/r/<recipe-slug>
|
||||
group_slug = _user_group_slug(client)
|
||||
mealie_url = (
|
||||
f"{cfg.mealie_public_url}/g/{group_slug}/r/{slug}"
|
||||
if group_slug
|
||||
else f"{cfg.mealie_public_url}/recipe/{slug}"
|
||||
)
|
||||
return jsonify({
|
||||
"recipe": recipe,
|
||||
"public_url": cfg.mealie_public_url,
|
||||
"mealie_url": mealie_url,
|
||||
})
|
||||
|
||||
@app.get("/recipes/<slug>")
|
||||
@require_session
|
||||
|
|
@ -497,10 +509,16 @@ def create_app() -> Flask:
|
|||
except Exception as e:
|
||||
return (f"recipe load failed: {e}", 502)
|
||||
picked = slug in db.list_meal_pick_slugs(u["sub"])
|
||||
group_slug = _user_group_slug(client)
|
||||
mealie_url = (
|
||||
f"{cfg.mealie_public_url}/g/{group_slug}/r/{slug}"
|
||||
if group_slug else f"{cfg.mealie_public_url}/recipe/{slug}"
|
||||
)
|
||||
return render_template(
|
||||
"recipe_detail.html",
|
||||
recipe=recipe,
|
||||
public_url=cfg.mealie_public_url,
|
||||
mealie_url=mealie_url,
|
||||
picked=picked,
|
||||
active="recipes",
|
||||
)
|
||||
|
|
@ -534,6 +552,22 @@ def create_app() -> Flask:
|
|||
return app
|
||||
|
||||
|
||||
def _user_group_slug(client) -> str | None:
|
||||
"""Mealie's recipe permalink lives at /g/<group-slug>/r/<slug>. Pull
|
||||
the group slug from /api/users/self. Cheap call (Mealie is on the
|
||||
same docker bridge); could cache in session if it becomes hot."""
|
||||
try:
|
||||
me = client.who_am_i()
|
||||
except Exception:
|
||||
return None
|
||||
g = me.get("group")
|
||||
if isinstance(g, dict):
|
||||
return g.get("slug") or g.get("name")
|
||||
if isinstance(g, str) and g:
|
||||
return g
|
||||
return me.get("groupSlug") or me.get("group_slug") or me.get("groupName")
|
||||
|
||||
|
||||
def _sort_to_order(sort: str) -> tuple[str, str]:
|
||||
"""Map our sort keys to Mealie's orderBy + direction."""
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -539,13 +539,13 @@ button { font-family: inherit; }
|
|||
const r = await fetch('/api/recipes/' + encodeURIComponent(slug) + '.json');
|
||||
if (!r.ok) throw new Error(r.status);
|
||||
const data = await r.json();
|
||||
renderRecipe(data.recipe, data.public_url);
|
||||
renderRecipe(data.recipe, data.mealie_url);
|
||||
} catch (e) {
|
||||
bodyEl.innerHTML = '<p style="color: var(--crit);">load failed.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderRecipe(r, publicUrl) {
|
||||
function renderRecipe(r, mealieUrl) {
|
||||
titleEl.textContent = r.name || '(untitled)';
|
||||
const meta = [];
|
||||
if (r.totalTime) meta.push('<span class="m">' + escapeHtml(r.totalTime) + '</span>');
|
||||
|
|
@ -584,7 +584,7 @@ button { font-family: inherit; }
|
|||
data-slug="${escapeHtml(r.slug)}" data-name="${escapeHtml(r.name||'')}">
|
||||
🍄 ${isPicked ? 'pinned · unpin' : 'pin to plan'}
|
||||
</button>
|
||||
<a class="btn" href="${publicUrl}/recipe/${encodeURIComponent(r.slug)}" target="_blank" rel="noopener">in mealie ↗</a>
|
||||
<a class="btn" href="${mealieUrl}" target="_blank" rel="noopener">in mealie ↗</a>
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
onclick="togglePick(this)">
|
||||
🍄 {% if picked %}pinned · remove{% else %}pin for ai plan{% endif %}
|
||||
</button>
|
||||
<a class="btn" href="{{ public_url }}/recipe/{{ recipe.slug }}" target="_blank" rel="noopener">view in mealie ↗</a>
|
||||
<a class="btn" href="{{ mealie_url }}" target="_blank" rel="noopener">view in mealie ↗</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue