NeahNew/app/api/missions/[missionId]/change-guardian/route.ts
2026-01-09 16:50:21 +01:00

165 lines
4.5 KiB
TypeScript

import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { logger } from '@/lib/logger';
export async function POST(
request: Request,
props: { params: Promise<{ missionId: string }> }
) {
const params = await props.params;
const { missionId } = params;
try {
// Check authentication
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json();
const { guardianRole, oldUserId, newUserId, oldUserEmail, newUserEmail } = body;
if (!guardianRole || !newUserId) {
return NextResponse.json(
{ error: 'guardianRole and newUserId are required' },
{ status: 400 }
);
}
// Get mission details
const mission = await prisma.mission.findUnique({
where: { id: missionId },
select: {
id: true,
name: true,
creatorId: true,
leantimeProjectId: true,
outlineCollectionId: true,
rocketChatChannelId: true,
giteaRepositoryUrl: true,
},
});
if (!mission) {
return NextResponse.json({ error: 'Mission not found' }, { status: 404 });
}
// Check if user is authorized (creator or admin)
const isCreator = mission.creatorId === session.user.id;
const isAdmin = session.user.role?.includes('admin');
if (!isCreator && !isAdmin) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Map guardian role to database role
const roleMap: Record<string, string> = {
'temps': 'temps',
'parole': 'parole',
'memoire': 'memoire',
};
const dbRole = roleMap[guardianRole];
if (!dbRole) {
return NextResponse.json({ error: 'Invalid guardian role' }, { status: 400 });
}
// Update the guardian in database
// First, remove old guardian if exists
if (oldUserId) {
await prisma.missionUser.deleteMany({
where: {
missionId,
userId: oldUserId,
role: dbRole,
},
});
}
// Then add new guardian
await prisma.missionUser.create({
data: {
missionId,
userId: newUserId,
role: dbRole,
},
});
// Extract repo name from Gitea URL
let repoName = '';
if (mission.giteaRepositoryUrl) {
try {
const url = new URL(mission.giteaRepositoryUrl);
const pathParts = url.pathname.split('/').filter(Boolean);
repoName = pathParts[pathParts.length - 1] || '';
} catch {
const match = mission.giteaRepositoryUrl.match(/\/([^\/]+)\/?$/);
repoName = match ? match[1] : '';
}
}
// Prepare data for N8N webhook
const n8nData = {
missionId: mission.id,
missionName: mission.name,
guardianRole,
oldUserId,
newUserId,
oldUserEmail,
newUserEmail,
repoName,
leantimeProjectId: mission.leantimeProjectId || '',
outlineCollectionId: mission.outlineCollectionId || '',
rocketChatChannelId: mission.rocketChatChannelId || '',
giteaRepositoryUrl: mission.giteaRepositoryUrl || '',
};
// Call N8N webhook
const webhookUrl = process.env.N8N_CHANGE_GUARDIAN_WEBHOOK_URL || 'https://brain.slm-lab.net/webhook/NeahMissionChangeGuardian';
const apiKey = process.env.N8N_API_KEY || '';
logger.debug('Calling N8N ChangeGuardian webhook', {
missionId,
guardianRole,
oldUserId,
newUserId,
});
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
},
body: JSON.stringify(n8nData),
});
if (!response.ok) {
const errorText = await response.text();
logger.error('N8N ChangeGuardian webhook error', {
status: response.status,
error: errorText.substring(0, 200),
});
// Continue even if N8N fails, database is already updated
}
return NextResponse.json({
success: true,
message: 'Guardian changed successfully',
});
} catch (error) {
logger.error('Error changing guardian', {
error: error instanceof Error ? error.message : String(error),
missionId,
});
return NextResponse.json(
{ error: 'Failed to change guardian', details: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}