All files / modules/users users.controller.ts

84.61% Statements 22/26
100% Branches 2/2
50% Functions 4/8
83.33% Lines 20/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 1081x                         1x 1x 1x 1x 1x   1x           1x   6x 6x         1x         2x         1x       2x         1x         2x                 1x                   1x                     1x                         1x              
import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Param,
  Body,
  UseGuards,
  Query,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { InvitationService } from './services/invitation.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { RequestUser } from '../auth/strategies/jwt.strategy';
import { InviteUserDto, InvitationResponseDto } from './dto/invite-user.dto';
 
@ApiTags('users')
@Controller('users')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class UsersController {
  constructor(
    private readonly usersService: UsersService,
    private readonly invitationService: InvitationService,
  ) {}
 
  @Get()
  @ApiOperation({ summary: 'List users in tenant' })
  async findAll(
    @CurrentUser() user: RequestUser,
    @Query('page') page = 1,
    @Query('limit') limit = 10,
  ) {
    return this.usersService.findAllByTenant(user.tenant_id, page, limit);
  }
 
  @Get(':id')
  @ApiOperation({ summary: 'Get user by ID' })
  async findOne(
    @Param('id') id: string,
    @CurrentUser() user: RequestUser,
  ) {
    return this.usersService.findOne(id, user.tenant_id);
  }
 
  @Patch(':id')
  @ApiOperation({ summary: 'Update user' })
  async update(
    @Param('id') id: string,
    @Body() updateDto: any,
    @CurrentUser() user: RequestUser,
  ) {
    return this.usersService.update(id, updateDto, user.tenant_id);
  }
 
  // ==================== Invitation Endpoints ====================
 
  @Post('invite')
  @ApiOperation({ summary: 'Send invitation to join tenant' })
  @ApiResponse({ status: 201, description: 'Invitation sent successfully', type: InvitationResponseDto })
  @ApiResponse({ status: 409, description: 'Email already registered or invitation pending' })
  async invite(
    @Body() inviteDto: InviteUserDto,
    @CurrentUser() user: RequestUser,
  ): Promise<InvitationResponseDto> {
    return this.invitationService.invite(inviteDto, user.id, user.tenant_id);
  }
 
  @Get('invitations')
  @ApiOperation({ summary: 'List pending invitations for tenant' })
  @ApiResponse({ status: 200, description: 'List of invitations', type: [InvitationResponseDto] })
  async listInvitations(
    @CurrentUser() user: RequestUser,
  ): Promise<InvitationResponseDto[]> {
    return this.invitationService.findAllByTenant(user.tenant_id);
  }
 
  @Post('invitations/:token/resend')
  @ApiOperation({ summary: 'Resend invitation email' })
  @ApiResponse({ status: 200, description: 'Invitation resent successfully', type: InvitationResponseDto })
  @ApiResponse({ status: 404, description: 'Invitation not found' })
  @ApiResponse({ status: 400, description: 'Only pending invitations can be resent' })
  async resendInvitation(
    @Param('token') token: string,
    @CurrentUser() user: RequestUser,
  ): Promise<InvitationResponseDto> {
    return this.invitationService.resend(token, user.id, user.tenant_id);
  }
 
  @Delete('invitations/:id')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Cancel pending invitation' })
  @ApiResponse({ status: 204, description: 'Invitation cancelled' })
  @ApiResponse({ status: 404, description: 'Invitation not found' })
  @ApiResponse({ status: 400, description: 'Only pending invitations can be cancelled' })
  async cancelInvitation(
    @Param('id') id: string,
    @CurrentUser() user: RequestUser,
  ): Promise<void> {
    return this.invitationService.cancel(id, user.tenant_id);
  }
}