feat: add isPrivate field to Product model and implement private product creation and retrieval
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
-- Privata produkter: skapade av användare, synliga bara för ägaren
|
||||
ALTER TABLE `Product` ADD COLUMN `isPrivate` BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -52,6 +52,7 @@ model Product {
|
||||
userProducts UserProduct[]
|
||||
categoryId Int?
|
||||
categoryRef Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
isPrivate Boolean @default(false)
|
||||
}
|
||||
|
||||
model Category {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { IsNotEmpty, IsString, MaxLength } from 'class-validator';
|
||||
import { IsInt, IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
|
||||
|
||||
export class CreateProductDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(191)
|
||||
name!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
categoryId?: number;
|
||||
}
|
||||
|
||||
@@ -94,12 +94,27 @@ export class ProductsController {
|
||||
return this.productsService.findDeleted();
|
||||
}
|
||||
|
||||
// Inloggad användares egna privata produkter (måste vara före :id)
|
||||
@Get('mine')
|
||||
findMine(@Request() req: { user: { id: number } }) {
|
||||
return this.productsService.findByOwner(req.user.id);
|
||||
}
|
||||
|
||||
// Tillgänglig för alla inloggade användare
|
||||
@Get(':id')
|
||||
findOne(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.productsService.findOne(id);
|
||||
}
|
||||
|
||||
// Skapa en privat produkt för den inloggade användaren
|
||||
@Post('private')
|
||||
createPrivate(
|
||||
@Body() body: CreateProductDto,
|
||||
@Request() req: { user: { id: number } },
|
||||
) {
|
||||
return this.productsService.createPrivate(body, req.user.id);
|
||||
}
|
||||
|
||||
@UseGuards(PremiumOrAdminGuard)
|
||||
@Get(':id/suggest-category')
|
||||
@Throttle({ default: { ttl: 60_000, limit: 20 } })
|
||||
|
||||
@@ -19,6 +19,7 @@ export class ProductsService {
|
||||
return this.prisma.product.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
isPrivate: false,
|
||||
...(filters?.subcategory ? { subcategory: filters.subcategory } : {}),
|
||||
...(filters?.tag
|
||||
? { tags: { some: { tag: { name: filters.tag } } } }
|
||||
@@ -33,6 +34,45 @@ export class ProductsService {
|
||||
});
|
||||
}
|
||||
|
||||
async findByOwner(userId: number) {
|
||||
return this.prisma.product.findMany({
|
||||
where: { ownerId: userId, isPrivate: true, isActive: true },
|
||||
select: { id: true, name: true, canonicalName: true, categoryId: true },
|
||||
orderBy: { name: 'asc' },
|
||||
});
|
||||
}
|
||||
|
||||
async createPrivate(data: CreateProductDto, userId: number) {
|
||||
const name = data.name.trim();
|
||||
// Privata produkters normalizedName är prefixade för att undvika kollision
|
||||
const normalizedName = `private:${userId}:${normalizeName(name)}`;
|
||||
|
||||
const existing = await this.prisma.product.findUnique({
|
||||
where: { normalizedName },
|
||||
});
|
||||
|
||||
if (existing && existing.isActive) return existing;
|
||||
|
||||
if (existing) {
|
||||
return this.prisma.product.update({
|
||||
where: { id: existing.id },
|
||||
data: { isActive: true, deletedAt: null, name, canonicalName: name },
|
||||
});
|
||||
}
|
||||
|
||||
return this.prisma.product.create({
|
||||
data: {
|
||||
name,
|
||||
normalizedName,
|
||||
canonicalName: name,
|
||||
isActive: true,
|
||||
isPrivate: true,
|
||||
ownerId: userId,
|
||||
...(data.categoryId != null ? { categoryId: data.categoryId } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findDuplicateCandidates() {
|
||||
const products = await this.prisma.product.findMany({
|
||||
where: {
|
||||
@@ -107,6 +147,7 @@ export class ProductsService {
|
||||
canonicalName: name,
|
||||
isActive: true,
|
||||
deletedAt: null,
|
||||
...(data.categoryId != null ? { categoryId: data.categoryId } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user