feat(api): add user search endpoint and normalize response data and validation

This commit is contained in:
Dominik 2025-06-17 21:46:38 +02:00
parent b9dda271af
commit 16a5825dd3
Signed by: dominik
GPG key ID: 06A4003FC5049644
14 changed files with 574 additions and 368 deletions

View file

@ -1,6 +1,19 @@
import { prisma } from '@/prisma';
import { auth } from '@/auth';
import { NextResponse } from 'next/server';
import { z } from 'zod/v4';
const postEventSchema = z
.object({
title: z.string().min(1, 'Title is required'),
description: z.string().optional(),
start_time: z.iso.datetime(),
end_time: z.iso.datetime(),
location: z.string().optional().default(''),
})
.refine((data) => new Date(data.start_time) < new Date(data.end_time), {
error: 'Start time must be before end time',
});
/**
* @swagger
@ -74,11 +87,31 @@ export const GET = auth(async (req) => {
{ participants: { some: { user_id: dbUser.id } } },
],
},
include: {
organizer: true,
select: {
id: true,
title: true,
description: true,
start_time: true,
end_time: true,
status: true,
location: true,
created_at: true,
updated_at: true,
organizer: {
select: {
id: true,
name: true,
},
},
participants: {
include: {
user: true,
select: {
user: {
select: {
id: true,
name: true,
},
},
status: true,
},
},
},
@ -86,23 +119,7 @@ export const GET = auth(async (req) => {
return NextResponse.json({
success: true,
events: userEvents.map((event) => ({
id: event.id,
title: event.title,
description: event.description,
start_time: event.start_time,
end_time: event.end_time,
status: event.status,
location: event.location,
organizer: {
id: event.organizer.id,
name: event.organizer.name,
},
participants: event.participants.map((participant) => ({
id: participant.user.id,
name: participant.user.name,
})),
})),
events: userEvents,
});
});
@ -150,14 +167,14 @@ export const GET = auth(async (req) => {
* event:
* $ref: '#/components/schemas/Event'
* 400:
* description: Missing required fields.
* description: Bad request due to invalid input data.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* example:
* success: false
* message: Missing required fields
* message: 'Invalid input data'
* 401:
* description: Not authenticated.
* content:
@ -189,36 +206,19 @@ export const POST = auth(async (req) => {
{ status: 404 },
);
const body = await req.json();
const { title, description, start_time, end_time, location } = body;
if (!title || !start_time || !end_time) {
const dataRaw = await req.json();
const data = await postEventSchema.safeParseAsync(dataRaw);
if (!data.success) {
return NextResponse.json(
{ success: false, message: 'Missing required fields' },
{ status: 400 },
);
}
if (isNaN(new Date(start_time).getTime())) {
return NextResponse.json(
{ success: false, message: 'Invalid start_time' },
{ status: 400 },
);
}
if (isNaN(new Date(end_time).getTime())) {
return NextResponse.json(
{ success: false, message: 'Invalid end_time' },
{ status: 400 },
);
}
if (new Date(start_time) >= new Date(end_time)) {
return NextResponse.json(
{ success: false, message: 'start_time must be before end_time' },
{
success: false,
message: 'Invalid request data',
errors: data.error.issues,
},
{ status: 400 },
);
}
const { title, description, start_time, end_time, location } = data.data;
const newEvent = await prisma.meeting.create({
data: {
@ -226,26 +226,41 @@ export const POST = auth(async (req) => {
description,
start_time,
end_time,
location: location || '',
location,
organizer_id: req.auth.user.id,
},
select: {
id: true,
title: true,
description: true,
start_time: true,
end_time: true,
status: true,
location: true,
created_at: true,
updated_at: true,
organizer: {
select: {
id: true,
name: true,
},
},
participants: {
select: {
user: {
select: {
id: true,
name: true,
},
},
status: true,
},
},
},
});
return NextResponse.json({
success: true,
event: {
id: newEvent.id,
title: newEvent.title,
description: newEvent.description,
start_time: newEvent.start_time,
end_time: newEvent.end_time,
status: newEvent.status,
location: newEvent.location,
organizer: {
id: req.auth.user.id,
name: req.auth.user.name,
},
participants: [],
},
event: newEvent,
});
});