import { Body , Controller , forwardRef , Get , Headers , HttpCode , Inject , Logger , Param , Post , Put , Query , Res , UploadedFile , UseGuards , UseInterceptors , } from '@nestjs/common' ; import { Transactional } from 'typeorm-transactional-cls-hooked' ; import { UserService } from '../service/user.service' ; import { UserMapper } from '../mapper/user.mapper' ; import { ApiBearerAuth , ApiBody , ApiCreatedResponse , ApiGoneResponse , ApiNotFoundResponse , ApiOkResponse , ApiOperation , ApiParam , ApiTags , ApiUnauthorizedResponse , } from '@nestjs/swagger' ; import { RoleEnum } from '../../SecurityModule/enum/role.enum' ; import { SecurityService } from '../../SecurityModule/service/security.service' ; import { User } from '../entity/user.entity' ; import { CertificateUserDTO } from '../dto/certificate-user.dto' ; import { AdminChangePasswordDTO } from '../dto/admin-change-password.dto' ; import { ChangePasswordRequestIdDTO } from '../dto/change-password-request-id.dto' ; import { ForgotPasswordDTO } from '../dto/forgot-password' ; import { ChangePasswordForgotFlowDTO } from '../dto/change-password-forgot-flow.dto' ; import { UserDTO } from '../dto/user.dto' ; import { NewUserDTO } from '../dto/new-user.dto' ; import { UserUpdateDTO } from '../dto/user-update.dto' ; import { NewStudentDTO } from '../dto/new-student.dto' ; import { Constants } from '../../CommonsModule/constants' ; import { NeedPolicies , NeedRoles } from '../../CommonsModule/decorator/role-guard-metadata.decorator' ; import { RoleGuard } from '../../CommonsModule/guard/role.guard' ; import { BadgeWithQuantityDTO } from '../../GameficationModule/dto/badge-with-quantity.dto' ; import { NewUserSwagger } from '../swagger/new-user.swagger' ; import { FileInterceptor } from '@nestjs/platform-express' ; import { UserIdParam } from '../../CommonsModule/guard/student-metadata.guard' ; import { StudentGuard } from '../../CommonsModule/guard/student.guard' ; import { PhotoDTO } from '../dto/photo.dto' ; import { AppConfigService as ConfigService } from '../../ConfigModule/service/app-config.service' ; import { Response } from 'express' ; import { UserJWTDTO } from '../../CommonsModule/dto/user-jwt.dto' ; @ ApiTags ( 'User' ) @ ApiBearerAuth ( ) @ Controller ( `${ Constants . API_PREFIX }/${ Constants . API_VERSION_1 }/${ Constants . USER_ENDPOINT }` ) export class UserController { private readonly logger = new Logger ( UserController . name ) ; constructor ( private readonly service , private readonly mapper , @ Inject ( forwardRef ( ( ) => SecurityService ) ) private readonly securityService ) { } @ Get ( ) @ HttpCode ( 200 ) @ ApiOperation ( { summary : 'Get Users' , description : 'Get all users' } ) @ ApiOkResponse ( { type : NewUserDTO , isArray : true , description : 'All users' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN ) @ NeedPolicies ( `${ Constants . POLICIES_PREFIX }/GET_ALL_USERS` ) public async getAll ( ) { return this . mapper . toDtoList ( await this . service . getAll ( ) ) ; } @ Get ( '/me' ) @ HttpCode ( 200 ) @ ApiOkResponse ( { type : UserDTO } ) @ ApiOperation ( { summary : 'Find user by jwt id' , description : 'Decodes de jwt and finds the user by the jwt id' , } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN or STUDENT role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) public async findUserByJwtId ( @ Headers ( 'authorization' ) authorization ) { const { id } = await this . securityService . getUserFromToken ( authorization ) ; this . logger . log ( `user id: ${ id }` ) ; return this . mapper . toDtoAsync ( await this . service . findById ( id ) ) ; } @ Get ( '/:id/badge' ) @ HttpCode ( 200 ) @ ApiOkResponse ( { type : UserDTO } ) @ ApiOperation ( { summary : 'Find user badges by user id' , description : 'Decodes de jwt and finds the user badges by the user id' , } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async findBadgesWithQuantityByUserId ( @ Param ( 'id' ) id ) { this . logger . log ( `user id: ${ id }` ) ; return await this . service . findBadgesWithQuantityByUserId ( id ) ; } @ Get ( ':id/photo' ) @ HttpCode ( 200 ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) @ UseGuards ( StudentGuard ) @ UserIdParam ( 'id' ) public async getUserPhoto ( @ Param ( 'id' ) id ) { return { photo : await this . service . getUserPhoto ( id ) } ; } @ Post ( ':id/photo' ) @ UseInterceptors ( FileInterceptor ( 'file' ) ) @ HttpCode ( 200 ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async uploadUserPhoto ( @ UploadedFile ( 'file' ) file , @ Param ( 'id' ) id ) { return this . service . uploadUserPhoto ( file , id ) ; } @ Get ( ':id' ) @ HttpCode ( 200 ) @ ApiOkResponse ( { type : NewUserDTO } ) @ ApiParam ( { name : 'id' , type : Number , required : true , description : 'User id' , } ) @ ApiOperation ( { summary : 'Find user by id' , description : 'Find user by id' } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) @ NeedPolicies ( '@AUTHORIZATION-RESOURCE-SERVER/GET-USER' ) public async findById ( @ Param ( 'id' ) id ) { this . logger . log ( `user id: ${ id }` ) ; return this . mapper . toDtoAsync ( await this . service . findById ( id ) ) ; } @ Post ( ) @ HttpCode ( 201 ) @ Transactional ( ) @ ApiCreatedResponse ( { type : NewUserSwagger , description : 'User created' } ) @ ApiOperation ( { summary : 'Add user' , description : 'Creates a new user' } ) @ ApiBody ( { type : NewUserDTO } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN ) public async add ( @ Body ( ) user ) { this . logger . log ( `user: ${ user }` ) ; return this . mapper . toDto ( await this . service . add ( user ) ) ; } @ Post ( '/student' ) @ HttpCode ( 201 ) @ Transactional ( ) @ ApiCreatedResponse ( { type : NewUserDTO , description : 'User student created' } ) @ ApiOperation ( { summary : 'Add student user' , description : 'Creates a new student' , } ) @ ApiBody ( { type : NewStudentDTO } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have EXTERNAL role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . EXTERNAL ) public async addStudent ( @ Body ( ) user , @ Query ( 'inviteKey' ) inviteKey ? ) { this . logger . log ( `user: ${ user }` ) ; return this . mapper . toDto ( await this . service . addStudent ( { ... user , role : RoleEnum . STUDENT } , inviteKey ) ) ; } @ Put ( ':id' ) @ HttpCode ( 200 ) @ ApiParam ( { name : 'id' , type : Number , required : true , description : 'User id' , } ) @ ApiOperation ( { summary : 'Update user' , description : 'Update user by id' } ) @ ApiOkResponse ( { type : UserDTO } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async update ( @ Param ( 'id' ) id , @ Body ( ) userUpdatedInfo ) { this . logger . log ( `user id: ${ id }, new user information: ${ userUpdatedInfo }` ) ; return this . mapper . toDto ( await this . service . update ( id , userUpdatedInfo ) ) ; } @ Put ( ':id/change-password' ) @ HttpCode ( 200 ) @ ApiOkResponse ( { type : UserDTO } ) @ ApiOperation ( { summary : 'change-password' , description : 'Changes password from an authenticated user' , } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : `throw if there is not an authorization token, if authorization token does not have STUDENT role or if the id param is different from the user id` , } ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async changeUserPassword ( @ Param ( 'id' ) id , @ Body ( ) changePassword ) { this . logger . log ( `user id: ${ id }` ) ; return this . mapper . toDto ( await this . service . adminChangePassword ( id , changePassword ) ) ; } @ Post ( '/forgot-password' ) @ HttpCode ( 200 ) @ Transactional ( ) @ ApiOkResponse ( { type : ChangePasswordRequestIdDTO } ) @ ApiOperation ( { summary : 'Create change password request' , description : 'Create change password request' , } ) @ ApiNotFoundResponse ( { description : 'thrown if user is not found' } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have EXTERNAL role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . EXTERNAL ) public async forgotPassword ( @ Body ( ) forgotPasswordDTO ) { this . logger . log ( `forgot password: ${ forgotPasswordDTO }` ) ; const forgotPasswordRequestId = await this . service . forgotPassword ( forgotPasswordDTO ) ; const changePasswordRequestIdDTO = new ChangePasswordRequestIdDTO ( ) ; changePasswordRequestIdDTO . id = forgotPasswordRequestId ; return changePasswordRequestIdDTO ; } @ Get ( '/forgot-password/:changePasswordRequestId/validate' ) @ HttpCode ( 200 ) @ ApiOperation ( { summary : 'Validate change password request' , description : 'validate change password expiration time. If time is not expired, 200 is returned' , } ) @ ApiGoneResponse ( { description : 'thrown if change password request time is up' , } ) @ ApiNotFoundResponse ( { description : 'thrown if change password request is not found' , } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have EXTERNAL role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . EXTERNAL ) public async validateChangePasswordExpirationTime ( @ Param ( 'changePasswordRequestId' ) changePasswordRequestId ) { this . logger . log ( `change password request id: ${ changePasswordRequestId }` ) ; await this . service . validateChangePassword ( changePasswordRequestId ) ; } @ Post ( '/forgot-password/:changePasswordRequestId' ) @ HttpCode ( 200 ) @ ApiOperation ( { summary : 'change password on forgot password flow' , } ) @ ApiNotFoundResponse ( { description : 'thrown if change password request is not found' , } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have EXTERNAL role' , } ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . EXTERNAL ) public async changePassword ( @ Param ( 'changePasswordRequestId' ) changePasswordRequestId , @ Body ( ) changePasswordDTO ) { this . logger . log ( `change password request id: ${ changePasswordRequestId }, change password information: ${ changePasswordDTO }` ) ; await this . service . changePasswordForgotPasswordFlow ( changePasswordRequestId , changePasswordDTO ) ; } @ Get ( ':id/certificate' ) @ HttpCode ( 200 ) @ ApiOperation ( { summary : 'Get Certificates' , description : 'Get All Certificates' , } ) @ ApiOkResponse ( { type : CertificateUserDTO , isArray : true , description : 'All Certificates' , } ) @ ApiUnauthorizedResponse ( { description : 'thrown if there is not an authorization token or if authorization token does not have ADMIN role' , } ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . ADMIN , RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async findCertificatesByUser ( @ Param ( 'id' ) id ) { return await this . service . getCertificateByUser ( id ) ; } @ Get ( ':id/semear' ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async userAcceptedSemear ( @ Param ( 'id' ) id ) { return { accepted : await this . service . userAcceptedSemear ( id ) } ; } @ Post ( ':id/semear' ) @ UseGuards ( RoleGuard , StudentGuard ) @ NeedRoles ( RoleEnum . STUDENT ) @ UserIdParam ( 'id' ) public async acceptSemear ( @ Param ( 'id' ) id ) { return await this . service . acceptSemear ( id ) ; } @ Get ( 'semear/students' ) @ UseGuards ( RoleGuard ) @ NeedRoles ( RoleEnum . EXTERNAL ) public async createSemearStudentsFile ( @ Res ( ) res ) { return this . service . getStudentsAcceptedSemearTerms ( ) ; } }