import { Body, Controller, Delete, Get, HttpException, HttpService, HttpStatus, Param, Post, Put, Query, UseGuards, } from '@nestjs/common'; import { ApiParam } from '@nestjs/swagger'; import { Types } from 'mongoose'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { CategoriesAccompagnementService } from '../categories/services/categories-accompagnement.service'; import { CategoriesFormationsService } from '../categories/services/categories-formations.service'; import { CategoriesOthersService } from '../categories/services/categories-others.service'; import { CreateTempUserDto } from '../temp-user/dto/create-temp-user.dto'; import { TempUserService } from '../temp-user/temp-user.service'; import { Roles } from '../users/decorators/roles.decorator'; import { IsStructureOwnerGuard } from '../users/guards/isStructureOwner.guard'; import { User } from '../users/schemas/user.schema'; import { UsersService } from '../users/users.service'; import { CreateStructureDto } from './dto/create-structure.dto'; import { QueryStructure } from './dto/query-structure.dto'; import { structureDto } from './dto/structure.dto'; import { Structure, StructureDocument } from './schemas/structure.schema'; import { StructuresService } from './services/structures.service'; import { RolesGuard } from '../users/guards/roles.guard'; @Controller('structures') export class StructuresController { constructor( private readonly httpService: HttpService, private readonly structureService: StructuresService, private readonly userService: UsersService, private readonly tempUserService: TempUserService, private readonly categoriesFormationsService: CategoriesFormationsService, private readonly categoriesOthersService: CategoriesOthersService, private readonly categoriesAccompagnementService: CategoriesAccompagnementService ) {} /** * Return points of given town exist. * @param zipcode * @returns Array of points */ @Get('coordinates/:zipcode') @ApiParam({ name: 'zipcode', type: String, required: true }) public async getCoordinates(@Param('zipcode') city: string): Promise<any> { return await this.httpService .get(encodeURI('https://download.data.grandlyon.com/geocoding/photon-bal/api?q=' + city)) .toPromise() .then(async (res) => res.data.features) .then((data) => data.filter((cityPoint) => cityPoint.properties.city.toLowerCase().includes(city.toLowerCase()))) .then((data) => data.map((filteredCityPoint) => filteredCityPoint.geometry.coordinates)); } @Post() public async create(@Body() createStructureDto: CreateStructureDto): Promise<Structure> { return this.structureService.create(createStructureDto.idUser, createStructureDto.structure); } @Post('search') public async search(@Query() query: QueryStructure, @Body() body): Promise<Structure[]> { return await this.structureService.searchForStructures(query.query, body ? body.filters : null); } @Post('resetSearchIndex') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') public async resetES(): Promise<StructureDocument[]> { return this.structureService.initiateStructureIndex(); } @Put('updateAfterOwnerVerify/:id') public async updateAfterOwnerVerify(@Param('id') id: string): Promise<Structure> { return this.structureService.updateAccountVerified(id); } @Put(':id') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) @Roles('admin') public async update(@Param('id') id: string, @Body() body: structureDto): Promise<Structure> { return this.structureService.update(id, body); } @Get() public async findAll(): Promise<Structure[]> { return this.structureService.findAll(); } @Get('formated') public async findAllFormated(): Promise<Structure[]> { const formationCategories = await this.categoriesFormationsService.findAll(); const accompagnementCategories = await this.categoriesAccompagnementService.findAll(); const otherCategories = await this.categoriesOthersService.findAll(); return this.structureService.findAllFormated(formationCategories, accompagnementCategories, otherCategories); } @Post(':id/isClaimed') public async isClaimed(@Param('id') id: string, @Body() user?: User): Promise<boolean> { return this.structureService.isClaimed(id, user); } @Post(':id/claim') public async claim(@Param('id') idStructure: string, @Body() user: User): Promise<Types.ObjectId[]> { return this.userService.updateStructureLinkedClaim(user.email, idStructure); } @Post('count') public async countCategories( @Body() selectedFilter: { id: string; text: string }[] ): Promise<Array<{ id: string; count: number }>> { const data = await Promise.all([ this.structureService.countByStructureKey('proceduresAccompaniment', selectedFilter), this.structureService.countByStructureKey('accessRight', selectedFilter), this.structureService.countByStructureKey('baseSkills', selectedFilter), this.structureService.countByStructureKey('parentingHelp', selectedFilter), this.structureService.countByStructureKey('digitalCultureSecurity', selectedFilter), this.structureService.countByStructureKey('socialAndProfessional', selectedFilter), this.structureService.countByStructureKey('publicsAccompaniment', selectedFilter), this.structureService.countByStructureKey('labelsQualifications', selectedFilter), this.structureService.countByStructureKey('publics', selectedFilter), this.structureService.countByStructureKey('accessModality', selectedFilter), this.structureService.countByStructureKey('equipmentsAndServices', selectedFilter), ]); // Return a concat of all arrays return data.reduce((a, b) => [...a, ...b]); } @Post('address') public async searchAddress(@Body() data: { searchQuery: string }) { return await this.structureService.searchAddress(data); } @Get(':id') public async find(@Param('id') id: string) { const result = await this.structureService.findOne(id); if (!result || result.deletedAt) { throw new HttpException('Structure does not exist', HttpStatus.NOT_FOUND); } else { return result; } } @Post(':id/withOwners') public async findWithOwners(@Param('id') id: string, @Body() data: { emailUser: string }) { return this.structureService.findWithOwners(id, data.emailUser); } @Delete(':id') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) @Roles('admin') @ApiParam({ name: 'id', type: String, required: true }) public async delete(@Param('id') id: string) { return this.structureService.deleteOne(id); } @Post(':id/addOwner') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) @Roles('admin') @ApiParam({ name: 'id', type: String, required: true }) public async addOwner(@Param('id') id: string, @Body() user: CreateTempUserDto): Promise<any> { // Get structure name const structure = await this.structureService.findOne(id); if (!structure) { throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND); } user.pendingStructuresLink = [Types.ObjectId(id)]; // If user already exist, use created account if (await this.userService.verifyUserExist(user.email)) { return this.userService.updateStructureLinked(user.email, id); } // If temp user exist, update it if (await this.tempUserService.findOne(user.email)) { return this.tempUserService.updateStructureLinked(user); } // If not, create return this.tempUserService.create(user, structure.structureName); } @Post(':id/join') @ApiParam({ name: 'id', type: String, required: true }) public async join(@Param('id') id: string, @Body() user: User): Promise<void> { // Get structure name const structure = await this.structureService.findOne(id); if (!structure) { throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND); } // Get user and add pending structure const userFromDb = await this.userService.findOne(user.email); if (!userFromDb) { throw new HttpException('Invalid User', HttpStatus.NOT_FOUND); } // If user has not already request it, send owner's validation email if (!userFromDb.pendingStructuresLink.includes(Types.ObjectId(id))) { userFromDb.pendingStructuresLink.push(Types.ObjectId(id)); userFromDb.save(); // Send structure owner's an email this.structureService.sendStructureJoinRequest(userFromDb, structure); } } @Post(':id/join/:userId/:status') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) @ApiParam({ name: 'id', type: String, required: true }) @ApiParam({ name: 'userId', type: String, required: true }) @ApiParam({ name: 'status', type: String, required: true }) public async joinValidation( @Param('id') id: string, @Param('status') status: string, @Param('userId') userId: string ): Promise<any> { // Get structure name const structure = await this.structureService.findOne(id); if (!structure) { throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND); } // Get user and add pending structure const userFromDb = await this.userService.findById(userId); if (!userFromDb) { throw new HttpException('Invalid User', HttpStatus.NOT_FOUND); } if (!userFromDb.pendingStructuresLink.includes(Types.ObjectId(id))) { throw new HttpException('User not linked to structure', HttpStatus.NOT_FOUND); } if (status === 'true') { // Accept await this.userService.updateStructureLinked(userFromDb.email, id); await this.userService.removeFromPendingStructureLinked(userFromDb.email, id); } else { // Refuse this.userService.removeFromPendingStructureLinked(userFromDb.email, id); } } @Delete(':id/owner/:userId') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) @Roles('admin') @ApiParam({ name: 'id', type: String, required: true }) @ApiParam({ name: 'userId', type: String, required: true }) public async removeOwner(@Param('id') id: string, @Param('userId') userId: string): Promise<void> { // Get structure const structure = await this.structureService.findOne(id); if (!structure) { throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND); } // Get user const userFromDb = await this.userService.findById(userId); if (!userFromDb || !userFromDb.structuresLink.includes(Types.ObjectId(id))) { throw new HttpException('Invalid User', HttpStatus.NOT_FOUND); } this.userService.removeFromStructureLinked(userFromDb.email, id); } @Post('reportStructureError') public async reportStructureError(@Body() data: { structureId: string; content: string }): Promise<void> { return await this.structureService.reportStructureError(data.structureId, data.content); } }