diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dfc223..58b1dde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to Epicure are documented here. This file is mirrored in-app at `/changelog` (and in the admin dashboard) via `apps/web/lib/changelog.ts` — update both together. +## 0.51.6 — 2026-07-19 13:20 + +### Fixed +- Image attachments on support tickets now embed inline in the Gitea issue (rendered preview) instead of just a plain link. Also fixed the admin "Create Gitea issue" retry action, which was dropping attachments entirely and only ever sent the ticket description. + ## 0.51.5 — 2026-07-19 13:05 ### Fixed diff --git a/apps/web/app/api/v1/admin/support/[id]/route.ts b/apps/web/app/api/v1/admin/support/[id]/route.ts index 2d6473f..ee33593 100644 --- a/apps/web/app/api/v1/admin/support/[id]/route.ts +++ b/apps/web/app/api/v1/admin/support/[id]/route.ts @@ -1,8 +1,8 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; -import { db, supportTickets, eq } from "@epicure/db"; +import { db, supportTickets, supportTicketAttachments, eq } from "@epicure/db"; import { requireAdmin } from "@/lib/api-auth"; -import { createGiteaIssue } from "@/lib/gitea"; +import { createGiteaIssue, buildGiteaIssueBody } from "@/lib/gitea"; const UpdateTicketBody = z.object({ status: z.enum(["open", "triaged", "closed"]).optional(), @@ -30,10 +30,15 @@ export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id } if (parsed.data.retryGitea) { + const attachments = await db + .select({ key: supportTicketAttachments.storageKey, contentType: supportTicketAttachments.contentType }) + .from(supportTicketAttachments) + .where(eq(supportTicketAttachments.ticketId, id)); + const { url, error } = await createGiteaIssue({ type: ticket.type, title: ticket.title, - body: `${ticket.description}\n\n---\nReported via Epicure support form by user \`${ticket.userId}\`.`, + body: buildGiteaIssueBody({ description: ticket.description, userId: ticket.userId, attachments }), }); updates.giteaIssueUrl = url; updates.giteaError = error; diff --git a/apps/web/app/api/v1/support/route.ts b/apps/web/app/api/v1/support/route.ts index 3662cec..a75b006 100644 --- a/apps/web/app/api/v1/support/route.ts +++ b/apps/web/app/api/v1/support/route.ts @@ -4,7 +4,7 @@ import { z } from "zod"; import { db, supportTickets, supportTicketAttachments, eq, desc } from "@epicure/db"; import { requireSession } from "@/lib/api-auth"; import { sendEmail, supportTicketReceivedHtml } from "@/lib/email"; -import { createGiteaIssue } from "@/lib/gitea"; +import { createGiteaIssue, buildGiteaIssueBody } from "@/lib/gitea"; import { getPublicUrl, isOwnedSupportAttachmentKey } from "@/lib/storage"; const MAX_ATTACHMENTS = 5; @@ -65,17 +65,10 @@ export async function POST(req: NextRequest) { const id = crypto.randomUUID(); const now = new Date(); - const attachmentLinks = attachments.map((a) => getPublicUrl(a.key)); - const giteaBody = [ - description, - attachmentLinks.length > 0 ? `\n**Attachments:**\n${attachmentLinks.map((u) => `- ${u}`).join("\n")}` : "", - `\n---\nReported via Epicure support form by user \`${session!.user.id}\`.`, - ].join("\n"); - const { url: giteaIssueUrl, error: giteaError } = await createGiteaIssue({ type, title, - body: giteaBody, + body: buildGiteaIssueBody({ description, userId: session!.user.id, attachments }), }); await db.insert(supportTickets).values({ diff --git a/apps/web/lib/changelog.ts b/apps/web/lib/changelog.ts index 82dfa5c..d4068cd 100644 --- a/apps/web/lib/changelog.ts +++ b/apps/web/lib/changelog.ts @@ -1,5 +1,5 @@ // Mirrors CHANGELOG.md at the repo root — update both together. -export const APP_VERSION = "0.51.5"; +export const APP_VERSION = "0.51.6"; export type ChangelogEntry = { version: string; @@ -11,6 +11,13 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + version: "0.51.6", + date: "2026-07-19 13:20", + fixed: [ + "Image attachments on support tickets now embed inline in the Gitea issue (rendered preview) instead of just a plain link. Also fixed the admin \"Create Gitea issue\" retry action, which was dropping attachments entirely and only ever sent the ticket description.", + ], + }, { version: "0.51.5", date: "2026-07-19 13:05", diff --git a/apps/web/lib/gitea.ts b/apps/web/lib/gitea.ts index 7746872..e002494 100644 --- a/apps/web/lib/gitea.ts +++ b/apps/web/lib/gitea.ts @@ -1,4 +1,5 @@ import { getSiteSetting } from "@/lib/site-settings"; +import { getPublicUrl } from "@/lib/storage"; const LABEL_NAMES: Record = { bug: ["bug"], @@ -26,6 +27,27 @@ async function resolveLabelIds(baseUrl: string, token: string, repo: string, nam } } +/** Shared by ticket creation and the admin retry action, so a retry embeds + * attachments exactly the same way the original attempt would have. Image + * attachments embed inline (`![](url)`) so they render as a preview in the + * Gitea issue instead of just a clickable link — everything else (PDF, + * text, zip) stays a plain link since Gitea can't preview those anyway. */ +export function buildGiteaIssueBody(opts: { + description: string; + userId: string; + attachments: { key: string; contentType: string }[]; +}): string { + const attachmentLines = opts.attachments.map((a) => { + const url = getPublicUrl(a.key); + return a.contentType.startsWith("image/") ? `![attachment](${url})` : `- ${url}`; + }); + return [ + opts.description, + attachmentLines.length > 0 ? `\n**Attachments:**\n${attachmentLines.join("\n")}` : "", + `\n---\nReported via Epicure support form by user \`${opts.userId}\`.`, + ].join("\n"); +} + /** * Opens an issue on the configured Gitea repo for a support ticket. Returns * the issue's HTML URL on success, or null if Gitea isn't configured or the diff --git a/apps/web/package.json b/apps/web/package.json index c212464..994b185 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@epicure/web", - "version": "0.51.5", + "version": "0.51.6", "private": true, "scripts": { "dev": "next dev", diff --git a/package.json b/package.json index cfcfa2b..7535128 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "epicure", - "version": "0.51.5", + "version": "0.51.6", "private": true, "scripts": { "dev": "pnpm --filter web dev",