backend/src/users/users.controller.ts   A
last analyzed

Complexity

Total Complexity 10
Complexity/F 1.43

Size

Lines of Code 233
Function Count 7

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 191
dl 0
loc 233
ccs 36
cts 36
cp 1
rs 10
c 0
b 0
f 0
wmc 10
mnd 3
bc 3
fnc 7
bpm 0.4285
cpm 1.4285
noi 0

7 Functions

Rating   Name   Duplication   Size   Complexity  
A UsersController.getCustomerById 0 23 1
A UsersController.updateTerms 0 29 2
A UsersController.softDeleteUser 0 16 1
A UsersController.getAllCustomers 0 20 1
A UsersController.updateCustomer 0 41 1
A UsersController.adjustFunds 0 29 2
A UsersController.getAccountDetails 0 25 2
1 7
import {
2
  BadRequestException,
3
  Controller,
4
  Param,
5
  ForbiddenException,
6
  Patch,
7
  Get,
8
  Body,
9
  Req,
10
  UseGuards,
11
  Request,
12
} from '@nestjs/common';
13 7
import { UsersService } from './users.service';
14 7
import { UpdateTermsDto } from './dto/update-terms.dto/update-terms.dto';
15 7
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
16 7
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
17 7
import { UpdateUserDto } from './dto/update-user.dto/update-user.dto';
18 7
import { AdjustFundsDto } from './dto/update-user.dto/adjust-funds.dto';
19 7
import { AdminGuard } from '../auth/guards/admin.guard';
20 7
import { HTTP_STATUS } from '../constants/HTTP_responses';
21 7
import {
22
  ApiAuthResponses,
23
  ApiAdminResponses,
24
  ApiBadRequestResponse,
25
} from 'src/decorators/api-responses.decorator';
26
27 7
export const CustomerExample = {
28
  githubId: '169550',
29
  username: 'three-musketeers',
30
  email: 'dasthreemusketö[email protected]',
31
  roles: ['user'],
32
  hasAcceptedTerms: false,
33
  avatarUrl: 'https://avatars.githubusercontent.com/u/169550?v=4',
34
  createdAt: '2024-12-01T05:01:01.000Z',
35
  updatedAt: '2024-12-07T18:30:30.000Z',
36
} as const;
37
38
@Controller({ path: 'users', version: '1' })
39 7
export class UsersController {
40 12
  constructor(private readonly usersService: UsersService) {}
41
42
  @Patch('terms')
43
  @UseGuards(JwtAuthGuard)
44
  @ApiBearerAuth()
45
  @ApiOperation({ summary: 'Update terms acceptance status' })
46
  @ApiBody({
47
    description: 'The body containing the updated terms acceptance status',
48
    type: UpdateTermsDto,
49
  })
50
  @ApiResponse({
51
    status: HTTP_STATUS.OK,
52
    description: 'Terms acceptance status updated successfully',
53
    examples: {
54
      'application/json': {
55
        summary: 'Example of a successful terms update',
56
        value: {
57
          githubId: '12345',
58
          hasAcceptedTerms: true,
59
        },
60
      },
61
    },
62
  })
63
  @ApiBadRequestResponse()
64
  @ApiAuthResponses()
65 7
  async updateTerms(@Req() req, @Body() updateTermsDto: UpdateTermsDto) {
66 7
    if (typeof updateTermsDto.hasAcceptedTerms !== 'boolean') {
67 2
      throw new BadRequestException('Invalid input');
68
    }
69 5
    return await this.usersService.updateTerms(req.user.githubId, updateTermsDto.hasAcceptedTerms);
70
  }
71
  // Fetch all customers
72
  @Get()
73
  @UseGuards(JwtAuthGuard, AdminGuard)
74
  @ApiBearerAuth()
75
  @ApiOperation({ summary: 'Get all customers (Only for admin)' })
76
  @ApiResponse({
77
    status: HTTP_STATUS.OK,
78
    description: 'List of customers',
79
    examples: {
80
      'application/json': {
81
        summary: 'Example of a list of customers',
82
        value: [CustomerExample],
83
      },
84
    },
85
  })
86
  @ApiAuthResponses()
87
  @ApiAdminResponses()
88 7
  async getAllCustomers() {
89
    // return {userid: "hej1"};
90 1
    return await this.usersService.findAll();
91
  }
92
  // Fetch a customer by ID
93
  @Get(':githubId')
94
  @UseGuards(JwtAuthGuard, AdminGuard)
95
  @ApiBearerAuth()
96
  @ApiOperation({ summary: 'Get customer by id (Only for admin)' })
97
  @ApiResponse({
98
    status: HTTP_STATUS.OK,
99
    description: 'Customer details returned by id',
100
    examples: {
101
      'application/json': {
102
        summary: 'Example of a customer',
103
        value: CustomerExample,
104
      },
105
    },
106
  })
107
  @ApiResponse({
108
    status: HTTP_STATUS.NOT_FOUND,
109
    description: 'Customer not found',
110
  })
111
  @ApiAdminResponses()
112
  @ApiAuthResponses()
113 7
  async getCustomerById(@Param('githubId') githubId: string) {
114 4
    return await this.usersService.findById(githubId);
115
  }
116
  // Update a customer by ID
117
  @Patch(':githubId')
118
  @UseGuards(JwtAuthGuard, AdminGuard)
119
  @ApiBearerAuth()
120
  @ApiOperation({ summary: 'Update customer by githubId (Only for admin)' })
121
  @ApiParam({
122
    name: 'githubId',
123
    description: 'The GitHub ID of the user',
124
    example: '12345',
125
  })
126
  @ApiBody({
127
    description: 'The body containing the updated user details',
128
    type: UpdateUserDto,
129
  })
130
  @ApiResponse({
131
    status: HTTP_STATUS.OK,
132
    description: 'Customer updated successfully',
133
    examples: {
134
      'application/json': {
135
        summary: 'Example of a successful customer update',
136
        value: {
137
          githubId: '12345',
138
          email: '[email protected]',
139
          roles: ['admin'],
140
          hasAcceptedTerms: true,
141
        },
142
      },
143
    },
144
  })
145
  @ApiResponse({
146
    status: HTTP_STATUS.BAD_REQUEST,
147
    description: 'Invalid input with error message',
148
  })
149
  @ApiResponse({
150
    status: HTTP_STATUS.NOT_FOUND,
151
    description: 'Customer not found',
152
  })
153
  @ApiAdminResponses()
154
  @ApiAuthResponses()
155 7
  async updateCustomer(@Param('githubId') githubId: string, @Body() updateUserDto: UpdateUserDto) {
156 1
    return this.usersService.update(githubId, updateUserDto);
157
  }
158
159
  @Get(':githubId/account')
160
  @UseGuards(JwtAuthGuard)
161
  @ApiBearerAuth()
162
  @ApiOperation({
163
    summary: 'Get account balance and accumulated cost',
164
    description: 'Returns the users balance and accumulated monthly payment cost.',
165
  })
166
  @ApiResponse({
167
    status: HTTP_STATUS.OK,
168
    description: 'Account details retrieved successfully.',
169
  })
170 7
  async getAccountDetails(@Param('githubId') githubId: string, @Request() req: any) {
171 4
    const user = await this.usersService.findById(githubId);
172 4
    const authenticatedUser = req.user;
173
174
    // Only allow if the user is an admin or viewing their own account
175 4
    if (authenticatedUser.githubId !== githubId && !authenticatedUser.roles.includes('admin')) {
176 1
      throw new ForbiddenException("You are not allowed to view other users' accounts.");
177
    }
178
179 3
    return {
180
      balance: user.balance,
181
      accumulatedCost: user.accumulatedCost,
182
      isMonthlyPayment: user.isMonthlyPayment,
183
    };
184
  }
185
  @Patch(':githubId/adjust-funds')
186
  @UseGuards(JwtAuthGuard)
187
  @ApiBearerAuth()
188
  @ApiOperation({
189
    summary: 'Adjust user balance and payment mode',
190
    description: 'Set a new balance for the user and optionally toggle monthly payment mode.',
191
  })
192
  @ApiResponse({
193
    status: HTTP_STATUS.OK,
194
    description: 'User balance adjusted successfully',
195
  })
196
  @ApiResponse({
197
    status: HTTP_STATUS.NOT_FOUND,
198
    description: 'User not found',
199
  })
200
  @ApiAdminResponses()
201 7
  async adjustFunds(
202
    @Param('githubId') githubId: string,
203
    @Body() adjustFundsDto: AdjustFundsDto,
204
    @Request() req: any,
205
  ) {
206 5
    const authenticatedUser = req.user;
207
208
    // Only allow if the user is an admin or adjusting their own account
209 5
    if (authenticatedUser.githubId !== githubId && !authenticatedUser.roles.includes('admin')) {
210 1
      throw new ForbiddenException("You are not allowed to adjust other users' accounts.");
211
    }
212
213 4
    return await this.usersService.adjustFunds(githubId, adjustFundsDto);
214
  }
215
216
  @Patch(':githubId/soft-delete')
217
  @UseGuards(JwtAuthGuard, AdminGuard)
218
  @ApiBearerAuth()
219
  @ApiOperation({ summary: 'Soft delete a user (Only for admin - set user role to inactive)' })
220
  @ApiResponse({
221
    status: HTTP_STATUS.OK,
222
    description: 'User soft-deleted successfully',
223
  })
224
  @ApiResponse({
225
    status: HTTP_STATUS.NOT_FOUND,
226
    description: 'User not found',
227
  })
228
  @ApiAdminResponses()
229 7
  async softDeleteUser(@Param('githubId') githubId: string) {
230 3
    return await this.usersService.softDeleteUser(githubId);
231
  }
232
}
233