Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Fixes CI pipeline failures caused by missing Prisma Client generation and TypeScript type safety issues. Added Prisma generation step to CI pipeline, installed missing type dependencies, and resolved 40+ exactOptionalPropertyTypes violations across service layer. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
234 lines
6.2 KiB
TypeScript
234 lines
6.2 KiB
TypeScript
import { Injectable, NotFoundException } from "@nestjs/common";
|
|
import { Prisma } from "@prisma/client";
|
|
import { PrismaService } from "../prisma/prisma.service";
|
|
import { ActivityService } from "../activity/activity.service";
|
|
import type { CreateEventDto, UpdateEventDto, QueryEventsDto } from "./dto";
|
|
|
|
/**
|
|
* Service for managing events
|
|
*/
|
|
@Injectable()
|
|
export class EventsService {
|
|
constructor(
|
|
private readonly prisma: PrismaService,
|
|
private readonly activityService: ActivityService
|
|
) {}
|
|
|
|
/**
|
|
* Create a new event
|
|
*/
|
|
async create(workspaceId: string, userId: string, createEventDto: CreateEventDto) {
|
|
const projectConnection = createEventDto.projectId
|
|
? { connect: { id: createEventDto.projectId } }
|
|
: undefined;
|
|
|
|
const data: Prisma.EventCreateInput = {
|
|
title: createEventDto.title,
|
|
description: createEventDto.description ?? null,
|
|
startTime: createEventDto.startTime,
|
|
endTime: createEventDto.endTime ?? null,
|
|
location: createEventDto.location ?? null,
|
|
workspace: { connect: { id: workspaceId } },
|
|
creator: { connect: { id: userId } },
|
|
allDay: createEventDto.allDay ?? false,
|
|
metadata: createEventDto.metadata
|
|
? (createEventDto.metadata as unknown as Prisma.InputJsonValue)
|
|
: {},
|
|
...(projectConnection && { project: projectConnection }),
|
|
};
|
|
|
|
const event = await this.prisma.event.create({
|
|
data,
|
|
include: {
|
|
creator: {
|
|
select: { id: true, name: true, email: true },
|
|
},
|
|
project: {
|
|
select: { id: true, name: true, color: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
// Log activity
|
|
await this.activityService.logEventCreated(workspaceId, userId, event.id, {
|
|
title: event.title,
|
|
});
|
|
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* Get paginated events with filters
|
|
*/
|
|
async findAll(query: QueryEventsDto) {
|
|
const page = query.page ?? 1;
|
|
const limit = query.limit ?? 50;
|
|
const skip = (page - 1) * limit;
|
|
|
|
// Build where clause
|
|
const where: Prisma.EventWhereInput = query.workspaceId
|
|
? {
|
|
workspaceId: query.workspaceId,
|
|
}
|
|
: {};
|
|
|
|
if (query.projectId) {
|
|
where.projectId = query.projectId;
|
|
}
|
|
|
|
if (query.allDay !== undefined) {
|
|
where.allDay = query.allDay;
|
|
}
|
|
|
|
if (query.startFrom || query.startTo) {
|
|
where.startTime = {};
|
|
if (query.startFrom) {
|
|
where.startTime.gte = query.startFrom;
|
|
}
|
|
if (query.startTo) {
|
|
where.startTime.lte = query.startTo;
|
|
}
|
|
}
|
|
|
|
// Execute queries in parallel
|
|
const [data, total] = await Promise.all([
|
|
this.prisma.event.findMany({
|
|
where,
|
|
include: {
|
|
creator: {
|
|
select: { id: true, name: true, email: true },
|
|
},
|
|
project: {
|
|
select: { id: true, name: true, color: true },
|
|
},
|
|
},
|
|
orderBy: {
|
|
startTime: "asc",
|
|
},
|
|
skip,
|
|
take: limit,
|
|
}),
|
|
this.prisma.event.count({ where }),
|
|
]);
|
|
|
|
return {
|
|
data,
|
|
meta: {
|
|
total,
|
|
page,
|
|
limit,
|
|
totalPages: Math.ceil(total / limit),
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get a single event by ID
|
|
*/
|
|
async findOne(id: string, workspaceId: string) {
|
|
const event = await this.prisma.event.findUnique({
|
|
where: {
|
|
id,
|
|
workspaceId,
|
|
},
|
|
include: {
|
|
creator: {
|
|
select: { id: true, name: true, email: true },
|
|
},
|
|
project: {
|
|
select: { id: true, name: true, color: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!event) {
|
|
throw new NotFoundException(`Event with ID ${id} not found`);
|
|
}
|
|
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* Update an event
|
|
*/
|
|
async update(id: string, workspaceId: string, userId: string, updateEventDto: UpdateEventDto) {
|
|
// Verify event exists
|
|
const existingEvent = await this.prisma.event.findUnique({
|
|
where: { id, workspaceId },
|
|
});
|
|
|
|
if (!existingEvent) {
|
|
throw new NotFoundException(`Event with ID ${id} not found`);
|
|
}
|
|
|
|
// Build update data, only including defined fields (excluding projectId)
|
|
const updateData: Prisma.EventUpdateInput = {};
|
|
if (updateEventDto.title !== undefined) updateData.title = updateEventDto.title;
|
|
if (updateEventDto.description !== undefined)
|
|
updateData.description = updateEventDto.description;
|
|
if (updateEventDto.startTime !== undefined) updateData.startTime = updateEventDto.startTime;
|
|
if (updateEventDto.endTime !== undefined) updateData.endTime = updateEventDto.endTime;
|
|
if (updateEventDto.allDay !== undefined) updateData.allDay = updateEventDto.allDay;
|
|
if (updateEventDto.location !== undefined) updateData.location = updateEventDto.location;
|
|
if (updateEventDto.recurrence !== undefined) {
|
|
updateData.recurrence = updateEventDto.recurrence as unknown as Prisma.InputJsonValue;
|
|
}
|
|
if (updateEventDto.metadata !== undefined) {
|
|
updateData.metadata = updateEventDto.metadata as unknown as Prisma.InputJsonValue;
|
|
}
|
|
// Handle project relation separately
|
|
if (updateEventDto.projectId !== undefined) {
|
|
updateData.project = { connect: { id: updateEventDto.projectId } };
|
|
}
|
|
|
|
const event = await this.prisma.event.update({
|
|
where: {
|
|
id,
|
|
workspaceId,
|
|
},
|
|
data: updateData,
|
|
include: {
|
|
creator: {
|
|
select: { id: true, name: true, email: true },
|
|
},
|
|
project: {
|
|
select: { id: true, name: true, color: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
// Log activity
|
|
await this.activityService.logEventUpdated(workspaceId, userId, id, {
|
|
changes: updateEventDto as Prisma.JsonValue,
|
|
});
|
|
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* Delete an event
|
|
*/
|
|
async remove(id: string, workspaceId: string, userId: string) {
|
|
// Verify event exists
|
|
const event = await this.prisma.event.findUnique({
|
|
where: { id, workspaceId },
|
|
});
|
|
|
|
if (!event) {
|
|
throw new NotFoundException(`Event with ID ${id} not found`);
|
|
}
|
|
|
|
await this.prisma.event.delete({
|
|
where: {
|
|
id,
|
|
workspaceId,
|
|
},
|
|
});
|
|
|
|
// Log activity
|
|
await this.activityService.logEventDeleted(workspaceId, userId, id, {
|
|
title: event.title,
|
|
});
|
|
}
|
|
}
|