feat(backend): add fastify api, auth, prisma schema and jobs
This commit is contained in:
117
apps/backend/src/modules/wishes/wishes.service.ts
Normal file
117
apps/backend/src/modules/wishes/wishes.service.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { PrismaClient, Wish, WishStatus } from '@prisma/client';
|
||||
import {
|
||||
ConflictError,
|
||||
ForbiddenError,
|
||||
NotFoundError,
|
||||
} from '../../utils/errors.js';
|
||||
import type { CreateWishInput, UpdateWishInput } from '@family-wishlist/shared';
|
||||
|
||||
type Status = 'active' | 'archived' | 'completed' | 'deleted';
|
||||
|
||||
const statusMap: Record<Status, WishStatus> = {
|
||||
active: 'ACTIVE',
|
||||
archived: 'ARCHIVED',
|
||||
completed: 'COMPLETED',
|
||||
deleted: 'DELETED',
|
||||
};
|
||||
|
||||
export class WishesService {
|
||||
constructor(private readonly prisma: PrismaClient) {}
|
||||
|
||||
list(userId: string, status: Status): Promise<Wish[]> {
|
||||
return this.prisma.wish.findMany({
|
||||
where: { userId, status: statusMap[status] },
|
||||
orderBy: [{ status: 'asc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
|
||||
async getOwned(userId: string, id: string): Promise<Wish> {
|
||||
const wish = await this.prisma.wish.findUnique({ where: { id } });
|
||||
if (!wish) throw new NotFoundError('Wish');
|
||||
if (wish.userId !== userId) throw new ForbiddenError();
|
||||
return wish;
|
||||
}
|
||||
|
||||
create(userId: string, input: CreateWishInput): Promise<Wish> {
|
||||
return this.prisma.wish.create({
|
||||
data: {
|
||||
userId,
|
||||
title: input.title,
|
||||
price: input.price ?? null,
|
||||
currency: input.currency ?? 'RUB',
|
||||
url: input.url ?? null,
|
||||
comment: input.comment ?? null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async update(userId: string, id: string, input: UpdateWishInput): Promise<Wish> {
|
||||
await this.getOwned(userId, id);
|
||||
const data: Record<string, unknown> = {};
|
||||
if (input.title !== undefined) data.title = input.title;
|
||||
if (input.price !== undefined) data.price = input.price ?? null;
|
||||
if (input.currency !== undefined) data.currency = input.currency ?? 'RUB';
|
||||
if (input.url !== undefined) data.url = input.url ?? null;
|
||||
if (input.comment !== undefined) data.comment = input.comment ?? null;
|
||||
return this.prisma.wish.update({ where: { id }, data });
|
||||
}
|
||||
|
||||
async archive(userId: string, id: string): Promise<Wish> {
|
||||
const wish = await this.getOwned(userId, id);
|
||||
if (wish.status === 'ARCHIVED') return wish;
|
||||
if (wish.status === 'DELETED') {
|
||||
throw new ConflictError('Cannot archive a deleted wish; restore it first');
|
||||
}
|
||||
return this.prisma.wish.update({
|
||||
where: { id },
|
||||
data: { status: 'ARCHIVED', archivedAt: new Date(), completedAt: null, deletedAt: null },
|
||||
});
|
||||
}
|
||||
|
||||
async complete(userId: string, id: string): Promise<Wish> {
|
||||
const wish = await this.getOwned(userId, id);
|
||||
if (wish.status === 'COMPLETED') return wish;
|
||||
if (wish.status === 'DELETED') {
|
||||
throw new ConflictError('Cannot complete a deleted wish; restore it first');
|
||||
}
|
||||
return this.prisma.wish.update({
|
||||
where: { id },
|
||||
data: { status: 'COMPLETED', completedAt: new Date(), archivedAt: null, deletedAt: null },
|
||||
});
|
||||
}
|
||||
|
||||
async softDelete(userId: string, id: string): Promise<Wish> {
|
||||
const wish = await this.getOwned(userId, id);
|
||||
if (wish.status === 'DELETED') return wish;
|
||||
return this.prisma.wish.update({
|
||||
where: { id },
|
||||
data: { status: 'DELETED', deletedAt: new Date() },
|
||||
});
|
||||
}
|
||||
|
||||
async restore(userId: string, id: string): Promise<Wish> {
|
||||
const wish = await this.getOwned(userId, id);
|
||||
if (wish.status === 'ACTIVE') return wish;
|
||||
return this.prisma.wish.update({
|
||||
where: { id },
|
||||
data: { status: 'ACTIVE', archivedAt: null, completedAt: null, deletedAt: null },
|
||||
});
|
||||
}
|
||||
|
||||
async duplicate(userId: string, id: string): Promise<Wish> {
|
||||
const source = await this.getOwned(userId, id);
|
||||
return this.prisma.wish.create({
|
||||
data: {
|
||||
userId,
|
||||
title: source.title,
|
||||
price: source.price,
|
||||
currency: source.currency,
|
||||
url: source.url,
|
||||
comment: source.comment,
|
||||
imageUrl: source.imageSource === 'UPLOADED' ? null : source.imageUrl,
|
||||
imageSource: source.imageSource === 'UPLOADED' ? 'DEFAULT' : source.imageSource,
|
||||
sourceWishId: source.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user