230 lines
5.7 KiB
TypeScript
230 lines
5.7 KiB
TypeScript
![]() |
import {
|
||
|
Controller,
|
||
|
Get,
|
||
|
Put,
|
||
|
Delete,
|
||
|
Body,
|
||
|
Param,
|
||
|
UseGuards,
|
||
|
Req,
|
||
|
HttpStatus,
|
||
|
Logger,
|
||
|
} from '@nestjs/common';
|
||
|
import {
|
||
|
ApiTags,
|
||
|
ApiOperation,
|
||
|
ApiResponse,
|
||
|
ApiBearerAuth,
|
||
|
ApiParam,
|
||
|
} from '@nestjs/swagger';
|
||
|
|
||
|
import { UsersService } from './users.service';
|
||
|
import { JwtAuthGuard } from '../auth/auth.guard';
|
||
|
import {
|
||
|
UpdateUserDto,
|
||
|
UserResponseDto,
|
||
|
UserStatsDto
|
||
|
} from './users.entity';
|
||
|
|
||
|
export interface AuthenticatedRequest {
|
||
|
user: {
|
||
|
id: string;
|
||
|
email: string;
|
||
|
plan: string;
|
||
|
quotaRemaining: number;
|
||
|
isActive: boolean;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
@ApiTags('Users')
|
||
|
@Controller('users')
|
||
|
@UseGuards(JwtAuthGuard)
|
||
|
@ApiBearerAuth()
|
||
|
export class UsersController {
|
||
|
private readonly logger = new Logger(UsersController.name);
|
||
|
|
||
|
constructor(private readonly usersService: UsersService) {}
|
||
|
|
||
|
@Get('me')
|
||
|
@ApiOperation({
|
||
|
summary: 'Get current user profile',
|
||
|
description: 'Returns the authenticated user\'s profile information'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User profile retrieved successfully',
|
||
|
type: UserResponseDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async getProfile(@Req() req: AuthenticatedRequest): Promise<UserResponseDto> {
|
||
|
return await this.usersService.getProfile(req.user.id);
|
||
|
}
|
||
|
|
||
|
@Put('me')
|
||
|
@ApiOperation({
|
||
|
summary: 'Update current user profile',
|
||
|
description: 'Updates the authenticated user\'s profile information'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User profile updated successfully',
|
||
|
type: UserResponseDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 400,
|
||
|
description: 'Invalid update data'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async updateProfile(
|
||
|
@Req() req: AuthenticatedRequest,
|
||
|
@Body() updateData: UpdateUserDto,
|
||
|
): Promise<UserResponseDto> {
|
||
|
this.logger.log(`User ${req.user.email} updating profile`);
|
||
|
return await this.usersService.updateProfile(req.user.id, updateData);
|
||
|
}
|
||
|
|
||
|
@Get('me/stats')
|
||
|
@ApiOperation({
|
||
|
summary: 'Get current user statistics',
|
||
|
description: 'Returns usage statistics for the authenticated user'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User statistics retrieved successfully',
|
||
|
type: UserStatsDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async getUserStats(@Req() req: AuthenticatedRequest): Promise<UserStatsDto> {
|
||
|
return await this.usersService.getUserStats(req.user.id);
|
||
|
}
|
||
|
|
||
|
@Delete('me')
|
||
|
@ApiOperation({
|
||
|
summary: 'Deactivate current user account',
|
||
|
description: 'Deactivates the authenticated user\'s account (soft delete)'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User account deactivated successfully',
|
||
|
type: UserResponseDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async deactivateAccount(@Req() req: AuthenticatedRequest): Promise<UserResponseDto> {
|
||
|
this.logger.log(`User ${req.user.email} deactivating account`);
|
||
|
return await this.usersService.deactivateAccount(req.user.id);
|
||
|
}
|
||
|
|
||
|
@Put('me/reactivate')
|
||
|
@ApiOperation({
|
||
|
summary: 'Reactivate current user account',
|
||
|
description: 'Reactivates the authenticated user\'s account'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User account reactivated successfully',
|
||
|
type: UserResponseDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async reactivateAccount(@Req() req: AuthenticatedRequest): Promise<UserResponseDto> {
|
||
|
this.logger.log(`User ${req.user.email} reactivating account`);
|
||
|
return await this.usersService.reactivateAccount(req.user.id);
|
||
|
}
|
||
|
|
||
|
@Get(':id')
|
||
|
@ApiOperation({
|
||
|
summary: 'Get user by ID',
|
||
|
description: 'Returns user information by ID (admin/internal use)'
|
||
|
})
|
||
|
@ApiParam({
|
||
|
name: 'id',
|
||
|
description: 'User unique identifier',
|
||
|
example: '550e8400-e29b-41d4-a716-446655440000'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'User retrieved successfully',
|
||
|
type: UserResponseDto
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 404,
|
||
|
description: 'User not found'
|
||
|
})
|
||
|
async findOne(@Param('id') id: string): Promise<UserResponseDto> {
|
||
|
return await this.usersService.findOne(id);
|
||
|
}
|
||
|
|
||
|
@Get('me/quota/check')
|
||
|
@ApiOperation({
|
||
|
summary: 'Check user quota availability',
|
||
|
description: 'Checks if the user has sufficient quota for operations'
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 200,
|
||
|
description: 'Quota check completed',
|
||
|
schema: {
|
||
|
type: 'object',
|
||
|
properties: {
|
||
|
hasQuota: { type: 'boolean', example: true },
|
||
|
quotaRemaining: { type: 'number', example: 45 },
|
||
|
quotaUsed: { type: 'number', example: 5 },
|
||
|
totalQuota: { type: 'number', example: 50 },
|
||
|
plan: { type: 'string', example: 'BASIC' },
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
@ApiResponse({
|
||
|
status: 401,
|
||
|
description: 'Unauthorized'
|
||
|
})
|
||
|
async checkQuota(@Req() req: AuthenticatedRequest) {
|
||
|
const hasQuota = await this.usersService.hasQuota(req.user.id);
|
||
|
const stats = await this.usersService.getUserStats(req.user.id);
|
||
|
|
||
|
return {
|
||
|
hasQuota,
|
||
|
quotaRemaining: req.user.quotaRemaining,
|
||
|
quotaUsed: stats.quotaUsed,
|
||
|
totalQuota: stats.totalQuota,
|
||
|
plan: req.user.plan,
|
||
|
};
|
||
|
}
|
||
|
}
|