feat(auth): implement user authentication with JWT and NextAuth
- Added user registration and login functionality with JWT authentication. - Created auth controller, service, and module in the backend. - Implemented user model and user products management. - Integrated NextAuth for session management on the frontend. - Added middleware for protecting routes and handling public access. - Updated frontend API routes to include authorization headers. - Enhanced recipe and user product models to support ownership and visibility. - Created registration and login pages in the frontend. - Added necessary types for NextAuth session management.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import { IsInt, IsString, IsOptional, IsBoolean } from 'class-validator';
|
||||
|
||||
export class UpsertUserProductDto {
|
||||
@IsInt()
|
||||
productId: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
note?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
preferredBrand?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
preferredStore?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isPrivate?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { UserProductsService } from './user-products.service';
|
||||
import { UpsertUserProductDto } from './dto/upsert-user-product.dto';
|
||||
import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
|
||||
@Controller('user-products')
|
||||
export class UserProductsController {
|
||||
constructor(private readonly service: UserProductsService) {}
|
||||
|
||||
@Get()
|
||||
findAll(@CurrentUser() user: { userId: number }) {
|
||||
return this.service.findAll(user.userId);
|
||||
}
|
||||
|
||||
@Post()
|
||||
upsert(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Body() dto: UpsertUserProductDto,
|
||||
) {
|
||||
return this.service.upsert(user.userId, dto);
|
||||
}
|
||||
|
||||
@Delete(':productId')
|
||||
remove(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Param('productId', ParseIntPipe) productId: number,
|
||||
) {
|
||||
return this.service.remove(user.userId, productId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserProductsController } from './user-products.controller';
|
||||
import { UserProductsService } from './user-products.service';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
controllers: [UserProductsController],
|
||||
providers: [UserProductsService],
|
||||
})
|
||||
export class UserProductsModule {}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { UpsertUserProductDto } from './dto/upsert-user-product.dto';
|
||||
|
||||
const PRODUCT_INCLUDE = {
|
||||
product: {
|
||||
include: {
|
||||
nutrition: true,
|
||||
tags: { include: { tag: true } },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class UserProductsService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
findAll(userId: number) {
|
||||
return this.prisma.userProduct.findMany({
|
||||
where: { userId },
|
||||
include: PRODUCT_INCLUDE,
|
||||
orderBy: { updatedAt: 'desc' },
|
||||
});
|
||||
}
|
||||
|
||||
findOne(userId: number, productId: number) {
|
||||
return this.prisma.userProduct.findUnique({
|
||||
where: { userId_productId: { userId, productId } },
|
||||
include: PRODUCT_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
upsert(userId: number, dto: UpsertUserProductDto) {
|
||||
const { productId, ...data } = dto;
|
||||
return this.prisma.userProduct.upsert({
|
||||
where: { userId_productId: { userId, productId } },
|
||||
create: { userId, productId, ...data },
|
||||
update: data,
|
||||
include: PRODUCT_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
remove(userId: number, productId: number) {
|
||||
return this.prisma.userProduct.delete({
|
||||
where: { userId_productId: { userId, productId } },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user