feat: make pantry items and meal plan entries user-scoped; update related services and controllers
This commit is contained in:
@@ -1,33 +1,52 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common';
|
||||
import { MealPlanService } from './meal-plan.service';
|
||||
import { CreateMealPlanEntryDto } from './dto/create-meal-plan-entry.dto';
|
||||
import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
|
||||
@Controller('meal-plan')
|
||||
export class MealPlanController {
|
||||
constructor(private readonly mealPlanService: MealPlanService) {}
|
||||
|
||||
@Get()
|
||||
findByRange(@Query('from') from: string, @Query('to') to: string) {
|
||||
return this.mealPlanService.findByRange(from, to);
|
||||
findByRange(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Query('from') from: string,
|
||||
@Query('to') to: string,
|
||||
) {
|
||||
return this.mealPlanService.findByRange(user.userId, from, to);
|
||||
}
|
||||
|
||||
@Get('shopping-list')
|
||||
shoppingList(@Query('from') from: string, @Query('to') to: string) {
|
||||
return this.mealPlanService.shoppingList(from, to);
|
||||
shoppingList(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Query('from') from: string,
|
||||
@Query('to') to: string,
|
||||
) {
|
||||
return this.mealPlanService.shoppingList(user.userId, from, to);
|
||||
}
|
||||
|
||||
@Get('inventory-compare')
|
||||
inventoryCompare(@Query('from') from: string, @Query('to') to: string) {
|
||||
return this.mealPlanService.inventoryCompare(from, to);
|
||||
inventoryCompare(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Query('from') from: string,
|
||||
@Query('to') to: string,
|
||||
) {
|
||||
return this.mealPlanService.inventoryCompare(user.userId, from, to);
|
||||
}
|
||||
|
||||
@Post()
|
||||
upsert(@Body() dto: CreateMealPlanEntryDto) {
|
||||
return this.mealPlanService.upsert(dto);
|
||||
upsert(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Body() dto: CreateMealPlanEntryDto,
|
||||
) {
|
||||
return this.mealPlanService.upsert(user.userId, dto);
|
||||
}
|
||||
|
||||
@Delete(':date')
|
||||
removeByDate(@Param('date') date: string) {
|
||||
return this.mealPlanService.removeByDate(date);
|
||||
removeByDate(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Param('date') date: string,
|
||||
) {
|
||||
return this.mealPlanService.removeByDate(user.userId, date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,10 @@ export class MealPlanService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
/** Hämta matplan för ett datumintervall (default: nuvarande vecka) */
|
||||
async findByRange(from: string, to: string) {
|
||||
async findByRange(userId: number, from: string, to: string) {
|
||||
return this.prisma.mealPlanEntry.findMany({
|
||||
where: {
|
||||
userId,
|
||||
date: { gte: new Date(from), lte: new Date(to) },
|
||||
},
|
||||
include: { recipe: { select: recipeSelect } },
|
||||
@@ -33,28 +34,43 @@ export class MealPlanService {
|
||||
}
|
||||
|
||||
/** Sätt recept för ett datum (upsert — ett recept per dag) */
|
||||
async upsert(dto: CreateMealPlanEntryDto) {
|
||||
async upsert(userId: number, dto: CreateMealPlanEntryDto) {
|
||||
const date = new Date(dto.date);
|
||||
return this.prisma.mealPlanEntry.upsert({
|
||||
where: { date },
|
||||
create: { date, recipeId: dto.recipeId, servings: dto.servings ?? null },
|
||||
where: {
|
||||
userId_date: {
|
||||
userId,
|
||||
date,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
date,
|
||||
recipeId: dto.recipeId,
|
||||
servings: dto.servings ?? null,
|
||||
},
|
||||
update: { recipeId: dto.recipeId, servings: dto.servings ?? null },
|
||||
include: { recipe: { select: recipeSelect } },
|
||||
});
|
||||
}
|
||||
|
||||
/** Ta bort matplanspost för ett datum */
|
||||
async removeByDate(date: string) {
|
||||
async removeByDate(userId: number, date: string) {
|
||||
const entry = await this.prisma.mealPlanEntry.findUnique({
|
||||
where: { date: new Date(date) },
|
||||
where: {
|
||||
userId_date: {
|
||||
userId,
|
||||
date: new Date(date),
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!entry) throw new NotFoundException('Ingen matplanspost för detta datum');
|
||||
return this.prisma.mealPlanEntry.delete({ where: { id: entry.id } });
|
||||
}
|
||||
|
||||
/** Samlad ingredienslista för ett datumintervall */
|
||||
async shoppingList(from: string, to: string) {
|
||||
const entries = await this.findByRange(from, to);
|
||||
async shoppingList(userId: number, from: string, to: string) {
|
||||
const entries = await this.findByRange(userId, from, to);
|
||||
|
||||
// Summera ingredienser per produkt+enhet (skalat per portionsantal)
|
||||
const map = new Map<string, { productId: number; name: string; quantity: number; unit: string }>();
|
||||
@@ -83,11 +99,14 @@ export class MealPlanService {
|
||||
}
|
||||
|
||||
/** Jämför veckans ingrediensbehov mot inventariet */
|
||||
async inventoryCompare(from: string, to: string) {
|
||||
const entries = await this.findByRange(from, to);
|
||||
async inventoryCompare(userId: number, from: string, to: string) {
|
||||
const entries = await this.findByRange(userId, from, to);
|
||||
|
||||
// Hämta pantry-produkter — dessa anses alltid tillgängliga
|
||||
const pantryItems = await this.prisma.pantryItem.findMany({ select: { productId: true } });
|
||||
const pantryItems = await this.prisma.pantryItem.findMany({
|
||||
where: { userId },
|
||||
select: { productId: true },
|
||||
});
|
||||
const pantryProductIds = new Set(pantryItems.map((p) => p.productId));
|
||||
|
||||
// Aggregera ingredienser per produkt+enhet (skalat per portionsantal)
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post } from '@nestjs/common';
|
||||
import { PantryService } from './pantry.service';
|
||||
import { CreatePantryItemDto } from './dto/create-pantry-item.dto';
|
||||
import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
|
||||
@Controller('pantry')
|
||||
export class PantryController {
|
||||
constructor(private readonly pantryService: PantryService) {}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.pantryService.findAll();
|
||||
findAll(@CurrentUser() user: { userId: number }) {
|
||||
return this.pantryService.findAll(user.userId);
|
||||
}
|
||||
|
||||
@Post()
|
||||
create(@Body() body: CreatePantryItemDto) {
|
||||
return this.pantryService.create(body);
|
||||
create(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Body() body: CreatePantryItemDto,
|
||||
) {
|
||||
return this.pantryService.create(user.userId, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.pantryService.remove(id);
|
||||
remove(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
) {
|
||||
return this.pantryService.remove(user.userId, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import { CreatePantryItemDto } from './dto/create-pantry-item.dto';
|
||||
export class PantryService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
findAll() {
|
||||
findAll(userId: number) {
|
||||
return this.prisma.pantryItem.findMany({
|
||||
where: { userId },
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
@@ -17,9 +18,14 @@ export class PantryService {
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: CreatePantryItemDto) {
|
||||
async create(userId: number, data: CreatePantryItemDto) {
|
||||
const existing = await this.prisma.pantryItem.findUnique({
|
||||
where: { productId: data.productId },
|
||||
where: {
|
||||
userId_productId: {
|
||||
userId,
|
||||
productId: data.productId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
@@ -27,13 +33,15 @@ export class PantryService {
|
||||
}
|
||||
|
||||
return this.prisma.pantryItem.create({
|
||||
data: { productId: data.productId },
|
||||
data: { userId, productId: data.productId },
|
||||
include: { product: true },
|
||||
});
|
||||
}
|
||||
|
||||
async remove(id: number) {
|
||||
const item = await this.prisma.pantryItem.findUnique({ where: { id } });
|
||||
async remove(userId: number, id: number) {
|
||||
const item = await this.prisma.pantryItem.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
throw new NotFoundException(`PantryItem med id ${id} hittades inte`);
|
||||
|
||||
Reference in New Issue
Block a user