mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init sitemaps generation
This commit is contained in:
parent
09c0444284
commit
41a11c5f83
3 changed files with 88 additions and 3 deletions
61
apps/web/app/api/sitemap/route.ts
Normal file
61
apps/web/app/api/sitemap/route.ts
Normal 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>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue