import { Request } from "express"; import rateLimit from "express-rate-limit"; import { inject } from "inversify"; import { controller, httpGet, httpPatch, httpPost, queryParam, request, requestBody } from "inversify-express-utils"; import { HydratedDocument } from "mongoose"; import { ChangeEmailDTO, UpdateUserDTO, VerifyEmailDTO } from "./DTO/userUpdate.dto"; import { IUser } from "./models/Abstraction/IUser"; import { UserService } from "./user.service"; import { HttpStatus } from "../../common"; import { BaseController } from "../../common/base/controller"; import { ApiAuth, ApiBody, ApiFile, ApiModel, ApiOperation, ApiQuery, ApiResponse, ApiTags } from "../../common/decorator/swggerDocs"; import { AuthMessage } from "../../common/enums/message.enum"; import { OrderStatusQuery } from "../../common/types/query.type"; import { appConfig } from "../../core/config/app.config"; import { Guard } from "../../core/middlewares/guard.middleware"; import { ValidationMiddleware } from "../../core/middlewares/validator.middleware"; import { IOCTYPES } from "../../IOC/ioc.types"; import { UploadService } from "../../utils/upload.service"; import { AddressService } from "../address/address.service"; import { AuthService } from "../auth/auth.service"; import { AuthDTO } from "../auth/DTO/Auth.dto"; import { AuthCheckOtpDTO } from "../auth/DTO/AuthCheckOtp.dto"; import { TokenDto } from "../auth/DTO/Token.dto"; import { OrderService } from "../order/order.service"; @controller("/user") @ApiTags("User") class UserController extends BaseController { @inject(IOCTYPES.UserService) userService: UserService; @inject(IOCTYPES.AuthService) authService: AuthService; @inject(IOCTYPES.OrderService) orderService: OrderService; @inject(IOCTYPES.AddressService) addressService: AddressService; /** * * @param authDto * @returns */ @ApiOperation("Authenticate to send OTP code") @ApiResponse("Successful", 200, { message: AuthMessage.OtpSentToNo, phone: "09122569856" }) @ApiResponse("BadRequest", 400, { details: ["فرمت موبایل اشتباه است"] }) @ApiModel(AuthDTO) @ApiBody("Authenticate with phone or email") @httpPost("/authenticate", rateLimit(appConfig.rate), ValidationMiddleware.validateInput(AuthDTO)) async authUser(@requestBody() authDto: AuthDTO) { const data = await this.authService.authenticate(authDto, "user"); return this.response({ data }, HttpStatus.Ok); } /** * * @param loginOtpDto */ @ApiOperation("login user -> check sent OTP and generate the token") @ApiResponse("Successful login", 200, { message: AuthMessage.SuccessLogin, Accesstoken: "tokenValue", refreshToken: "tokenValue" }) @ApiModel(AuthCheckOtpDTO) @ApiBody("login user with otp code") @httpPost("/login/otp", rateLimit(appConfig.rate), ValidationMiddleware.validateInput(AuthCheckOtpDTO)) async loginOtp(@requestBody() loginOtpDto: AuthCheckOtpDTO) { const data = await this.authService.loginOtpS(loginOtpDto, "user"); return this.response({ data }, HttpStatus.Created); } /** * * @param refreshToken * @returns */ @ApiOperation("check the refresh token and generate access token base on that") @ApiResponse("Successful", 200, { accessToken: "tokenValue", refreshToken: "tokenValue" }) @ApiResponse("unauthorized", 401, { message: AuthMessage.TokenExpired }) @ApiResponse("notFound", 404, { message: AuthMessage.TokenNotFound }) @ApiModel(TokenDto) @httpPost("/token", rateLimit(appConfig.rate), ValidationMiddleware.validateInput(TokenDto)) public async refreshTokens(@requestBody() refreshToken: TokenDto) { const data = await this.authService.refreshTokensS(refreshToken); //return new tokens return this.response({ data }, HttpStatus.Created); } /** * * @param req * @returns */ @ApiOperation("logout the user based on the sent authorization token") @ApiResponse("Successful", 200, { message: AuthMessage.LoggedOut }) @ApiAuth() @httpPost("/logout", rateLimit(appConfig.rate), Guard.authUser()) public async logout(@request() req: Request) { //this is maybe user or seller based on token const user = req.user as IUser; const data = await this.authService.logoutS(user._id.toString()); //return logout message return this.response({ data }); } @ApiOperation("get current logged in user info ") @ApiResponse("successful", 200) @ApiAuth() @httpGet("/profile", Guard.authUser()) public async userProfile(@request() req: Request) { const user = req.user as HydratedDocument; const data = await this.userService.getProfile(user); return this.response(data); } @ApiOperation("update fields of the user with its current session") @ApiResponse("successful", HttpStatus.Created) @ApiModel(UpdateUserDTO) @ApiAuth() @httpPatch("/profile", Guard.authUser(), ValidationMiddleware.validateInput(UpdateUserDTO)) async updateUserProfile(@requestBody() updateUserDto: UpdateUserDTO, @request() req: Request) { const user = req.user as IUser; const data = await this.userService.updateUserProfileS(updateUserDto, user._id.toString()); return this.response({ data }, HttpStatus.Created); } @ApiOperation("change email of current session user") @ApiResponse("successful", HttpStatus.Ok) @ApiModel(ChangeEmailDTO) @ApiAuth() @httpPost("/profile/email/change", rateLimit(appConfig.rate), Guard.authUser(), ValidationMiddleware.validateInput(ChangeEmailDTO)) public async changeEmail(@requestBody() changeEmailDto: ChangeEmailDTO, @request() req: Request) { const user = req.user as IUser; const data = await this.authService.changeUserEmail(changeEmailDto, user._id.toString()); return this.response(data); } @ApiOperation("verify email of current session user") @ApiResponse("successful", HttpStatus.Ok) @ApiModel(VerifyEmailDTO) @ApiAuth() @httpPost("/profile/email/verify", rateLimit(appConfig.rate), Guard.authUser(), ValidationMiddleware.validateInput(VerifyEmailDTO)) public async verifyUserEmail(@requestBody() verifyEmailDto: VerifyEmailDTO, @request() req: Request) { const user = req.user as IUser; const data = await this.authService.verifyUserEmail(verifyEmailDto, user._id.toString()); return this.response(data); } @ApiOperation("get current logged in user address ") @ApiResponse("successful", HttpStatus.Ok) @ApiAuth() @httpGet("/profile/address", Guard.authUser()) public async getUserAddress(@request() req: Request) { const user = req.user as IUser; const data = await this.addressService.getUserAddress(user.address.toString()); return this.response({ address: data }); } @ApiOperation("get current logged in user comments ") @ApiResponse("successful", HttpStatus.Ok) @ApiAuth() @httpGet("/profile/comments", Guard.authUser()) public async getUserComments(@request() req: Request) { const user = req.user as IUser; const data = await this.userService.getUserComments(user._id.toString()); return this.response(data); } @ApiOperation("get current logged in user questions ") @ApiResponse("successful", HttpStatus.Ok) @ApiAuth() @httpGet("/profile/questions", Guard.authUser()) public async getUserQuestions(@request() req: Request) { const user = req.user as IUser; const data = await this.userService.getUserQuestions(user._id.toString()); return this.response(data); } @ApiOperation("get current logged in user product wishlist ") @ApiResponse("successful", HttpStatus.Ok) @ApiAuth() @httpGet("/profile/wishlist", Guard.authUser()) public async getUserWishList(@request() req: Request) { const user = req.user as IUser; const data = await this.userService.getUserWishList(user._id.toString()); return this.response(data); } //########################################### //order @ApiOperation("get current logged in user order ") @ApiResponse("successful", HttpStatus.Ok) @ApiQuery("status", "the status of order ==> can be = Delivered | Cancelled | Processing | Returned | Shipped") @ApiAuth() @httpGet("/profile/orders", Guard.authUser()) public async getUserOrders(@request() req: Request, @queryParam("status") status: string) { const statusQuery = status as OrderStatusQuery; const user = req.user as IUser; const data = await this.orderService.getUserOrders(user._id.toString(), statusQuery); return this.response(data); } //uploader @ApiOperation("Upload a user info image") @ApiResponse("File uploaded successfully", HttpStatus.Accepted) @ApiFile("image") @ApiAuth() @httpPost("/image/upload", Guard.authUser(), UploadService.single("image", "user-profile")) public async uploadImage(@request() req: Request) { // eslint-disable-next-line no-undef const file = req.file as Express.MulterS3.File; const data = { message: "file uploaded!", url: { size: file?.size, url: file?.location, type: file?.mimetype, }, }; return this.response({ data }, HttpStatus.Accepted); } } export { UserController };