Files
edr-platform/apps/edr-passenger-api/src/modules/auth/auth.controller.ts
2026-07-14 10:46:27 +03:00

232 lines
6.3 KiB
TypeScript

import {
Body,
Controller,
Post,
HttpCode,
HttpStatus,
UseGuards,
Get,
Patch,
Delete,
Param,
Request,
Query,
UnauthorizedException,
} from "@nestjs/common";
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBody,
ApiBearerAuth,
} from "@nestjs/swagger";
import { IsPublic } from "@tria-plc/api-common/modules/auth/decorators/public.decorator";
import { PassengerAuthService } from "./passenger-auth.service";
import {
RegisterDto,
LoginDto,
ResendRegistrationCodeDto,
FaydaRequestPasswordSetupDto,
FaydaVerifyAndLoginDto,
} from "./auth.dto";
import { JwtGuard } from "../../common/jwt.guard";
@ApiTags("Passenger Auth")
@Controller("auth")
// @Throttle({ auth: { limit: 5, ttl: 60_000 } })
export class AuthController {
constructor(private passengerAuthService: PassengerAuthService) {}
@Post("register")
@IsPublic()
@ApiOperation({
summary: "Register new passenger account (sends SMS verification code)",
})
@ApiResponse({
status: 201,
description:
"Account created as pending. A verification code is sent via SMS — complete signup via PATCH /v1/auth/set-password.",
})
@ApiResponse({
status: 409,
description: "Email or phone already registered",
})
@ApiBody({ type: RegisterDto })
register(@Request() req: any, @Body() dto: RegisterDto) {
return this.passengerAuthService.register(dto, req);
}
@Post("register/resend-code")
@IsPublic()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Resend the registration verification code for a pending account",
})
@ApiResponse({
status: 200,
description: "Verification code re-sent if the account is pending.",
})
@ApiBody({ type: ResendRegistrationCodeDto })
resendRegistrationCode(
@Request() req: any,
@Body() dto: ResendRegistrationCodeDto,
) {
return this.passengerAuthService.resendRegistrationCode(dto, req);
}
@Post("login")
@IsPublic()
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: "Login with email and password" })
@ApiResponse({
status: 200,
description: "Login successful. Returns token + passengerId.",
})
@ApiResponse({ status: 401, description: "Invalid credentials" })
@ApiBody({ type: LoginDto })
login(@Request() req: any, @Body() dto: LoginDto) {
return this.passengerAuthService.login(dto, req);
}
@Post("logout")
@HttpCode(HttpStatus.OK)
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Logout current user" })
@ApiResponse({ status: 200, description: "Logout successful" })
@ApiResponse({ status: 401, description: "Unauthorized" })
logout(@Request() req: any) {
if (!req.user?.id)
throw new UnauthorizedException("User not authenticated");
return this.passengerAuthService.logout(req.user, req);
}
@Get("me")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({
summary:
"[DEV] Inspect raw JWT payload — shows full req.user from JwtGuard",
})
@ApiResponse({
status: 200,
description: "Returns the full req.user object set by JwtGuard",
})
@ApiResponse({ status: 401, description: "Unauthorized" })
getMe(@Request() req: any) {
return { user: req.user };
}
@Get("profile")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Get current user profile" })
@ApiResponse({
status: 200,
description: "User profile retrieved successfully",
})
@ApiResponse({ status: 401, description: "Unauthorized" })
getProfile(@Request() req: any) {
const userId = req.user?.id;
if (!userId) throw new UnauthorizedException("User not authenticated");
return this.passengerAuthService.getProfile(userId);
}
// TODO: admin user management endpoints — implement when admin module is ready
@Get("users")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "List all users (admin)" })
listUsers(
@Query("search") search?: string,
@Query("role") role?: string,
@Query("status") status?: string,
@Query("page") page?: string,
@Query("pageSize") pageSize?: string,
) {
return this.passengerAuthService.listUsers({
search,
role,
status,
page: page ? +page : 1,
pageSize: pageSize ? +pageSize : 20,
});
}
@Post("users")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Create user (admin)" })
createUser(@Body() body: any) {
return this.passengerAuthService.createUser(body);
}
@Patch("users/:id")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Update user (admin)" })
updateUser(@Param("id") id: string, @Body() body: any) {
return this.passengerAuthService.updateUser(id, body);
}
@Delete("users/:id")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Delete user (admin)" })
deleteUser(@Param("id") id: string) {
return this.passengerAuthService.deleteUser(id);
}
@Post("users/:id/reset-password")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({ summary: "Reset user password (admin)" })
resetPassword(
@Param("id") id: string,
@Body() body: { tempPassword: string },
) {
return this.passengerAuthService.resetUserPassword(id, body.tempPassword);
}
@Post("fayda/request-password-setup")
@IsPublic()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Send OTP to phone for Fayda-verified account password setup",
})
@ApiResponse({
status: 200,
description: "OTP sent to registered phone number",
})
@ApiBody({ type: FaydaRequestPasswordSetupDto })
requestFaydaPasswordSetup(
@Body() dto: FaydaRequestPasswordSetupDto,
@Request() req: any,
) {
return this.passengerAuthService.requestFaydaPasswordSetup(
dto.phoneNumber,
req,
);
}
@Post("fayda/verify-and-login")
@IsPublic()
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: "Verify OTP and receive session token for Fayda-verified account",
})
@ApiResponse({
status: 200,
description:
"Returns token + requiresPassword flag. Use token with POST /v1/auth/set-fayda-password.",
})
@ApiBody({ type: FaydaVerifyAndLoginDto })
verifyFaydaAndLogin(@Body() dto: FaydaVerifyAndLoginDto) {
return this.passengerAuthService.verifyFaydaAndLogin(
dto.phoneNumber,
dto.otp,
);
}
}