@flusys/nestjs-auth 1.0.0-beta → 1.0.0-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +274 -291
- package/cjs/config/auth.constants.js +12 -0
- package/cjs/controllers/authentication.controller.js +219 -10
- package/cjs/controllers/branch.controller.js +44 -1
- package/cjs/controllers/company-selection.controller.js +27 -20
- package/cjs/controllers/company.controller.js +44 -1
- package/cjs/controllers/user-permission.controller.js +40 -25
- package/cjs/controllers/user.controller.js +211 -7
- package/cjs/dtos/authentication.dto.js +119 -13
- package/cjs/dtos/user-permission.dto.js +28 -0
- package/cjs/dtos/user.dto.js +19 -4
- package/cjs/entities/index.js +5 -1
- package/cjs/entities/pending-registration.entity.js +125 -0
- package/cjs/entities/user-company-permission.entity.js +0 -6
- package/cjs/entities/user-token.entity.js +129 -0
- package/cjs/guards/auth-throttler.guard.js +53 -0
- package/cjs/interceptors/clear-token.interceptor.js +3 -6
- package/cjs/interceptors/set-token.interceptor.js +38 -31
- package/cjs/interfaces/auth-email-provider.interface.js +45 -0
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/user-enricher.interface.js +4 -0
- package/cjs/modules/auth.module.js +8 -20
- package/cjs/services/auth-config.service.js +23 -2
- package/cjs/services/auth-datasource.provider.js +5 -3
- package/cjs/services/auth-email.service.js +471 -0
- package/cjs/services/authentication.service.js +169 -77
- package/cjs/services/branch.service.js +6 -5
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +0 -2
- package/cjs/services/user.service.js +213 -34
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +3 -0
- package/controllers/authentication.controller.d.ts +13 -9
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/user.controller.d.ts +33 -0
- package/dtos/authentication.dto.d.ts +21 -3
- package/dtos/company-branch.dto.d.ts +0 -1
- package/dtos/company.dto.d.ts +0 -1
- package/dtos/user-permission.dto.d.ts +4 -0
- package/dtos/user.dto.d.ts +1 -2
- package/entities/index.d.ts +7 -3
- package/entities/pending-registration.entity.d.ts +17 -0
- package/entities/user-company-permission.entity.d.ts +0 -2
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +6 -2
- package/fesm/controllers/authentication.controller.js +221 -12
- package/fesm/controllers/branch.controller.js +45 -2
- package/fesm/controllers/company-selection.controller.js +28 -21
- package/fesm/controllers/company.controller.js +45 -2
- package/fesm/controllers/user-permission.controller.js +41 -26
- package/fesm/controllers/user.controller.js +214 -10
- package/fesm/dtos/authentication.dto.js +106 -14
- package/fesm/dtos/user-permission.dto.js +28 -0
- package/fesm/dtos/user.dto.js +20 -5
- package/fesm/entities/index.js +7 -1
- package/fesm/entities/pending-registration.entity.js +115 -0
- package/fesm/entities/user-company-permission.entity.js +0 -6
- package/fesm/entities/user-token.entity.js +113 -0
- package/fesm/guards/auth-throttler.guard.js +43 -0
- package/fesm/interceptors/clear-token.interceptor.js +2 -5
- package/fesm/interceptors/set-token.interceptor.js +37 -30
- package/fesm/interfaces/auth-email-provider.interface.js +38 -0
- package/fesm/interfaces/authentication.interface.js +1 -1
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/user-enricher.interface.js +26 -0
- package/fesm/modules/auth.module.js +10 -22
- package/fesm/services/auth-config.service.js +24 -3
- package/fesm/services/auth-datasource.provider.js +6 -4
- package/fesm/services/auth-email.service.js +420 -0
- package/fesm/services/authentication.service.js +169 -77
- package/fesm/services/branch.service.js +6 -5
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +1 -3
- package/fesm/services/user.service.js +215 -36
- package/fesm/validators/password.validator.js +48 -0
- package/guards/auth-throttler.guard.d.ts +7 -0
- package/interceptors/set-token.interceptor.d.ts +1 -0
- package/interfaces/auth-email-provider.interface.d.ts +6 -0
- package/interfaces/auth-module-options.interface.d.ts +4 -1
- package/interfaces/authentication.interface.d.ts +14 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/user-enricher.interface.d.ts +64 -0
- package/interfaces/user.interface.d.ts +1 -0
- package/modules/auth.module.d.ts +0 -1
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +5 -1
- package/services/auth-email.service.d.ts +51 -0
- package/services/authentication.service.d.ts +16 -11
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/index.d.ts +1 -0
- package/services/user-permission.service.d.ts +0 -1
- package/services/user.service.d.ts +19 -3
- package/validators/password.validator.d.ts +10 -0
|
@@ -25,14 +25,13 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { Body, Controller,
|
|
29
|
-
import { ApiBearerAuth, ApiBody, ApiOperation,
|
|
30
|
-
import { JwtAuthGuard } from '@flusys/nestjs-shared
|
|
28
|
+
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
29
|
+
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
30
|
+
import { JwtAuthGuard, RequirePermission, USER_PERMISSIONS } from '@flusys/nestjs-shared';
|
|
31
31
|
import { AssignUserCompanyDto, AssignUserBranchDto, UserCompaniesResponseDto, UserBranchesResponseDto } from '../dtos/user-permission.dto';
|
|
32
32
|
import { UserPermissionService } from '../services/user-permission.service';
|
|
33
33
|
export class UserPermissionController {
|
|
34
|
-
|
|
35
|
-
/** Batch assign/revoke user-company permissions */ async assignUserCompany(dto) {
|
|
34
|
+
async assignUserCompany(dto) {
|
|
36
35
|
let addedCount = 0;
|
|
37
36
|
let removedCount = 0;
|
|
38
37
|
for (const item of dto.items){
|
|
@@ -52,9 +51,8 @@ export class UserPermissionController {
|
|
|
52
51
|
message: `Processed ${addedCount} additions and ${removedCount} removals`
|
|
53
52
|
};
|
|
54
53
|
}
|
|
55
|
-
|
|
54
|
+
async getUserCompanies(userId) {
|
|
56
55
|
const permissions = await this.userPermissionService.findUserCompanies(userId);
|
|
57
|
-
// Map to DTO format with populated company details
|
|
58
56
|
const data = permissions.map((permission)=>({
|
|
59
57
|
id: permission.id,
|
|
60
58
|
userId: permission.userId,
|
|
@@ -63,11 +61,12 @@ export class UserPermissionController {
|
|
|
63
61
|
companySlug: permission.company?.slug || ''
|
|
64
62
|
}));
|
|
65
63
|
return {
|
|
64
|
+
success: true,
|
|
65
|
+
message: 'User companies retrieved successfully',
|
|
66
66
|
data
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
/** Batch assign/revoke user-branch permissions */ async assignUserBranch(dto) {
|
|
69
|
+
async assignUserBranch(dto) {
|
|
71
70
|
let addedCount = 0;
|
|
72
71
|
let removedCount = 0;
|
|
73
72
|
for (const item of dto.items){
|
|
@@ -87,9 +86,8 @@ export class UserPermissionController {
|
|
|
87
86
|
message: `Processed ${addedCount} additions and ${removedCount} removals`
|
|
88
87
|
};
|
|
89
88
|
}
|
|
90
|
-
|
|
89
|
+
async getUserBranches(userId) {
|
|
91
90
|
const permissions = await this.userPermissionService.findUserBranches(userId);
|
|
92
|
-
// Map to DTO format with populated branch details
|
|
93
91
|
const data = permissions.map((permission)=>({
|
|
94
92
|
id: permission.id,
|
|
95
93
|
userId: permission.userId,
|
|
@@ -99,10 +97,11 @@ export class UserPermissionController {
|
|
|
99
97
|
companyId: permission.branch?.companyId || ''
|
|
100
98
|
}));
|
|
101
99
|
return {
|
|
100
|
+
success: true,
|
|
101
|
+
message: 'User branches retrieved successfully',
|
|
102
102
|
data
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
106
105
|
constructor(userPermissionService){
|
|
107
106
|
_define_property(this, "userPermissionService", void 0);
|
|
108
107
|
this.userPermissionService = userPermissionService;
|
|
@@ -110,6 +109,7 @@ export class UserPermissionController {
|
|
|
110
109
|
}
|
|
111
110
|
_ts_decorate([
|
|
112
111
|
Post('user-company/assign'),
|
|
112
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
113
113
|
ApiOperation({
|
|
114
114
|
summary: 'Batch assign/revoke user-company permissions',
|
|
115
115
|
description: `
|
|
@@ -164,22 +164,29 @@ Batch operation to assign or revoke user permissions to companies.
|
|
|
164
164
|
_ts_metadata("design:returntype", Promise)
|
|
165
165
|
], UserPermissionController.prototype, "assignUserCompany", null);
|
|
166
166
|
_ts_decorate([
|
|
167
|
-
|
|
167
|
+
Post('get-user-company'),
|
|
168
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
168
169
|
ApiOperation({
|
|
169
170
|
summary: 'Get user companies',
|
|
170
171
|
description: 'Returns all companies the user has access to.'
|
|
171
172
|
}),
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
ApiBody({
|
|
174
|
+
schema: {
|
|
175
|
+
properties: {
|
|
176
|
+
userId: {
|
|
177
|
+
type: 'string'
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
required: [
|
|
181
|
+
'userId'
|
|
182
|
+
]
|
|
183
|
+
}
|
|
177
184
|
}),
|
|
178
185
|
ApiResponse({
|
|
179
186
|
status: 200,
|
|
180
187
|
type: UserCompaniesResponseDto
|
|
181
188
|
}),
|
|
182
|
-
_ts_param(0,
|
|
189
|
+
_ts_param(0, Body('userId')),
|
|
183
190
|
_ts_metadata("design:type", Function),
|
|
184
191
|
_ts_metadata("design:paramtypes", [
|
|
185
192
|
String
|
|
@@ -188,6 +195,7 @@ _ts_decorate([
|
|
|
188
195
|
], UserPermissionController.prototype, "getUserCompanies", null);
|
|
189
196
|
_ts_decorate([
|
|
190
197
|
Post('user-branch/assign'),
|
|
198
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
191
199
|
ApiOperation({
|
|
192
200
|
summary: 'Batch assign/revoke user-branch permissions',
|
|
193
201
|
description: `
|
|
@@ -242,22 +250,29 @@ Batch operation to assign or revoke user permissions to branches.
|
|
|
242
250
|
_ts_metadata("design:returntype", Promise)
|
|
243
251
|
], UserPermissionController.prototype, "assignUserBranch", null);
|
|
244
252
|
_ts_decorate([
|
|
245
|
-
|
|
253
|
+
Post('get-user-branch'),
|
|
254
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
246
255
|
ApiOperation({
|
|
247
256
|
summary: 'Get user branches',
|
|
248
257
|
description: 'Returns all branches the user has access to.'
|
|
249
258
|
}),
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
ApiBody({
|
|
260
|
+
schema: {
|
|
261
|
+
properties: {
|
|
262
|
+
userId: {
|
|
263
|
+
type: 'string'
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
required: [
|
|
267
|
+
'userId'
|
|
268
|
+
]
|
|
269
|
+
}
|
|
255
270
|
}),
|
|
256
271
|
ApiResponse({
|
|
257
272
|
status: 200,
|
|
258
273
|
type: UserBranchesResponseDto
|
|
259
274
|
}),
|
|
260
|
-
_ts_param(0,
|
|
275
|
+
_ts_param(0, Body('userId')),
|
|
261
276
|
_ts_metadata("design:type", Function),
|
|
262
277
|
_ts_metadata("design:paramtypes", [
|
|
263
278
|
String
|
|
@@ -25,51 +25,160 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { createApiController } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import { CurrentUser } from '@flusys/nestjs-shared/decorators';
|
|
28
|
+
import { createApiController, USER_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
30
30
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
31
31
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
32
|
-
import { Body, Controller, Inject, Param, Post,
|
|
32
|
+
import { Body, Controller, Inject, Param, Post, UseGuards } from '@nestjs/common';
|
|
33
33
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
|
34
34
|
import { CreateUserDto, UpdateUserDto, UserResponseDto } from '../dtos/user.dto';
|
|
35
35
|
import { UserService } from '../services/user.service';
|
|
36
36
|
export class UserController extends createApiController(CreateUserDto, UpdateUserDto, UserResponseDto, {
|
|
37
|
-
security:
|
|
37
|
+
security: {
|
|
38
|
+
insert: {
|
|
39
|
+
level: 'permission',
|
|
40
|
+
permissions: [
|
|
41
|
+
USER_PERMISSIONS.CREATE
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
insertMany: {
|
|
45
|
+
level: 'permission',
|
|
46
|
+
permissions: [
|
|
47
|
+
USER_PERMISSIONS.CREATE
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
getById: {
|
|
51
|
+
level: 'permission',
|
|
52
|
+
permissions: [
|
|
53
|
+
USER_PERMISSIONS.READ
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
getAll: {
|
|
57
|
+
level: 'permission',
|
|
58
|
+
permissions: [
|
|
59
|
+
USER_PERMISSIONS.READ
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
update: {
|
|
63
|
+
level: 'permission',
|
|
64
|
+
permissions: [
|
|
65
|
+
USER_PERMISSIONS.UPDATE
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
updateMany: {
|
|
69
|
+
level: 'permission',
|
|
70
|
+
permissions: [
|
|
71
|
+
USER_PERMISSIONS.UPDATE
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
delete: {
|
|
75
|
+
level: 'permission',
|
|
76
|
+
permissions: [
|
|
77
|
+
USER_PERMISSIONS.DELETE
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
38
81
|
}) {
|
|
39
|
-
|
|
40
|
-
|
|
82
|
+
async getProfileWithExtras(id, user) {
|
|
83
|
+
const data = await this.service.getProfileWithExtras(id, user);
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
data
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async verifyEmail(id) {
|
|
41
90
|
await this.service.verifyEmail(id);
|
|
42
91
|
return {
|
|
92
|
+
success: true,
|
|
43
93
|
message: 'Email verified successfully'
|
|
44
94
|
};
|
|
45
95
|
}
|
|
46
|
-
|
|
96
|
+
async verifyPhone(id) {
|
|
47
97
|
await this.service.verifyPhone(id);
|
|
48
98
|
return {
|
|
99
|
+
success: true,
|
|
49
100
|
message: 'Phone verified successfully'
|
|
50
101
|
};
|
|
51
102
|
}
|
|
52
|
-
|
|
103
|
+
async updateStatus(id, isActive, user) {
|
|
53
104
|
await this.service.updateStatus(id, isActive, user);
|
|
54
105
|
return {
|
|
106
|
+
success: true,
|
|
55
107
|
message: 'Status updated successfully'
|
|
56
108
|
};
|
|
57
109
|
}
|
|
58
|
-
|
|
110
|
+
async profile(dto, user) {
|
|
59
111
|
const data = await this.service.profile(dto, user);
|
|
60
112
|
return {
|
|
113
|
+
success: true,
|
|
61
114
|
message: 'Profile updated successfully',
|
|
62
115
|
data
|
|
63
116
|
};
|
|
64
117
|
}
|
|
118
|
+
async getProfileSections() {
|
|
119
|
+
const sections = await this.service.getProfileSections();
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
message: 'Profile sections retrieved successfully',
|
|
123
|
+
data: sections
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async getProfileSectionData(id, sectionId, user) {
|
|
127
|
+
const data = await this.service.getProfileSectionData(id, sectionId, user);
|
|
128
|
+
return {
|
|
129
|
+
success: true,
|
|
130
|
+
message: 'Profile section data retrieved successfully',
|
|
131
|
+
data
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
async updateProfileSection(id, sectionId, data, user) {
|
|
135
|
+
await this.service.updateProfileSection(id, sectionId, data, user);
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
message: 'Section updated successfully'
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async getProfileCompletion(id, user) {
|
|
142
|
+
const percentage = await this.service.getProfileCompletion(id, user);
|
|
143
|
+
return {
|
|
144
|
+
success: true,
|
|
145
|
+
message: 'Profile completion retrieved successfully',
|
|
146
|
+
data: {
|
|
147
|
+
completionPercentage: percentage
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
65
151
|
constructor(service){
|
|
66
152
|
super(service), _define_property(this, "service", void 0), this.service = service;
|
|
67
153
|
}
|
|
68
154
|
}
|
|
155
|
+
_ts_decorate([
|
|
156
|
+
Post(':id/profile-extras'),
|
|
157
|
+
UseGuards(JwtAuthGuard),
|
|
158
|
+
ApiBearerAuth(),
|
|
159
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
160
|
+
ApiOperation({
|
|
161
|
+
summary: 'Get user profile with extras',
|
|
162
|
+
description: 'Returns user profile along with extra data (roles, permissions, etc.) if UserEnricher is provided.'
|
|
163
|
+
}),
|
|
164
|
+
ApiParam({
|
|
165
|
+
name: 'id',
|
|
166
|
+
description: 'User ID'
|
|
167
|
+
}),
|
|
168
|
+
_ts_param(0, Param('id')),
|
|
169
|
+
_ts_param(1, CurrentUser()),
|
|
170
|
+
_ts_metadata("design:type", Function),
|
|
171
|
+
_ts_metadata("design:paramtypes", [
|
|
172
|
+
String,
|
|
173
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
174
|
+
]),
|
|
175
|
+
_ts_metadata("design:returntype", Promise)
|
|
176
|
+
], UserController.prototype, "getProfileWithExtras", null);
|
|
69
177
|
_ts_decorate([
|
|
70
178
|
Post(':id/verify-email'),
|
|
71
179
|
UseGuards(JwtAuthGuard),
|
|
72
180
|
ApiBearerAuth(),
|
|
181
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
73
182
|
ApiOperation({
|
|
74
183
|
summary: 'Verify user email'
|
|
75
184
|
}),
|
|
@@ -88,6 +197,7 @@ _ts_decorate([
|
|
|
88
197
|
Post(':id/verify-phone'),
|
|
89
198
|
UseGuards(JwtAuthGuard),
|
|
90
199
|
ApiBearerAuth(),
|
|
200
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
91
201
|
ApiOperation({
|
|
92
202
|
summary: 'Verify user phone'
|
|
93
203
|
}),
|
|
@@ -103,9 +213,10 @@ _ts_decorate([
|
|
|
103
213
|
_ts_metadata("design:returntype", Promise)
|
|
104
214
|
], UserController.prototype, "verifyPhone", null);
|
|
105
215
|
_ts_decorate([
|
|
106
|
-
|
|
216
|
+
Post(':id/status'),
|
|
107
217
|
UseGuards(JwtAuthGuard),
|
|
108
218
|
ApiBearerAuth(),
|
|
219
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
109
220
|
ApiOperation({
|
|
110
221
|
summary: 'Update user active status',
|
|
111
222
|
description: 'Updates user active status. When company feature is enabled, updates the status for the current company context.'
|
|
@@ -151,6 +262,99 @@ _ts_decorate([
|
|
|
151
262
|
]),
|
|
152
263
|
_ts_metadata("design:returntype", Promise)
|
|
153
264
|
], UserController.prototype, "profile", null);
|
|
265
|
+
_ts_decorate([
|
|
266
|
+
Post('profile-sections'),
|
|
267
|
+
UseGuards(JwtAuthGuard),
|
|
268
|
+
ApiBearerAuth(),
|
|
269
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
270
|
+
ApiOperation({
|
|
271
|
+
summary: 'Get profile section definitions',
|
|
272
|
+
description: 'Returns available profile sections for multi-step profile (if enricher configured).'
|
|
273
|
+
}),
|
|
274
|
+
_ts_metadata("design:type", Function),
|
|
275
|
+
_ts_metadata("design:paramtypes", []),
|
|
276
|
+
_ts_metadata("design:returntype", Promise)
|
|
277
|
+
], UserController.prototype, "getProfileSections", null);
|
|
278
|
+
_ts_decorate([
|
|
279
|
+
Post(':id/profile-section/:sectionId'),
|
|
280
|
+
UseGuards(JwtAuthGuard),
|
|
281
|
+
ApiBearerAuth(),
|
|
282
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
283
|
+
ApiOperation({
|
|
284
|
+
summary: 'Get profile section data',
|
|
285
|
+
description: 'Returns data for a specific profile section.'
|
|
286
|
+
}),
|
|
287
|
+
ApiParam({
|
|
288
|
+
name: 'id',
|
|
289
|
+
description: 'User ID'
|
|
290
|
+
}),
|
|
291
|
+
ApiParam({
|
|
292
|
+
name: 'sectionId',
|
|
293
|
+
description: 'Section identifier'
|
|
294
|
+
}),
|
|
295
|
+
_ts_param(0, Param('id')),
|
|
296
|
+
_ts_param(1, Param('sectionId')),
|
|
297
|
+
_ts_param(2, CurrentUser()),
|
|
298
|
+
_ts_metadata("design:type", Function),
|
|
299
|
+
_ts_metadata("design:paramtypes", [
|
|
300
|
+
String,
|
|
301
|
+
String,
|
|
302
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
303
|
+
]),
|
|
304
|
+
_ts_metadata("design:returntype", Promise)
|
|
305
|
+
], UserController.prototype, "getProfileSectionData", null);
|
|
306
|
+
_ts_decorate([
|
|
307
|
+
Post(':id/profile-section/:sectionId/update'),
|
|
308
|
+
UseGuards(JwtAuthGuard),
|
|
309
|
+
ApiBearerAuth(),
|
|
310
|
+
RequirePermission(USER_PERMISSIONS.UPDATE),
|
|
311
|
+
ApiOperation({
|
|
312
|
+
summary: 'Update profile section',
|
|
313
|
+
description: 'Updates a specific profile section data.'
|
|
314
|
+
}),
|
|
315
|
+
ApiParam({
|
|
316
|
+
name: 'id',
|
|
317
|
+
description: 'User ID'
|
|
318
|
+
}),
|
|
319
|
+
ApiParam({
|
|
320
|
+
name: 'sectionId',
|
|
321
|
+
description: 'Section identifier'
|
|
322
|
+
}),
|
|
323
|
+
_ts_param(0, Param('id')),
|
|
324
|
+
_ts_param(1, Param('sectionId')),
|
|
325
|
+
_ts_param(2, Body()),
|
|
326
|
+
_ts_param(3, CurrentUser()),
|
|
327
|
+
_ts_metadata("design:type", Function),
|
|
328
|
+
_ts_metadata("design:paramtypes", [
|
|
329
|
+
String,
|
|
330
|
+
String,
|
|
331
|
+
typeof Record === "undefined" ? Object : Record,
|
|
332
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
333
|
+
]),
|
|
334
|
+
_ts_metadata("design:returntype", Promise)
|
|
335
|
+
], UserController.prototype, "updateProfileSection", null);
|
|
336
|
+
_ts_decorate([
|
|
337
|
+
Post(':id/profile-completion'),
|
|
338
|
+
UseGuards(JwtAuthGuard),
|
|
339
|
+
ApiBearerAuth(),
|
|
340
|
+
RequirePermission(USER_PERMISSIONS.READ),
|
|
341
|
+
ApiOperation({
|
|
342
|
+
summary: 'Get profile completion percentage',
|
|
343
|
+
description: 'Returns overall profile completion percentage.'
|
|
344
|
+
}),
|
|
345
|
+
ApiParam({
|
|
346
|
+
name: 'id',
|
|
347
|
+
description: 'User ID'
|
|
348
|
+
}),
|
|
349
|
+
_ts_param(0, Param('id')),
|
|
350
|
+
_ts_param(1, CurrentUser()),
|
|
351
|
+
_ts_metadata("design:type", Function),
|
|
352
|
+
_ts_metadata("design:paramtypes", [
|
|
353
|
+
String,
|
|
354
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
355
|
+
]),
|
|
356
|
+
_ts_metadata("design:returntype", Promise)
|
|
357
|
+
], UserController.prototype, "getProfileCompletion", null);
|
|
154
358
|
UserController = _ts_decorate([
|
|
155
359
|
ApiTags('Users'),
|
|
156
360
|
Controller('administration/users'),
|
|
@@ -21,7 +21,8 @@ function _ts_metadata(k, v) {
|
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
23
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
24
|
-
import { IsEmail, IsNotEmpty, IsOptional, IsString, IsUUID, MaxLength,
|
|
24
|
+
import { IsEmail, IsNotEmpty, IsOptional, IsString, IsUUID, MaxLength, ValidateIf } from 'class-validator';
|
|
25
|
+
import { IsStrongPassword } from '../validators/password.validator';
|
|
25
26
|
// Request DTOs
|
|
26
27
|
/** Login Request DTO */ export class LoginDto {
|
|
27
28
|
constructor(){
|
|
@@ -40,12 +41,12 @@ _ts_decorate([
|
|
|
40
41
|
], LoginDto.prototype, "email", void 0);
|
|
41
42
|
_ts_decorate([
|
|
42
43
|
ApiProperty({
|
|
43
|
-
example: '
|
|
44
|
-
description: 'User password
|
|
44
|
+
example: 'SecureP@ss1',
|
|
45
|
+
description: 'User password'
|
|
45
46
|
}),
|
|
46
47
|
IsString(),
|
|
47
48
|
IsNotEmpty(),
|
|
48
|
-
|
|
49
|
+
MaxLength(128),
|
|
49
50
|
_ts_metadata("design:type", String)
|
|
50
51
|
], LoginDto.prototype, "password", void 0);
|
|
51
52
|
/** Registration Request DTO - Supports simple and company-based registration */ export class RegistrationDto {
|
|
@@ -84,13 +85,13 @@ _ts_decorate([
|
|
|
84
85
|
], RegistrationDto.prototype, "email", void 0);
|
|
85
86
|
_ts_decorate([
|
|
86
87
|
ApiProperty({
|
|
87
|
-
example: '
|
|
88
|
-
description: 'Password (min
|
|
88
|
+
example: 'StrongP@ss123',
|
|
89
|
+
description: 'Password (min 8 chars, requires uppercase, lowercase, number, special char)'
|
|
89
90
|
}),
|
|
90
91
|
IsNotEmpty(),
|
|
91
92
|
IsString(),
|
|
92
|
-
|
|
93
|
-
MaxLength(
|
|
93
|
+
IsStrongPassword(),
|
|
94
|
+
MaxLength(128),
|
|
94
95
|
_ts_metadata("design:type", String)
|
|
95
96
|
], RegistrationDto.prototype, "password", void 0);
|
|
96
97
|
_ts_decorate([
|
|
@@ -151,6 +152,7 @@ _ts_decorate([
|
|
|
151
152
|
}),
|
|
152
153
|
IsOptional(),
|
|
153
154
|
IsString(),
|
|
155
|
+
MaxLength(500),
|
|
154
156
|
_ts_metadata("design:type", String)
|
|
155
157
|
], RegistrationDto.prototype, "newCompanyAddress", void 0);
|
|
156
158
|
/** Refresh Token Request DTO - refreshToken optional in body (browsers use HTTP-only cookie) */ export class RefreshTokenDto {
|
|
@@ -180,16 +182,17 @@ _ts_decorate([
|
|
|
180
182
|
}),
|
|
181
183
|
IsString(),
|
|
182
184
|
IsNotEmpty(),
|
|
185
|
+
MaxLength(128),
|
|
183
186
|
_ts_metadata("design:type", String)
|
|
184
187
|
], ChangePasswordDto.prototype, "currentPassword", void 0);
|
|
185
188
|
_ts_decorate([
|
|
186
189
|
ApiProperty({
|
|
187
|
-
example: '
|
|
188
|
-
description: 'New password (min
|
|
190
|
+
example: 'NewP@ssword456',
|
|
191
|
+
description: 'New password (min 8 chars, requires uppercase, lowercase, number, special char)'
|
|
189
192
|
}),
|
|
190
193
|
IsString(),
|
|
191
194
|
IsNotEmpty(),
|
|
192
|
-
|
|
195
|
+
IsStrongPassword(),
|
|
193
196
|
_ts_metadata("design:type", String)
|
|
194
197
|
], ChangePasswordDto.prototype, "newPassword", void 0);
|
|
195
198
|
/** Select Company & Branch Request DTO - Used after login when user needs to select company and branch */ export class SelectDto {
|
|
@@ -503,16 +506,17 @@ _ts_decorate([
|
|
|
503
506
|
_define_property(this, "company", void 0);
|
|
504
507
|
_define_property(this, "branch", void 0);
|
|
505
508
|
_define_property(this, "companyFeatureEnabled", void 0);
|
|
509
|
+
_define_property(this, "requiresEmailVerification", void 0);
|
|
506
510
|
}
|
|
507
511
|
}
|
|
508
512
|
_ts_decorate([
|
|
509
|
-
|
|
513
|
+
ApiPropertyOptional({
|
|
510
514
|
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
511
515
|
}),
|
|
512
516
|
_ts_metadata("design:type", String)
|
|
513
517
|
], RegistrationResponseDto.prototype, "accessToken", void 0);
|
|
514
518
|
_ts_decorate([
|
|
515
|
-
|
|
519
|
+
ApiPropertyOptional({
|
|
516
520
|
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
517
521
|
}),
|
|
518
522
|
_ts_metadata("design:type", String)
|
|
@@ -539,12 +543,19 @@ _ts_decorate([
|
|
|
539
543
|
_ts_metadata("design:type", typeof BranchInfoDto === "undefined" ? Object : BranchInfoDto)
|
|
540
544
|
], RegistrationResponseDto.prototype, "branch", void 0);
|
|
541
545
|
_ts_decorate([
|
|
542
|
-
|
|
546
|
+
ApiPropertyOptional({
|
|
543
547
|
example: true,
|
|
544
548
|
description: 'Whether company feature is enabled'
|
|
545
549
|
}),
|
|
546
550
|
_ts_metadata("design:type", Boolean)
|
|
547
551
|
], RegistrationResponseDto.prototype, "companyFeatureEnabled", void 0);
|
|
552
|
+
_ts_decorate([
|
|
553
|
+
ApiPropertyOptional({
|
|
554
|
+
example: true,
|
|
555
|
+
description: 'Whether email verification is required'
|
|
556
|
+
}),
|
|
557
|
+
_ts_metadata("design:type", Boolean)
|
|
558
|
+
], RegistrationResponseDto.prototype, "requiresEmailVerification", void 0);
|
|
548
559
|
/** Me Response DTO - Returned by GET /auth/me (user data only, no tokens) */ export class MeResponseDto {
|
|
549
560
|
constructor(){
|
|
550
561
|
_define_property(this, "user", void 0);
|
|
@@ -619,3 +630,84 @@ _ts_decorate([
|
|
|
619
630
|
}),
|
|
620
631
|
_ts_metadata("design:type", Array)
|
|
621
632
|
], CompanySelectionResponseDto.prototype, "companies", void 0);
|
|
633
|
+
/** Login Response when email verification required */ export class LoginResponseRequiresEmailVerificationDto {
|
|
634
|
+
constructor(){
|
|
635
|
+
_define_property(this, "requiresEmailVerification", void 0);
|
|
636
|
+
_define_property(this, "email", void 0);
|
|
637
|
+
_define_property(this, "message", void 0);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
_ts_decorate([
|
|
641
|
+
ApiProperty({
|
|
642
|
+
example: true
|
|
643
|
+
}),
|
|
644
|
+
_ts_metadata("design:type", Boolean)
|
|
645
|
+
], LoginResponseRequiresEmailVerificationDto.prototype, "requiresEmailVerification", void 0);
|
|
646
|
+
_ts_decorate([
|
|
647
|
+
ApiProperty({
|
|
648
|
+
example: 'john@example.com'
|
|
649
|
+
}),
|
|
650
|
+
_ts_metadata("design:type", String)
|
|
651
|
+
], LoginResponseRequiresEmailVerificationDto.prototype, "email", void 0);
|
|
652
|
+
_ts_decorate([
|
|
653
|
+
ApiProperty({
|
|
654
|
+
example: 'Please verify your email address before logging in.'
|
|
655
|
+
}),
|
|
656
|
+
_ts_metadata("design:type", String)
|
|
657
|
+
], LoginResponseRequiresEmailVerificationDto.prototype, "message", void 0);
|
|
658
|
+
// Email Auth DTOs
|
|
659
|
+
/** Forgot Password Request DTO - Initiates password reset flow */ export class ForgotPasswordDto {
|
|
660
|
+
constructor(){
|
|
661
|
+
_define_property(this, "email", void 0);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
_ts_decorate([
|
|
665
|
+
ApiProperty({
|
|
666
|
+
example: 'john@example.com',
|
|
667
|
+
description: 'Email address to send reset link to'
|
|
668
|
+
}),
|
|
669
|
+
IsEmail(),
|
|
670
|
+
IsNotEmpty(),
|
|
671
|
+
_ts_metadata("design:type", String)
|
|
672
|
+
], ForgotPasswordDto.prototype, "email", void 0);
|
|
673
|
+
/** Reset Password Request DTO - Resets password using token */ export class ResetPasswordDto {
|
|
674
|
+
constructor(){
|
|
675
|
+
_define_property(this, "token", void 0);
|
|
676
|
+
_define_property(this, "newPassword", void 0);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
_ts_decorate([
|
|
680
|
+
ApiProperty({
|
|
681
|
+
example: 'a1b2c3d4e5f6...',
|
|
682
|
+
description: 'Password reset token from email'
|
|
683
|
+
}),
|
|
684
|
+
IsString(),
|
|
685
|
+
IsNotEmpty(),
|
|
686
|
+
_ts_metadata("design:type", String)
|
|
687
|
+
], ResetPasswordDto.prototype, "token", void 0);
|
|
688
|
+
_ts_decorate([
|
|
689
|
+
ApiProperty({
|
|
690
|
+
example: 'NewSecureP@ss123',
|
|
691
|
+
description: 'New password (min 8 chars, requires uppercase, lowercase, number, special char)'
|
|
692
|
+
}),
|
|
693
|
+
IsString(),
|
|
694
|
+
IsNotEmpty(),
|
|
695
|
+
IsStrongPassword(),
|
|
696
|
+
_ts_metadata("design:type", String)
|
|
697
|
+
], ResetPasswordDto.prototype, "newPassword", void 0);
|
|
698
|
+
/** Verify Email Request DTO - Verifies email using token */ export class VerifyEmailDto {
|
|
699
|
+
constructor(){
|
|
700
|
+
_define_property(this, "token", void 0);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
_ts_decorate([
|
|
704
|
+
ApiProperty({
|
|
705
|
+
example: 'a1b2c3d4e5f6...',
|
|
706
|
+
description: 'Email verification token from email'
|
|
707
|
+
}),
|
|
708
|
+
IsString(),
|
|
709
|
+
IsNotEmpty(),
|
|
710
|
+
_ts_metadata("design:type", String)
|
|
711
|
+
], VerifyEmailDto.prototype, "token", void 0);
|
|
712
|
+
/** Resend Verification Email Request DTO - Same structure as ForgotPasswordDto */ export class ResendVerificationDto extends ForgotPasswordDto {
|
|
713
|
+
}
|
|
@@ -233,9 +233,23 @@ _ts_decorate([
|
|
|
233
233
|
* User companies response
|
|
234
234
|
*/ export class UserCompaniesResponseDto {
|
|
235
235
|
constructor(){
|
|
236
|
+
_define_property(this, "success", void 0);
|
|
237
|
+
_define_property(this, "message", void 0);
|
|
236
238
|
_define_property(this, "data", void 0);
|
|
237
239
|
}
|
|
238
240
|
}
|
|
241
|
+
_ts_decorate([
|
|
242
|
+
ApiProperty({
|
|
243
|
+
example: true
|
|
244
|
+
}),
|
|
245
|
+
_ts_metadata("design:type", Boolean)
|
|
246
|
+
], UserCompaniesResponseDto.prototype, "success", void 0);
|
|
247
|
+
_ts_decorate([
|
|
248
|
+
ApiProperty({
|
|
249
|
+
example: 'User companies retrieved successfully'
|
|
250
|
+
}),
|
|
251
|
+
_ts_metadata("design:type", String)
|
|
252
|
+
], UserCompaniesResponseDto.prototype, "message", void 0);
|
|
239
253
|
_ts_decorate([
|
|
240
254
|
ApiProperty({
|
|
241
255
|
description: 'List of companies the user has access to',
|
|
@@ -265,9 +279,23 @@ _ts_decorate([
|
|
|
265
279
|
* User branches response
|
|
266
280
|
*/ export class UserBranchesResponseDto {
|
|
267
281
|
constructor(){
|
|
282
|
+
_define_property(this, "success", void 0);
|
|
283
|
+
_define_property(this, "message", void 0);
|
|
268
284
|
_define_property(this, "data", void 0);
|
|
269
285
|
}
|
|
270
286
|
}
|
|
287
|
+
_ts_decorate([
|
|
288
|
+
ApiProperty({
|
|
289
|
+
example: true
|
|
290
|
+
}),
|
|
291
|
+
_ts_metadata("design:type", Boolean)
|
|
292
|
+
], UserBranchesResponseDto.prototype, "success", void 0);
|
|
293
|
+
_ts_decorate([
|
|
294
|
+
ApiProperty({
|
|
295
|
+
example: 'User branches retrieved successfully'
|
|
296
|
+
}),
|
|
297
|
+
_ts_metadata("design:type", String)
|
|
298
|
+
], UserBranchesResponseDto.prototype, "message", void 0);
|
|
271
299
|
_ts_decorate([
|
|
272
300
|
ApiProperty({
|
|
273
301
|
description: 'List of branches the user has access to',
|