diff --git a/backend/src/auth/user/authUsercontroller.ts b/backend/src/auth/user/authUsercontroller.ts index 8febe05f74cabc2903975780f0a86f2200aa91f9..2988adbdc42cf0c0fdef7ca2bbc3dca7ef74cd3a 100644 --- a/backend/src/auth/user/authUsercontroller.ts +++ b/backend/src/auth/user/authUsercontroller.ts @@ -14,7 +14,6 @@ export class AuthUserController { constructor(private readonly authUserService: AuthUserService) {} @ApiBody({ type: CreateUserDto }) - @ApiBearerAuth() @ApiCreatedResponse({ type: UserSigninResDto, }) diff --git a/backend/src/auth/user/authUserservice.ts b/backend/src/auth/user/authUserservice.ts index b3b5db3b6624006fb37004b19a5c4fcab6a938d8..88f3b6f39203d0904910e7352548a8cc9e24c7bb 100644 --- a/backend/src/auth/user/authUserservice.ts +++ b/backend/src/auth/user/authUserservice.ts @@ -47,7 +47,6 @@ export class AuthUserService { { secret: JwtConstants.SECRET }, ); const userSigninResDto: UserSigninResDto = { - userId: user.userId, email: user.email, name: user.name, lastName: user.lastName, diff --git a/backend/src/auth/user/dto/user-signin-res.dto.ts b/backend/src/auth/user/dto/user-signin-res.dto.ts index 632d3ee9bd16877e1e55a9ed7b3c5abca2fc2ffc..90cf4a05d109c182ff5c9f811ef50908d3eba64e 100644 --- a/backend/src/auth/user/dto/user-signin-res.dto.ts +++ b/backend/src/auth/user/dto/user-signin-res.dto.ts @@ -2,8 +2,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { ALL_ROLES } from 'src/shared/enum/admin-role.enum'; export class UserSigninResDto { - @ApiProperty() - userId: number; @ApiProperty() email: string; @ApiProperty() diff --git a/backend/src/place/place.service.ts b/backend/src/place/place.service.ts index 784232d0da538d9037fa64df21241cf1e95bf8d0..6f258c3c9e281fab376587cf7811f10d0b2b1ba5 100644 --- a/backend/src/place/place.service.ts +++ b/backend/src/place/place.service.ts @@ -14,6 +14,7 @@ import { ServerConstants } from 'src/constants/server.contants'; import { Available } from 'src/pointOfInterest/enum/available.enum'; import { UpdatePlaceReqDto } from './dto/update-place.req.dto'; import { Category } from 'src/category/entities/category.entity'; +import { Visited } from 'src/visited/entities/visited.entity'; @Injectable() export class PlaceService { @@ -206,4 +207,17 @@ export class PlaceService { ); } } + + async findPlacesNotVisitedByUser(email: string, lang: LANGUAGES, idTown: number): Promise { + const places: GetPlaceDto[] = await this.findAllByTown(idTown, lang); + const visited: any[] = await this.dataSource + .getRepository(Visited) + .createQueryBuilder('visited') + .leftJoinAndSelect('visited.place', 'place') + .where('visited.user = :email', { email }) + .getMany(); + const visitedIds: number[] = visited.map((visit) => visit.place.idPlace); + // podemos hacerlo en la query + return places.filter((place) => !visitedIds.includes(place.idPlace)); + } } diff --git a/backend/src/route/route.controller.ts b/backend/src/route/route.controller.ts index b3162fc3317adff25fd6ae044e4ad6c14e1b6372..bdd2127512cd804acfee2809245a98a88b2b43a8 100644 --- a/backend/src/route/route.controller.ts +++ b/backend/src/route/route.controller.ts @@ -1,8 +1,6 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, Req, Query } from '@nestjs/common'; +import { Controller, Get, Param, UseGuards, Req, Query } from '@nestjs/common'; import { RouteService } from './route.service'; -import { CreateRouteDto } from './dto/create-route.dto'; -import { UpdateRouteDto } from './dto/update-route.dto'; -import { ApiBearerAuth, ApiConsumes, ApiParam, ApiQuery, ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiParam, ApiQuery, ApiTags } from '@nestjs/swagger'; import { LANGUAGES } from 'src/shared/enum/languages.enum'; import { AuthUserGuard } from 'src/auth/user/authUser.guard'; import { CustomUserRequest } from 'src/auth/user/interface/customUserReq'; @@ -12,28 +10,6 @@ import { CustomUserRequest } from 'src/auth/user/interface/customUserReq'; export class RouteController { constructor(private readonly routeService: RouteService) {} - // @Post() - // @ApiConsumes('multipart/form-data') - // // @UseGuards(AuthUserGuard) - // async create(@Body() createRouteDto: CreateRouteDto) { - // return await this.routeService.recommend(); - // } - - // @Get(':idRoute') - // async findOne(@Param('idRoute') idRoute: number) { - // return await this.routeService.findOne(idRoute); - // } - - // @Patch(':id') - // update(@Param('id') id: string, @Body() updateRouteDto: UpdateRouteDto) { - // return this.routeService.update(+id, updateRouteDto); - // } - - // @Delete(':id') - // remove(@Param('id') id: string) { - // return this.routeService.remove(+id); - // } - @Get('recommend:idTown') @ApiQuery({ name: 'lang', type: String }) @ApiParam({ name: 'idTown', type: Number }) diff --git a/backend/src/route/route.service.ts b/backend/src/route/route.service.ts index 5d359bfe4d63990abbcdd56c1776e4cff3381a87..e624089e3888f1ac7972d94eeb6dd4e1c338b70a 100644 --- a/backend/src/route/route.service.ts +++ b/backend/src/route/route.service.ts @@ -1,13 +1,10 @@ import { Injectable } from '@nestjs/common'; -import { CreateRouteDto } from './dto/create-route.dto'; -import { UpdateRouteDto } from './dto/update-route.dto'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { Route } from './entities/route.entity'; -import { DataSource, In, Repository } from 'typeorm'; +import { DataSource, Repository } from 'typeorm'; import { User } from 'src/user/entities/user.entity'; import { Town } from 'src/town/entities/town.entity'; import { TravelPlaceService } from 'src/travel-place/travel-place.service'; -import { TravelPlace } from 'src/travel-place/entities/travel-place.entity'; import { RecommendationsSystem } from './utils/recommendations'; import { PlaceService } from 'src/place/place.service'; import { LANGUAGES } from 'src/shared/enum/languages.enum'; @@ -27,46 +24,25 @@ export class RouteService { private readonly placeService: PlaceService, private readonly visitedService: VisitedService, ) {} - private async createRoute(idUser: number, idTown: number) { - const user: User = await this.userRepository.findOneBy({ userId: idUser }); + private async createRoute(email: string, idTown: number, idPlace: number, startDate: Date, endDate: Date) { + const user: User = await this.userRepository.findOneBy({ email }); const town: Town = await this.townRepository.findOneBy({ townId: idTown }); - await this.routeRepository.save({ user, town, startDate: new Date(), endDate: new Date() }); + // const idRoute = await this.routeRepository.save({ user, town, startDate, endDate }); + const idRoute = (await this.routeRepository.save({ user, town, startDate, endDate })).idRoute; await this.travelPlaceService.create({ - idRoute: 1, - idPlace: 1, + idRoute, + idPlace, startDate: new Date(), endDate: new Date(), - done: true, + done: false, }); } - findAll() { - return `This action returns all route`; - } - - async findOne(id: number) { - const res: any[] = await this.dataSource - .getRepository(Route) - .createQueryBuilder('route') - .leftJoinAndSelect('route.travelPlace', 'travelPlace') - .getMany(); - - return res; - } - - update(id: number, updateRouteDto: UpdateRouteDto) { - return `This action updates a #${id} route`; - } - - remove(id: number) { - return `This action removes a #${id} route`; - } - async recommend(idTown: number, email: string, language: LANGUAGES) { // Obtener los visitados y los candidatos - const places: GetPlaceDto[] = await this.placeService.findAllByTown(idTown, language); + const placesNotVisited: GetPlaceDto[] = await this.placeService.findPlacesNotVisitedByUser(email, language, idTown); const visited: Visited[] = await this.visitedService.getVisitedByUser(email); - const placesMapped: RecommendPlace[] = places.map((place) => { + const placesMapped: RecommendPlace[] = placesNotVisited.map((place) => { return { idPlace: place.idPlace, openAt: place.openAt, @@ -93,6 +69,8 @@ export class RouteService { placesChooen.push(await this.placeService.findOneAndTradAndAvailable(index, LANGUAGES.EN)); } - return placesChooen; + for (const place of placesChooen) { + await this.createRoute(email, idTown, place.idPlace, new Date(), new Date()); + } } } diff --git a/backend/src/travel-place/travel-place.controller.ts b/backend/src/travel-place/travel-place.controller.ts index 01d13a967e6bb23e1ac0eef78459a9d43c4445af..ddace02e4023e8381fa7de61f41633797f078874 100644 --- a/backend/src/travel-place/travel-place.controller.ts +++ b/backend/src/travel-place/travel-place.controller.ts @@ -1,7 +1,6 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { Controller, Post, Body } from '@nestjs/common'; import { TravelPlaceService } from './travel-place.service'; import { CreateTravelPlaceDto } from './dto/create-travel-place.dto'; -import { UpdateTravelPlaceDto } from './dto/update-travel-place.dto'; @Controller('travel-place') export class TravelPlaceController { @@ -11,24 +10,4 @@ export class TravelPlaceController { create(@Body() createTravelPlaceDto: CreateTravelPlaceDto) { return this.travelPlaceService.create(createTravelPlaceDto); } - - @Get() - findAll() { - return this.travelPlaceService.findAll(); - } - - @Get(':id') - findOne(@Param('id') id: string) { - return this.travelPlaceService.findOne(+id); - } - - @Patch(':id') - update(@Param('id') id: string, @Body() updateTravelPlaceDto: UpdateTravelPlaceDto) { - return this.travelPlaceService.update(+id, updateTravelPlaceDto); - } - - @Delete(':id') - remove(@Param('id') id: string) { - return this.travelPlaceService.remove(+id); - } } diff --git a/backend/src/travel-place/travel-place.service.ts b/backend/src/travel-place/travel-place.service.ts index 0e6867b95f1205377f9959801e543020cc1ffd19..99fbb5e59d1bc03d103d412dae97391c435100aa 100644 --- a/backend/src/travel-place/travel-place.service.ts +++ b/backend/src/travel-place/travel-place.service.ts @@ -1,9 +1,8 @@ import { Injectable } from '@nestjs/common'; import { CreateTravelPlaceDto } from './dto/create-travel-place.dto'; -import { UpdateTravelPlaceDto } from './dto/update-travel-place.dto'; import { InjectRepository } from '@nestjs/typeorm'; import { TravelPlace } from './entities/travel-place.entity'; -import { In, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { Place } from 'src/place/entities/place.entity'; import { Route } from 'src/route/entities/route.entity'; @@ -21,25 +20,25 @@ export class TravelPlaceService { await this.travelPlaceRepository.save({ route, place, - startDate: new Date(), - endDate: new Date(), - done: true, + startDate: createTravelPlaceDto.startDate, + endDate: createTravelPlaceDto.endDate, + done: createTravelPlaceDto.done, }); } - findAll() { - return `This action returns all travelPlace`; - } + // findAll() { + // return `This action returns all travelPlace`; + // } - findOne(id: number) { - return `This action returns a #${id} travelPlace`; - } + // findOne(id: number) { + // return `This action returns a #${id} travelPlace`; + // } - update(id: number, updateTravelPlaceDto: UpdateTravelPlaceDto) { - return `This action updates a #${id} travelPlace`; - } + // update(id: number, updateTravelPlaceDto: UpdateTravelPlaceDto) { + // return `This action updates a #${id} travelPlace`; + // } - remove(id: number) { - return `This action removes a #${id} travelPlace`; - } + // remove(id: number) { + // return `This action removes a #${id} travelPlace`; + // } } diff --git a/backend/src/user/entities/user.entity.ts b/backend/src/user/entities/user.entity.ts index 43698b21e11247364dca95fd78c66f8fc553af0f..6ee89b3731fd81b23decdef219ab20deeca0cd2a 100644 --- a/backend/src/user/entities/user.entity.ts +++ b/backend/src/user/entities/user.entity.ts @@ -1,14 +1,9 @@ import { Category } from 'src/category/entities/category.entity'; -import { Entity, Column, PrimaryGeneratedColumn, ManyToMany, JoinTable } from 'typeorm'; +import { Entity, Column, ManyToMany, JoinTable, PrimaryColumn } from 'typeorm'; @Entity() export class User { - @PrimaryGeneratedColumn() - userId: number; - - @Column({ - unique: true, - }) + @PrimaryColumn() email: string; @JoinTable() diff --git a/backend/src/visited/dto/create-visited.dto.ts b/backend/src/visited/dto/create-visited.dto.ts index 60f86a2fc4d28ae7e83c2ff68c1f3218d1c1253c..ce591becd5922f8417cb014f4a28a3a919502e21 100644 --- a/backend/src/visited/dto/create-visited.dto.ts +++ b/backend/src/visited/dto/create-visited.dto.ts @@ -3,10 +3,6 @@ import { ApiProperty } from '@nestjs/swagger'; export class CreateVisitedDto { @ApiProperty() idPlace: number; - @ApiProperty() - email: string; @ApiProperty({ type: 'number', description: 'Rating from 1 to 5' }) rating: number; - @ApiProperty() - date: Date; } diff --git a/backend/src/visited/entities/visited.entity.ts b/backend/src/visited/entities/visited.entity.ts index 65a92aff1e83330ddd0e9c6c9f4353e4fc64b86e..81de0fedb2cc903d4532f3139814ba3dc228676c 100644 --- a/backend/src/visited/entities/visited.entity.ts +++ b/backend/src/visited/entities/visited.entity.ts @@ -1,23 +1,22 @@ import { Place } from 'src/place/entities/place.entity'; import { User } from 'src/user/entities/user.entity'; -import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; @Entity() export class Visited { - @PrimaryGeneratedColumn() - idVisited: number; - + @PrimaryColumn() @ManyToOne(() => Place, (place) => place.idPlace, { eager: true }) @JoinColumn({ name: 'place' }) place: Place; - @ManyToOne(() => User, (user) => user.userId) + @PrimaryColumn() + @ManyToOne(() => User, (user) => user.email) @JoinColumn({ name: 'user' }) user: User; @Column({ nullable: false }) rating: number; - @Column({ nullable: false }) + @Column({ nullable: true, default: () => 'CURRENT_TIMESTAMP' }) date: Date; } diff --git a/backend/src/visited/visited.controller.ts b/backend/src/visited/visited.controller.ts index ea96456ffb89d334d9ef7b89a672e304e8500347..039d63dff9cdc676fdad6ecf6d9e2b5012030515 100644 --- a/backend/src/visited/visited.controller.ts +++ b/backend/src/visited/visited.controller.ts @@ -1,7 +1,9 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { Controller, Get, Post, Body, Param, Delete, UseGuards, Req } from '@nestjs/common'; import { VisitedService } from './visited.service'; import { CreateVisitedDto } from './dto/create-visited.dto'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { AuthUserGuard } from 'src/auth/user/authUser.guard'; +import { CustomUserRequest } from 'src/auth/user/interface/customUserReq'; // import { UpdateVisitedDto } from './dto/update-visited.dto'; @Controller('visited') @@ -9,10 +11,13 @@ import { ApiTags } from '@nestjs/swagger'; export class VisitedController { constructor(private readonly visitedService: VisitedService) {} + @ApiBearerAuth('jwt') + @UseGuards(AuthUserGuard) @Post() - async create(@Body() createVisitedDto: CreateVisitedDto) { + async create(@Body() createVisitedDto: CreateVisitedDto, @Req() req: CustomUserRequest) { try { - return await this.visitedService.create(createVisitedDto); + const { email } = req.user; + return await this.visitedService.create(createVisitedDto, email); } catch (e) { return e; } @@ -28,11 +33,6 @@ export class VisitedController { return this.visitedService.findOne(+id); } - // @Patch(':id') - // update(@Param('id') id: string, @Body() updateVisitedDto: UpdateVisitedDto) { - // return this.visitedService.update(+id, updateVisitedDto); - // } - @Delete(':id') remove(@Param('id') id: string) { return this.visitedService.remove(+id); diff --git a/backend/src/visited/visited.module.ts b/backend/src/visited/visited.module.ts index 022aaf567fe62aa23e1b014b9b34e96ceefa9ac9..9dacfd6663a4f18c50ce4bf762b652f48668bcc8 100644 --- a/backend/src/visited/visited.module.ts +++ b/backend/src/visited/visited.module.ts @@ -12,10 +12,21 @@ import { Category } from 'src/category/entities/category.entity'; import { AvailableDate } from 'src/place/entities/available-date.entity'; import { PlaceTraduction } from 'src/place/entities/place-traduction.entity'; import { Town } from 'src/town/entities/town.entity'; +import { AuthUserService } from 'src/auth/user/authUserservice'; +import { JwtService } from '@nestjs/jwt'; +import { EncryptionService } from 'src/auth/encryption/encryption.service'; @Module({ controllers: [VisitedController], - providers: [VisitedService, UserService, PlaceService, CategoryService], - imports: [TypeOrmModule.forFeature([User, Place, Visited, Category, AvailableDate, PlaceTraduction, Town])], + providers: [ + VisitedService, + UserService, + PlaceService, + CategoryService, + AuthUserService, + JwtService, + EncryptionService, + ], + imports: [TypeOrmModule.forFeature([User, Place, Visited, Category, AvailableDate, PlaceTraduction, Town, Visited])], }) export class VisitedModule {} diff --git a/backend/src/visited/visited.service.ts b/backend/src/visited/visited.service.ts index c4a4f6869fba7cd4e56ed46578687a7aeb5c6259..722905b5c3c3aa54891dd84bff983921a7ddb2ac 100644 --- a/backend/src/visited/visited.service.ts +++ b/backend/src/visited/visited.service.ts @@ -7,7 +7,6 @@ import { UserService } from 'src/user/user.service'; import { CreateVisitedDto } from './dto/create-visited.dto'; import { Place } from 'src/place/entities/place.entity'; import { PlaceService } from 'src/place/place.service'; -import { UpdateVisitedDto } from './dto/update-visited.dto'; @Injectable() export class VisitedService { @@ -17,11 +16,15 @@ export class VisitedService { private readonly placeService: PlaceService, ) {} - async create(createVisitedDto: CreateVisitedDto) { + async create(createVisitedDto: CreateVisitedDto, email: string) { const place: Place = await this.placeService.findOne(createVisitedDto.idPlace); - const user: User = await this.userService.findOne(createVisitedDto.email); + const user: User = await this.userService.findOne(email); if (!place || !user) throw new BadRequestException('Place or user not found'); - await this.visitedRepository.save({ place, user, rating: createVisitedDto.rating, date: createVisitedDto.date }); + + await this.visitedRepository.upsert( + { place, user, rating: createVisitedDto.rating }, + { conflictPaths: ['place', 'user'] }, + ); } async getVisitedByUser(email: string): Promise {