Openstatus www.openstatus.dev
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: feed route error handling (#1564)

authored by

Maximilian Kaske and committed by
GitHub
f781b1f0 4cde653a

+80 -77
+80 -77
apps/status-page/src/app/(status-page)/[domain]/(public)/feed/[type]/route.ts
··· 17 17 _request: Request, 18 18 props: { params: Promise<{ domain: string; type: string }> }, 19 19 ) { 20 - const queryClient = getQueryClient(); 21 - const { domain, type } = await props.params; 22 - if (!["rss", "atom"].includes(type)) return notFound(); 20 + try { 21 + const queryClient = getQueryClient(); 22 + const { domain, type } = await props.params; 23 + if (!["rss", "atom"].includes(type)) return notFound(); 23 24 24 - const page = await queryClient.fetchQuery( 25 - trpc.page.getPageBySlug.queryOptions({ slug: domain }), 26 - ); 27 - if (!page) return notFound(); 25 + const page = await queryClient.fetchQuery( 26 + trpc.page.getPageBySlug.queryOptions({ slug: domain }), 27 + ); 28 + if (!page) return notFound(); 28 29 29 - if (page.passwordProtected) { 30 - const url = new URL(_request.url); 31 - const password = url.searchParams.get("pw"); 32 - if (password !== page.password) return unauthorized(); 33 - } 30 + if (page.passwordProtected) { 31 + const url = new URL(_request.url); 32 + const password = url.searchParams.get("pw"); 33 + if (password !== page.password) return unauthorized(); 34 + } 34 35 35 - const baseUrl = getBaseUrl({ 36 - slug: page.slug, 37 - customDomain: page.customDomain, 38 - }); 36 + const baseUrl = getBaseUrl({ 37 + slug: page.slug, 38 + customDomain: page.customDomain, 39 + }); 39 40 40 - const feed = new Feed({ 41 - id: `${baseUrl}/feed/${type}`, 42 - title: page.title, 43 - description: page.description, 44 - generator: "OpenStatus - Status Page Updates", 45 - feedLinks: { 46 - rss: `${baseUrl}/feed/rss`, 47 - atom: `${baseUrl}/feed/atom`, 48 - }, 49 - link: baseUrl, 50 - author: { 51 - name: page.title, 52 - email: 53 - page.contactUrl?.startsWith("mailto:") && page.contactUrl !== null 54 - ? page.contactUrl.slice(7) 55 - : undefined, 56 - link: page.homepageUrl || baseUrl, 57 - }, 58 - copyright: `Copyright ${new Date() 59 - .getFullYear() 60 - .toString()} openstatus.dev`, 61 - language: "en-US", 62 - updated: new Date(), 63 - ttl: 60, 64 - }); 41 + const feed = new Feed({ 42 + id: `${baseUrl}/feed/${type}`, 43 + title: page.title, 44 + description: page.description, 45 + generator: "OpenStatus - Status Page Updates", 46 + feedLinks: { 47 + rss: `${baseUrl}/feed/rss`, 48 + atom: `${baseUrl}/feed/atom`, 49 + }, 50 + link: baseUrl, 51 + author: { 52 + name: page.title, 53 + email: 54 + page.contactUrl?.startsWith("mailto:") && page.contactUrl !== null 55 + ? page.contactUrl.slice(7) 56 + : undefined, 57 + link: page.homepageUrl || baseUrl, 58 + }, 59 + copyright: `Copyright ${new Date() 60 + .getFullYear() 61 + .toString()} openstatus.dev`, 62 + language: "en-US", 63 + updated: new Date(), 64 + ttl: 60, 65 + }); 65 66 66 - for (const maintenance of page.maintenances) { 67 - const maintenanceUrl = `${baseUrl}/events/maintenance/${maintenance.id}`; 68 - feed.addItem({ 69 - id: maintenanceUrl, 70 - title: `Maintenance - ${maintenance.title}`, 71 - link: maintenanceUrl, 72 - description: maintenance.message, 73 - date: maintenance.updatedAt ?? maintenance.createdAt ?? new Date(), 74 - }); 75 - } 67 + for (const maintenance of page.maintenances ?? []) { 68 + const maintenanceUrl = `${baseUrl}/events/maintenance/${maintenance.id}`; 69 + feed.addItem({ 70 + id: maintenanceUrl, 71 + title: `Maintenance - ${maintenance.title}`, 72 + link: maintenanceUrl, 73 + description: maintenance.message, 74 + date: maintenance.updatedAt ?? maintenance.createdAt ?? new Date(), 75 + }); 76 + } 76 77 77 - for (const statusReport of page.statusReports) { 78 - const statusReportUrl = `${baseUrl}/events/report/${statusReport.id}`; 79 - const status = STATUS_LABELS[statusReport.status]; 80 - const statusReportUpdates = statusReport.statusReportUpdates 81 - .map((update) => { 82 - const updateStatus = STATUS_LABELS[update.status]; 83 - return `${updateStatus}: ${update.message}.`; 84 - }) 85 - .join("\n\n"); 78 + for (const statusReport of page.statusReports ?? []) { 79 + const statusReportUrl = `${baseUrl}/events/report/${statusReport.id}`; 80 + const status = STATUS_LABELS[statusReport.status] ?? statusReport.status; 81 + const statusReportUpdates = (statusReport.statusReportUpdates ?? []) 82 + .map((update) => { 83 + const updateStatus = STATUS_LABELS[update.status] ?? update.status; 84 + return `${updateStatus}: ${update.message}.`; 85 + }) 86 + .join("\n\n"); 86 87 87 - feed.addItem({ 88 - id: statusReportUrl, 89 - title: `${status} - ${statusReport.title}`, 90 - link: statusReportUrl, 91 - description: statusReportUpdates, 92 - date: statusReport.updatedAt ?? statusReport.createdAt ?? new Date(), 93 - }); 94 - } 88 + feed.addItem({ 89 + id: statusReportUrl, 90 + title: `${status} - ${statusReport.title}`, 91 + link: statusReportUrl, 92 + description: statusReportUpdates, 93 + date: statusReport.updatedAt ?? statusReport.createdAt ?? new Date(), 94 + }); 95 + } 95 96 96 - feed.items.sort( 97 - (a, b) => (a.date as Date).getTime() - (b.date as Date).getTime(), 98 - ); 97 + feed.items.sort((a, b) => a.date.getTime() - b.date.getTime()); 99 98 100 - const res = type === "atom" ? feed.atom1() : feed.rss2(); 99 + const res = type === "atom" ? feed.atom1() : feed.rss2(); 101 100 102 - return new Response(res, { 103 - headers: { 104 - "Content-Type": "application/xml; charset=utf-8", 105 - }, 106 - }); 101 + return new Response(res, { 102 + headers: { 103 + "Content-Type": "application/xml; charset=utf-8", 104 + }, 105 + }); 106 + } catch (error) { 107 + console.error("Error generating feed:", error); 108 + throw error; 109 + } 107 110 }