feat: init sitemaps generation

This commit is contained in:
swve 2024-09-26 23:29:05 +02:00
parent 09c0444284
commit 41a11c5f83
3 changed files with 88 additions and 3 deletions

View file

@ -0,0 +1,61 @@
import { getUriWithOrg } from '@services/config/config';
import { getOrgCourses } from '@services/courses/courses';
import { getOrganizationContextInfo } from '@services/organizations/orgs';
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const orgSlug = request.headers.get('X-Sitemap-Orgslug');
if (!orgSlug) {
return NextResponse.json({ error: 'Missing X-Sitemap-Orgslug header' }, { status: 400 });
}
const orgInfo = await getOrganizationContextInfo(orgSlug, null);
const courses = await getOrgCourses(orgSlug, null);
const host = request.headers.get('host');
if (!host) {
return NextResponse.json({ error: 'Missing host header' }, { status: 400 });
}
const baseUrl = getUriWithOrg(orgSlug, '/');
const sitemapUrls: SitemapUrl[] = [
{ loc: baseUrl, priority: 1.0, changefreq: 'daily' },
...courses.map((course: { course_uuid: string }) => ({
loc: `${baseUrl}course/${course.course_uuid.replace('course_', '')}`,
priority: 0.8,
changefreq: 'weekly'
}))
];
const sitemap = generateSitemap(baseUrl, sitemapUrls);
return new NextResponse(sitemap, {
headers: {
'Content-Type': 'application/xml',
},
});
}
interface SitemapUrl {
loc: string;
priority: number;
changefreq: string;
}
function generateSitemap(baseUrl: string, urls: SitemapUrl[]): string {
const urlEntries = urls.map(({ loc, priority, changefreq }) => `
<url>
<loc>${loc}</loc>
<priority>${priority.toFixed(1)}</priority>
<changefreq>${changefreq}</changefreq>
</url>`).join('');
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urlEntries}
</urlset>`;
}

View file

@ -21,6 +21,7 @@ export const config = {
* 5. all root files inside /public (e.g. /favicon.ico) * 5. all root files inside /public (e.g. /favicon.ico)
*/ */
'/((?!api|_next|fonts|umami|examples|[\\w-]+\\.\\w+).*)', '/((?!api|_next|fonts|umami|examples|[\\w-]+\\.\\w+).*)',
'/sitemap.xml',
], ],
} }
@ -99,6 +100,29 @@ export default async function middleware(req: NextRequest) {
} }
} }
if (pathname.startsWith('/sitemap.xml')) {
let orgslug: string;
if (hosting_mode === 'multi') {
orgslug = fullhost
? fullhost.replace(`.${LEARNHOUSE_DOMAIN}`, '')
: (default_org as string);
} else {
// Single hosting mode
orgslug = default_org as string;
}
const sitemapUrl = new URL(`/api/sitemap`, req.url);
// Create a response object
const response = NextResponse.rewrite(sitemapUrl);
// Set the orgslug in a header
response.headers.set('X-Sitemap-Orgslug', orgslug);
return response;
}
// Multi Organization Mode // Multi Organization Mode
if (hosting_mode === 'multi') { if (hosting_mode === 'multi') {
// Get the organization slug from the URL // Get the organization slug from the URL

View file

@ -12,12 +12,12 @@ import {
*/ */
export async function getOrgCourses( export async function getOrgCourses(
org_id: number, org_slug: string,
next: any, next: any,
access_token: any access_token?: any
) { ) {
const result: any = await fetch( const result: any = await fetch(
`${getAPIUrl()}courses/org_slug/${org_id}/page/1/limit/10`, `${getAPIUrl()}courses/org_slug/${org_slug}/page/1/limit/10`,
RequestBodyWithAuthHeader('GET', null, next, access_token) RequestBodyWithAuthHeader('GET', null, next, access_token)
) )
const res = await errorHandling(result) const res = await errorHandling(result)