@flusys/nestjs-auth 1.0.0-rc → 1.0.1
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 +530 -396
- package/cjs/controllers/authentication.controller.js +160 -28
- package/cjs/controllers/user-permission.controller.js +49 -136
- package/cjs/docs/auth-swagger.config.js +14 -7
- package/cjs/dtos/authentication.dto.js +0 -30
- package/cjs/dtos/index.js +0 -1
- package/cjs/entities/user-company-permission.entity.js +3 -3
- package/cjs/interceptors/clear-token.interceptor.js +8 -18
- package/cjs/interceptors/set-token.interceptor.js +8 -55
- package/cjs/interfaces/auth-email-provider.interface.js +1 -1
- package/cjs/modules/auth.module.js +63 -129
- package/cjs/services/auth-config.service.js +6 -29
- package/cjs/services/auth-datasource.provider.js +8 -20
- package/cjs/services/auth-email.service.js +72 -87
- package/cjs/services/authentication.service.js +211 -355
- package/cjs/services/branch.service.js +9 -5
- package/cjs/services/user-permission.service.js +43 -71
- package/cjs/services/user.service.js +18 -47
- package/cjs/strategies/jwt.strategy.js +44 -44
- package/controllers/authentication.controller.d.ts +5 -3
- package/controllers/user-permission.controller.d.ts +5 -4
- package/dtos/authentication.dto.d.ts +0 -4
- package/dtos/index.d.ts +0 -1
- package/entities/index.d.ts +3 -3
- package/entities/user-company-permission.entity.d.ts +1 -1
- package/fesm/controllers/authentication.controller.js +162 -30
- package/fesm/controllers/user-permission.controller.js +50 -137
- package/fesm/docs/auth-swagger.config.js +14 -7
- package/fesm/dtos/authentication.dto.js +0 -30
- package/fesm/dtos/index.js +0 -1
- package/fesm/entities/user-company-permission.entity.js +3 -3
- package/fesm/interceptors/clear-token.interceptor.js +8 -18
- package/fesm/interceptors/set-token.interceptor.js +8 -55
- package/fesm/interfaces/auth-email-provider.interface.js +1 -1
- package/fesm/modules/auth.module.js +63 -129
- package/fesm/services/auth-config.service.js +6 -29
- package/fesm/services/auth-datasource.provider.js +8 -20
- package/fesm/services/auth-email.service.js +72 -87
- package/fesm/services/authentication.service.js +211 -355
- package/fesm/services/branch.service.js +9 -5
- package/fesm/services/user-permission.service.js +44 -72
- package/fesm/services/user.service.js +18 -47
- package/fesm/strategies/jwt.strategy.js +44 -44
- package/interceptors/clear-token.interceptor.d.ts +0 -1
- package/interceptors/set-token.interceptor.d.ts +1 -2
- package/interfaces/authentication.interface.d.ts +0 -4
- package/modules/auth.module.d.ts +6 -2
- package/package.json +3 -3
- package/services/auth-config.service.d.ts +2 -7
- package/services/auth-datasource.provider.d.ts +2 -4
- package/services/auth-email.service.d.ts +7 -4
- package/services/authentication.service.d.ts +14 -8
- package/services/user-permission.service.d.ts +6 -8
- package/services/user.service.d.ts +1 -1
- package/strategies/jwt.strategy.d.ts +4 -1
- package/cjs/dtos/user-company-permission.dto.js +0 -110
- package/cjs/guards/auth-throttler.guard.js +0 -53
- package/dtos/user-company-permission.dto.d.ts +0 -10
- package/fesm/dtos/user-company-permission.dto.js +0 -98
- package/fesm/guards/auth-throttler.guard.js +0 -43
- package/guards/auth-throttler.guard.d.ts +0 -7
|
@@ -9,14 +9,15 @@ Object.defineProperty(exports, "AuthenticationController", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _decorators = require("@flusys/nestjs-shared/decorators");
|
|
12
|
+
const _dtos = require("@flusys/nestjs-shared/dtos");
|
|
12
13
|
const _guards = require("@flusys/nestjs-shared/guards");
|
|
13
14
|
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
14
15
|
const _common = require("@nestjs/common");
|
|
15
16
|
const _swagger = require("@nestjs/swagger");
|
|
16
17
|
const _throttler = require("@nestjs/throttler");
|
|
17
18
|
const _express = require("express");
|
|
19
|
+
const _config = require("../config");
|
|
18
20
|
const _authenticationdto = require("../dtos/authentication.dto");
|
|
19
|
-
const _dtos = require("@flusys/nestjs-shared/dtos");
|
|
20
21
|
const _cleartokeninterceptor = require("../interceptors/clear-token.interceptor");
|
|
21
22
|
const _settokeninterceptor = require("../interceptors/set-token.interceptor");
|
|
22
23
|
const _authconfigservice = require("../services/auth-config.service");
|
|
@@ -54,8 +55,20 @@ let AuthenticationController = class AuthenticationController {
|
|
|
54
55
|
const frontendUrl = this.authConfig?.getFrontendUrl();
|
|
55
56
|
return frontendUrl ? `${frontendUrl}${path}` : `${req.protocol}://${req.get('host')}${path}`;
|
|
56
57
|
}
|
|
58
|
+
get emailService() {
|
|
59
|
+
if (!this.authEmailService) {
|
|
60
|
+
throw new Error('Email service is not configured');
|
|
61
|
+
}
|
|
62
|
+
return this.authEmailService;
|
|
63
|
+
}
|
|
64
|
+
get isEmailEnabled() {
|
|
65
|
+
return !!this.authEmailService;
|
|
66
|
+
}
|
|
57
67
|
async login(loginDto) {
|
|
58
68
|
const result = await this.authService.login(loginDto.email, loginDto.password);
|
|
69
|
+
if ('requiresEmailVerification' in result) {
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
59
72
|
if ('requiresSelection' in result) {
|
|
60
73
|
return result;
|
|
61
74
|
}
|
|
@@ -64,14 +77,15 @@ let AuthenticationController = class AuthenticationController {
|
|
|
64
77
|
/** Register new user. If company feature enabled, can join/create company. */ async register(req, registrationDto) {
|
|
65
78
|
const verifyUrlBase = this.buildAuthUrl(req, '/auth/verify-email');
|
|
66
79
|
const result = await this.authService.register(registrationDto, verifyUrlBase);
|
|
67
|
-
return
|
|
68
|
-
...result,
|
|
69
|
-
companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
|
|
70
|
-
};
|
|
80
|
+
return result;
|
|
71
81
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Refresh access token.
|
|
84
|
+
* - **Browser**: Prefers HTTP-only cookie, falls back to body if cookie missing.
|
|
85
|
+
* - **API/Mobile**: Must send `refreshToken` in request body. Set header `x-client-type: mobile` or `x-client-type: api`.
|
|
86
|
+
*/ async refreshToken(req, refreshTokenDto) {
|
|
87
|
+
const cookieName = this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
|
|
88
|
+
// Always check cookie first, then body - handles Browser, SSR, and Mobile/API
|
|
75
89
|
const refreshToken = req.cookies?.[cookieName] || refreshTokenDto.refreshToken;
|
|
76
90
|
if (!refreshToken) {
|
|
77
91
|
throw new _common.UnauthorizedException('Refresh token is required');
|
|
@@ -96,46 +110,42 @@ let AuthenticationController = class AuthenticationController {
|
|
|
96
110
|
};
|
|
97
111
|
}
|
|
98
112
|
async forgotPassword(req, dto) {
|
|
99
|
-
if (!this.
|
|
113
|
+
if (!this.isEmailEnabled) {
|
|
100
114
|
return {
|
|
101
115
|
success: false,
|
|
102
116
|
message: 'Email service is not configured'
|
|
103
117
|
};
|
|
104
118
|
}
|
|
105
|
-
return this.
|
|
119
|
+
return this.emailService.forgotPassword(dto.email, this.buildAuthUrl(req, '/auth/reset-password'));
|
|
106
120
|
}
|
|
107
121
|
async resetPassword(dto) {
|
|
108
|
-
if (!this.
|
|
122
|
+
if (!this.isEmailEnabled) {
|
|
109
123
|
return {
|
|
110
124
|
success: false,
|
|
111
125
|
message: 'Email service is not configured'
|
|
112
126
|
};
|
|
113
127
|
}
|
|
114
|
-
return this.
|
|
128
|
+
return this.emailService.resetPassword(dto.token, dto.newPassword);
|
|
115
129
|
}
|
|
116
130
|
async resendVerification(req, dto) {
|
|
117
|
-
if (!this.
|
|
131
|
+
if (!this.isEmailEnabled) {
|
|
118
132
|
return {
|
|
119
133
|
success: false,
|
|
120
134
|
message: 'Email service is not configured'
|
|
121
135
|
};
|
|
122
136
|
}
|
|
123
|
-
return this.
|
|
137
|
+
return this.emailService.resendVerificationEmail(dto.email, this.buildAuthUrl(req, '/auth/verify-email'));
|
|
124
138
|
}
|
|
125
139
|
/** Verify email - Verify email using token. Handles both pending registration and existing user verification. */ async verifyEmail(dto) {
|
|
126
|
-
if (!this.
|
|
140
|
+
if (!this.isEmailEnabled) {
|
|
127
141
|
return {
|
|
128
142
|
success: false,
|
|
129
143
|
message: 'Email service is not configured'
|
|
130
144
|
};
|
|
131
145
|
}
|
|
132
|
-
const result = await this.
|
|
146
|
+
const result = await this.emailService.verifyEmail(dto.token);
|
|
133
147
|
if (result.type === 'pending') {
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
...registrationResult,
|
|
137
|
-
companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
|
|
138
|
-
};
|
|
148
|
+
return this.authService.createUserFromPendingRegistration(result.pending);
|
|
139
149
|
}
|
|
140
150
|
return {
|
|
141
151
|
success: true,
|
|
@@ -167,13 +177,102 @@ _ts_decorate([
|
|
|
167
177
|
(0, _swagger.ApiBody)({
|
|
168
178
|
type: _authenticationdto.LoginDto
|
|
169
179
|
}),
|
|
180
|
+
(0, _swagger.ApiExtraModels)(_authenticationdto.LoginResponseDto, _authenticationdto.CompanySelectionResponseDto, _authenticationdto.LoginResponseRequiresEmailVerificationDto),
|
|
170
181
|
(0, _swagger.ApiResponse)({
|
|
171
182
|
status: 200,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
description: 'Login successful, requires company selection, or requires email verification',
|
|
184
|
+
content: {
|
|
185
|
+
'application/json': {
|
|
186
|
+
schema: {
|
|
187
|
+
oneOf: [
|
|
188
|
+
{
|
|
189
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseDto)
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.CompanySelectionResponseDto)
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseRequiresEmailVerificationDto)
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
examples: {
|
|
200
|
+
loginSuccess: {
|
|
201
|
+
summary: 'Login Success',
|
|
202
|
+
description: 'Successful login with tokens (company/branch included when company feature enabled)',
|
|
203
|
+
value: {
|
|
204
|
+
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
205
|
+
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
206
|
+
user: {
|
|
207
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
208
|
+
email: 'john@example.com',
|
|
209
|
+
name: 'John Doe'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
loginSuccessWithCompany: {
|
|
214
|
+
summary: 'Login Success (Company Feature)',
|
|
215
|
+
description: 'Login with company/branch - only when company feature is enabled',
|
|
216
|
+
value: {
|
|
217
|
+
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
218
|
+
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
219
|
+
user: {
|
|
220
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
221
|
+
email: 'john@example.com',
|
|
222
|
+
name: 'John Doe'
|
|
223
|
+
},
|
|
224
|
+
company: {
|
|
225
|
+
id: '550e8400-e29b-41d4-a716-446655440001',
|
|
226
|
+
name: 'Acme Corporation',
|
|
227
|
+
slug: 'acme-corp'
|
|
228
|
+
},
|
|
229
|
+
branch: {
|
|
230
|
+
id: '550e8400-e29b-41d4-a716-446655440002',
|
|
231
|
+
name: 'Main Branch',
|
|
232
|
+
slug: 'main-branch'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
companySelection: {
|
|
237
|
+
summary: 'Company Selection Required (Company Feature)',
|
|
238
|
+
description: 'User has multiple companies/branches - only when company feature is enabled',
|
|
239
|
+
value: {
|
|
240
|
+
requiresSelection: true,
|
|
241
|
+
sessionId: 'sess_abc123def456',
|
|
242
|
+
expiresAt: '2024-12-18T15:30:00.000Z',
|
|
243
|
+
user: {
|
|
244
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
245
|
+
email: 'john@example.com',
|
|
246
|
+
name: 'John Doe'
|
|
247
|
+
},
|
|
248
|
+
companies: [
|
|
249
|
+
{
|
|
250
|
+
id: '550e8400-e29b-41d4-a716-446655440001',
|
|
251
|
+
name: 'Company A',
|
|
252
|
+
slug: 'company-a',
|
|
253
|
+
branches: [
|
|
254
|
+
{
|
|
255
|
+
id: '550e8400-e29b-41d4-a716-446655440010',
|
|
256
|
+
name: 'Branch 1',
|
|
257
|
+
slug: 'branch-1'
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
emailVerification: {
|
|
265
|
+
summary: 'Email Verification Required',
|
|
266
|
+
description: 'User must verify email before logging in',
|
|
267
|
+
value: {
|
|
268
|
+
requiresEmailVerification: true,
|
|
269
|
+
email: 'john@example.com',
|
|
270
|
+
message: 'Please verify your email address before logging in.'
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
177
276
|
}),
|
|
178
277
|
_ts_param(0, (0, _common.Body)()),
|
|
179
278
|
_ts_metadata("design:type", Function),
|
|
@@ -221,10 +320,43 @@ _ts_decorate([
|
|
|
221
320
|
}
|
|
222
321
|
}),
|
|
223
322
|
(0, _swagger.ApiOperation)({
|
|
224
|
-
summary: 'Refresh access token'
|
|
323
|
+
summary: 'Refresh access token',
|
|
324
|
+
description: `
|
|
325
|
+
**Browser clients**: Refresh token is read from HTTP-only cookie (automatically set on login/register).
|
|
326
|
+
Falls back to request body if cookie is not available.
|
|
327
|
+
|
|
328
|
+
**API/Mobile clients**: Must send \`refreshToken\` in request body.
|
|
329
|
+
Set header \`x-client-type: mobile\` or \`x-client-type: api\` to identify as non-browser client.
|
|
330
|
+
|
|
331
|
+
**Client detection**: Uses \`x-client-type\` header first, then falls back to User-Agent detection.
|
|
332
|
+
`
|
|
333
|
+
}),
|
|
334
|
+
(0, _swagger.ApiHeader)({
|
|
335
|
+
name: 'x-client-type',
|
|
336
|
+
required: false,
|
|
337
|
+
description: 'Client type: "browser"/"web" for cookie-based auth, "mobile"/"api" for body-based auth',
|
|
338
|
+
example: 'mobile'
|
|
225
339
|
}),
|
|
226
340
|
(0, _swagger.ApiBody)({
|
|
227
|
-
type: _authenticationdto.RefreshTokenDto
|
|
341
|
+
type: _authenticationdto.RefreshTokenDto,
|
|
342
|
+
description: 'Required for API/Mobile clients. Browser clients prefer HTTP-only cookie with body fallback.'
|
|
343
|
+
}),
|
|
344
|
+
(0, _swagger.ApiResponse)({
|
|
345
|
+
status: 200,
|
|
346
|
+
description: 'New access token',
|
|
347
|
+
schema: {
|
|
348
|
+
type: 'object',
|
|
349
|
+
properties: {
|
|
350
|
+
accessToken: {
|
|
351
|
+
type: 'string',
|
|
352
|
+
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}),
|
|
357
|
+
(0, _swagger.ApiResponse)({
|
|
358
|
+
status: 401,
|
|
359
|
+
description: 'Invalid or missing refresh token'
|
|
228
360
|
}),
|
|
229
361
|
_ts_param(0, (0, _common.Req)()),
|
|
230
362
|
_ts_param(1, (0, _common.Body)()),
|
|
@@ -8,10 +8,11 @@ Object.defineProperty(exports, "UserPermissionController", {
|
|
|
8
8
|
return UserPermissionController;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
11
12
|
const _common = require("@nestjs/common");
|
|
12
13
|
const _swagger = require("@nestjs/swagger");
|
|
13
|
-
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
14
14
|
const _userpermissiondto = require("../dtos/user-permission.dto");
|
|
15
|
+
const _usercompanypermissionentity = require("../entities/user-company-permission.entity");
|
|
15
16
|
const _userpermissionservice = require("../services/user-permission.service");
|
|
16
17
|
function _define_property(obj, key, value) {
|
|
17
18
|
if (key in obj) {
|
|
@@ -42,122 +43,66 @@ function _ts_param(paramIndex, decorator) {
|
|
|
42
43
|
}
|
|
43
44
|
let UserPermissionController = class UserPermissionController {
|
|
44
45
|
async assignUserCompany(dto) {
|
|
45
|
-
|
|
46
|
-
let removedCount = 0;
|
|
47
|
-
for (const item of dto.items){
|
|
48
|
-
if (item.isAdd) {
|
|
49
|
-
await this.userPermissionService.assignUserToCompany({
|
|
50
|
-
userId: dto.userId,
|
|
51
|
-
companyId: item.targetId
|
|
52
|
-
});
|
|
53
|
-
addedCount++;
|
|
54
|
-
} else {
|
|
55
|
-
await this.userPermissionService.revokeCompanyAccess(dto.userId, item.targetId);
|
|
56
|
-
removedCount++;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
success: true,
|
|
61
|
-
message: `Processed ${addedCount} additions and ${removedCount} removals`
|
|
62
|
-
};
|
|
46
|
+
return this.processBatchPermissions(dto.userId, dto.items, _usercompanypermissionentity.PermissionType.COMPANY);
|
|
63
47
|
}
|
|
64
48
|
async getUserCompanies(userId) {
|
|
65
|
-
const permissions = await this.
|
|
66
|
-
const data = permissions.map((permission)=>({
|
|
67
|
-
id: permission.id,
|
|
68
|
-
userId: permission.userId,
|
|
69
|
-
companyId: permission.company?.id || permission.targetId,
|
|
70
|
-
companyName: permission.company?.name || '',
|
|
71
|
-
companySlug: permission.company?.slug || ''
|
|
72
|
-
}));
|
|
49
|
+
const permissions = await this.permissionService.findUserCompanies(userId);
|
|
73
50
|
return {
|
|
74
51
|
success: true,
|
|
75
52
|
message: 'User companies retrieved successfully',
|
|
76
|
-
data
|
|
53
|
+
data: permissions.map((p)=>({
|
|
54
|
+
id: p.id,
|
|
55
|
+
userId: p.userId,
|
|
56
|
+
companyId: p.company?.id || p.targetId,
|
|
57
|
+
companyName: p.company?.name || '',
|
|
58
|
+
companySlug: p.company?.slug || ''
|
|
59
|
+
}))
|
|
77
60
|
};
|
|
78
61
|
}
|
|
79
62
|
async assignUserBranch(dto) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await this.userPermissionService.assignUserToBranch({
|
|
85
|
-
userId: dto.userId,
|
|
86
|
-
branchId: item.targetId
|
|
87
|
-
});
|
|
88
|
-
addedCount++;
|
|
89
|
-
} else {
|
|
90
|
-
await this.userPermissionService.revokeBranchAccess(dto.userId, item.targetId);
|
|
91
|
-
removedCount++;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
63
|
+
return this.processBatchPermissions(dto.userId, dto.items, _usercompanypermissionentity.PermissionType.BRANCH);
|
|
64
|
+
}
|
|
65
|
+
async getUserBranches(userId, companyId) {
|
|
66
|
+
const permissions = await this.permissionService.findUserBranches(userId, companyId);
|
|
94
67
|
return {
|
|
95
68
|
success: true,
|
|
96
|
-
message:
|
|
69
|
+
message: 'User branches retrieved successfully',
|
|
70
|
+
data: permissions.map((p)=>({
|
|
71
|
+
id: p.id,
|
|
72
|
+
userId: p.userId,
|
|
73
|
+
branchId: p.branch?.id || p.targetId,
|
|
74
|
+
branchName: p.branch?.name || '',
|
|
75
|
+
branchSlug: p.branch?.slug || '',
|
|
76
|
+
companyId: p.branch?.companyId || ''
|
|
77
|
+
}))
|
|
97
78
|
};
|
|
98
79
|
}
|
|
99
|
-
async
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
80
|
+
/** Process batch permission assignments/revocations */ async processBatchPermissions(userId, items, type) {
|
|
81
|
+
let added = 0, removed = 0;
|
|
82
|
+
for (const item of items){
|
|
83
|
+
if (item.isAdd) {
|
|
84
|
+
await this.permissionService.assignPermission(userId, item.targetId, type);
|
|
85
|
+
added++;
|
|
86
|
+
} else {
|
|
87
|
+
await this.permissionService.revokePermission(userId, item.targetId, type);
|
|
88
|
+
removed++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
109
91
|
return {
|
|
110
92
|
success: true,
|
|
111
|
-
message:
|
|
112
|
-
data
|
|
93
|
+
message: `Processed ${added} additions and ${removed} removals`
|
|
113
94
|
};
|
|
114
95
|
}
|
|
115
|
-
constructor(
|
|
116
|
-
_define_property(this, "
|
|
117
|
-
this.
|
|
96
|
+
constructor(permissionService){
|
|
97
|
+
_define_property(this, "permissionService", void 0);
|
|
98
|
+
this.permissionService = permissionService;
|
|
118
99
|
}
|
|
119
100
|
};
|
|
120
101
|
_ts_decorate([
|
|
121
102
|
(0, _common.Post)('user-company/assign'),
|
|
122
103
|
(0, _nestjsshared.RequirePermission)(_nestjsshared.USER_PERMISSIONS.UPDATE),
|
|
123
104
|
(0, _swagger.ApiOperation)({
|
|
124
|
-
summary: 'Batch assign/revoke user-company permissions'
|
|
125
|
-
description: `
|
|
126
|
-
Batch operation to assign or revoke user permissions to companies.
|
|
127
|
-
|
|
128
|
-
**Example: Add company permissions**
|
|
129
|
-
\`\`\`json
|
|
130
|
-
{
|
|
131
|
-
"userId": "user-id",
|
|
132
|
-
"items": [
|
|
133
|
-
{ "targetId": "company-id-1", "isAdd": true },
|
|
134
|
-
{ "targetId": "company-id-2", "isAdd": true }
|
|
135
|
-
]
|
|
136
|
-
}
|
|
137
|
-
\`\`\`
|
|
138
|
-
|
|
139
|
-
**Example: Remove company permissions**
|
|
140
|
-
\`\`\`json
|
|
141
|
-
{
|
|
142
|
-
"userId": "user-id",
|
|
143
|
-
"items": [
|
|
144
|
-
{ "targetId": "company-id-1", "isAdd": false },
|
|
145
|
-
{ "targetId": "company-id-2", "isAdd": false }
|
|
146
|
-
]
|
|
147
|
-
}
|
|
148
|
-
\`\`\`
|
|
149
|
-
|
|
150
|
-
**Example: Mix add and remove**
|
|
151
|
-
\`\`\`json
|
|
152
|
-
{
|
|
153
|
-
"userId": "user-id",
|
|
154
|
-
"items": [
|
|
155
|
-
{ "targetId": "company-id-1", "isAdd": true },
|
|
156
|
-
{ "targetId": "company-id-2", "isAdd": false }
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
\`\`\`
|
|
160
|
-
`
|
|
105
|
+
summary: 'Batch assign/revoke user-company permissions'
|
|
161
106
|
}),
|
|
162
107
|
(0, _swagger.ApiResponse)({
|
|
163
108
|
status: 200,
|
|
@@ -177,8 +122,7 @@ _ts_decorate([
|
|
|
177
122
|
(0, _common.Post)('get-user-company'),
|
|
178
123
|
(0, _nestjsshared.RequirePermission)(_nestjsshared.USER_PERMISSIONS.READ),
|
|
179
124
|
(0, _swagger.ApiOperation)({
|
|
180
|
-
summary: 'Get user companies'
|
|
181
|
-
description: 'Returns all companies the user has access to.'
|
|
125
|
+
summary: 'Get user companies'
|
|
182
126
|
}),
|
|
183
127
|
(0, _swagger.ApiBody)({
|
|
184
128
|
schema: {
|
|
@@ -207,43 +151,7 @@ _ts_decorate([
|
|
|
207
151
|
(0, _common.Post)('user-branch/assign'),
|
|
208
152
|
(0, _nestjsshared.RequirePermission)(_nestjsshared.USER_PERMISSIONS.UPDATE),
|
|
209
153
|
(0, _swagger.ApiOperation)({
|
|
210
|
-
summary: 'Batch assign/revoke user-branch permissions'
|
|
211
|
-
description: `
|
|
212
|
-
Batch operation to assign or revoke user permissions to branches.
|
|
213
|
-
|
|
214
|
-
**Example: Add branch permissions**
|
|
215
|
-
\`\`\`json
|
|
216
|
-
{
|
|
217
|
-
"userId": "user-id",
|
|
218
|
-
"items": [
|
|
219
|
-
{ "targetId": "branch-id-1", "isAdd": true },
|
|
220
|
-
{ "targetId": "branch-id-2", "isAdd": true }
|
|
221
|
-
]
|
|
222
|
-
}
|
|
223
|
-
\`\`\`
|
|
224
|
-
|
|
225
|
-
**Example: Remove branch permissions**
|
|
226
|
-
\`\`\`json
|
|
227
|
-
{
|
|
228
|
-
"userId": "user-id",
|
|
229
|
-
"items": [
|
|
230
|
-
{ "targetId": "branch-id-1", "isAdd": false },
|
|
231
|
-
{ "targetId": "branch-id-2", "isAdd": false }
|
|
232
|
-
]
|
|
233
|
-
}
|
|
234
|
-
\`\`\`
|
|
235
|
-
|
|
236
|
-
**Example: Mix add and remove**
|
|
237
|
-
\`\`\`json
|
|
238
|
-
{
|
|
239
|
-
"userId": "user-id",
|
|
240
|
-
"items": [
|
|
241
|
-
{ "targetId": "branch-id-1", "isAdd": true },
|
|
242
|
-
{ "targetId": "branch-id-2", "isAdd": false }
|
|
243
|
-
]
|
|
244
|
-
}
|
|
245
|
-
\`\`\`
|
|
246
|
-
`
|
|
154
|
+
summary: 'Batch assign/revoke user-branch permissions'
|
|
247
155
|
}),
|
|
248
156
|
(0, _swagger.ApiResponse)({
|
|
249
157
|
status: 200,
|
|
@@ -263,14 +171,17 @@ _ts_decorate([
|
|
|
263
171
|
(0, _common.Post)('get-user-branch'),
|
|
264
172
|
(0, _nestjsshared.RequirePermission)(_nestjsshared.USER_PERMISSIONS.READ),
|
|
265
173
|
(0, _swagger.ApiOperation)({
|
|
266
|
-
summary: 'Get user branches'
|
|
267
|
-
description: 'Returns all branches the user has access to.'
|
|
174
|
+
summary: 'Get user branches'
|
|
268
175
|
}),
|
|
269
176
|
(0, _swagger.ApiBody)({
|
|
270
177
|
schema: {
|
|
271
178
|
properties: {
|
|
272
179
|
userId: {
|
|
273
180
|
type: 'string'
|
|
181
|
+
},
|
|
182
|
+
companyId: {
|
|
183
|
+
type: 'string',
|
|
184
|
+
description: 'Optional company ID to filter branches'
|
|
274
185
|
}
|
|
275
186
|
},
|
|
276
187
|
required: [
|
|
@@ -283,8 +194,10 @@ _ts_decorate([
|
|
|
283
194
|
type: _userpermissiondto.UserBranchesResponseDto
|
|
284
195
|
}),
|
|
285
196
|
_ts_param(0, (0, _common.Body)('userId')),
|
|
197
|
+
_ts_param(1, (0, _common.Body)('companyId')),
|
|
286
198
|
_ts_metadata("design:type", Function),
|
|
287
199
|
_ts_metadata("design:paramtypes", [
|
|
200
|
+
String,
|
|
288
201
|
String
|
|
289
202
|
]),
|
|
290
203
|
_ts_metadata("design:returntype", Promise)
|
|
@@ -14,6 +14,16 @@ Object.defineProperty(exports, "authSwaggerConfig", {
|
|
|
14
14
|
'User Permissions',
|
|
15
15
|
'Company Selection'
|
|
16
16
|
];
|
|
17
|
+
/** Examples to exclude when company feature is disabled */ const COMPANY_EXAMPLE_EXCLUSIONS = [
|
|
18
|
+
{
|
|
19
|
+
pathPattern: '/auth/login',
|
|
20
|
+
method: 'post',
|
|
21
|
+
examples: [
|
|
22
|
+
'loginSuccessWithCompany',
|
|
23
|
+
'companySelection'
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
];
|
|
17
27
|
/**
|
|
18
28
|
* Schema properties to exclude when company feature is disabled
|
|
19
29
|
*
|
|
@@ -58,16 +68,14 @@ Object.defineProperty(exports, "authSwaggerConfig", {
|
|
|
58
68
|
schemaName: 'RegistrationResponseDto',
|
|
59
69
|
properties: [
|
|
60
70
|
'company',
|
|
61
|
-
'branch'
|
|
62
|
-
'companyFeatureEnabled'
|
|
71
|
+
'branch'
|
|
63
72
|
]
|
|
64
73
|
},
|
|
65
74
|
{
|
|
66
75
|
schemaName: 'LoginResponseDto',
|
|
67
76
|
properties: [
|
|
68
77
|
'company',
|
|
69
|
-
'branch'
|
|
70
|
-
'companyFeatureEnabled'
|
|
78
|
+
'branch'
|
|
71
79
|
]
|
|
72
80
|
},
|
|
73
81
|
{
|
|
@@ -102,7 +110,6 @@ Object.defineProperty(exports, "authSwaggerConfig", {
|
|
|
102
110
|
'id',
|
|
103
111
|
'name',
|
|
104
112
|
'slug',
|
|
105
|
-
'isActive',
|
|
106
113
|
'logoId'
|
|
107
114
|
]
|
|
108
115
|
},
|
|
@@ -112,7 +119,6 @@ Object.defineProperty(exports, "authSwaggerConfig", {
|
|
|
112
119
|
'id',
|
|
113
120
|
'name',
|
|
114
121
|
'slug',
|
|
115
|
-
'isActive',
|
|
116
122
|
'logoId',
|
|
117
123
|
'branches'
|
|
118
124
|
]
|
|
@@ -404,6 +410,7 @@ POST /auth/login → { accessToken, refreshToken, user }
|
|
|
404
410
|
path: 'api/docs/auth',
|
|
405
411
|
bearerAuth: true,
|
|
406
412
|
excludeTags,
|
|
407
|
-
excludeSchemaProperties: enableCompanyFeature ? undefined : COMPANY_SCHEMA_EXCLUSIONS
|
|
413
|
+
excludeSchemaProperties: enableCompanyFeature ? undefined : COMPANY_SCHEMA_EXCLUSIONS,
|
|
414
|
+
excludeExamples: enableCompanyFeature ? undefined : COMPANY_EXAMPLE_EXCLUSIONS
|
|
408
415
|
};
|
|
409
416
|
}
|
|
@@ -431,7 +431,6 @@ let BranchSelectionInfoDto = class BranchSelectionInfoDto {
|
|
|
431
431
|
_define_property(this, "id", void 0);
|
|
432
432
|
_define_property(this, "name", void 0);
|
|
433
433
|
_define_property(this, "slug", void 0);
|
|
434
|
-
_define_property(this, "isActive", void 0);
|
|
435
434
|
_define_property(this, "logoId", void 0);
|
|
436
435
|
}
|
|
437
436
|
};
|
|
@@ -453,12 +452,6 @@ _ts_decorate([
|
|
|
453
452
|
}),
|
|
454
453
|
_ts_metadata("design:type", String)
|
|
455
454
|
], BranchSelectionInfoDto.prototype, "slug", void 0);
|
|
456
|
-
_ts_decorate([
|
|
457
|
-
(0, _swagger.ApiProperty)({
|
|
458
|
-
example: true
|
|
459
|
-
}),
|
|
460
|
-
_ts_metadata("design:type", Boolean)
|
|
461
|
-
], BranchSelectionInfoDto.prototype, "isActive", void 0);
|
|
462
455
|
_ts_decorate([
|
|
463
456
|
(0, _swagger.ApiPropertyOptional)({
|
|
464
457
|
example: '550e8400-e29b-41d4-a716-446655440077',
|
|
@@ -472,7 +465,6 @@ let CompanyWithBranchesDto = class CompanyWithBranchesDto {
|
|
|
472
465
|
_define_property(this, "id", void 0);
|
|
473
466
|
_define_property(this, "name", void 0);
|
|
474
467
|
_define_property(this, "slug", void 0);
|
|
475
|
-
_define_property(this, "isActive", void 0);
|
|
476
468
|
_define_property(this, "logoId", void 0);
|
|
477
469
|
_define_property(this, "branches", void 0);
|
|
478
470
|
}
|
|
@@ -495,12 +487,6 @@ _ts_decorate([
|
|
|
495
487
|
}),
|
|
496
488
|
_ts_metadata("design:type", String)
|
|
497
489
|
], CompanyWithBranchesDto.prototype, "slug", void 0);
|
|
498
|
-
_ts_decorate([
|
|
499
|
-
(0, _swagger.ApiProperty)({
|
|
500
|
-
example: true
|
|
501
|
-
}),
|
|
502
|
-
_ts_metadata("design:type", Boolean)
|
|
503
|
-
], CompanyWithBranchesDto.prototype, "isActive", void 0);
|
|
504
490
|
_ts_decorate([
|
|
505
491
|
(0, _swagger.ApiPropertyOptional)({
|
|
506
492
|
example: '550e8400-e29b-41d4-a716-446655440088',
|
|
@@ -525,7 +511,6 @@ let LoginResponseDto = class LoginResponseDto {
|
|
|
525
511
|
_define_property(this, "user", void 0);
|
|
526
512
|
_define_property(this, "company", void 0);
|
|
527
513
|
_define_property(this, "branch", void 0);
|
|
528
|
-
_define_property(this, "companyFeatureEnabled", void 0);
|
|
529
514
|
}
|
|
530
515
|
};
|
|
531
516
|
_ts_decorate([
|
|
@@ -561,13 +546,6 @@ _ts_decorate([
|
|
|
561
546
|
}),
|
|
562
547
|
_ts_metadata("design:type", typeof BranchInfoDto === "undefined" ? Object : BranchInfoDto)
|
|
563
548
|
], LoginResponseDto.prototype, "branch", void 0);
|
|
564
|
-
_ts_decorate([
|
|
565
|
-
(0, _swagger.ApiPropertyOptional)({
|
|
566
|
-
example: true,
|
|
567
|
-
description: 'Whether company feature is enabled'
|
|
568
|
-
}),
|
|
569
|
-
_ts_metadata("design:type", Boolean)
|
|
570
|
-
], LoginResponseDto.prototype, "companyFeatureEnabled", void 0);
|
|
571
549
|
let RegistrationResponseDto = class RegistrationResponseDto {
|
|
572
550
|
constructor(){
|
|
573
551
|
_define_property(this, "accessToken", void 0);
|
|
@@ -575,7 +553,6 @@ let RegistrationResponseDto = class RegistrationResponseDto {
|
|
|
575
553
|
_define_property(this, "user", void 0);
|
|
576
554
|
_define_property(this, "company", void 0);
|
|
577
555
|
_define_property(this, "branch", void 0);
|
|
578
|
-
_define_property(this, "companyFeatureEnabled", void 0);
|
|
579
556
|
_define_property(this, "requiresEmailVerification", void 0);
|
|
580
557
|
}
|
|
581
558
|
};
|
|
@@ -612,13 +589,6 @@ _ts_decorate([
|
|
|
612
589
|
}),
|
|
613
590
|
_ts_metadata("design:type", typeof BranchInfoDto === "undefined" ? Object : BranchInfoDto)
|
|
614
591
|
], RegistrationResponseDto.prototype, "branch", void 0);
|
|
615
|
-
_ts_decorate([
|
|
616
|
-
(0, _swagger.ApiPropertyOptional)({
|
|
617
|
-
example: true,
|
|
618
|
-
description: 'Whether company feature is enabled'
|
|
619
|
-
}),
|
|
620
|
-
_ts_metadata("design:type", Boolean)
|
|
621
|
-
], RegistrationResponseDto.prototype, "companyFeatureEnabled", void 0);
|
|
622
592
|
_ts_decorate([
|
|
623
593
|
(0, _swagger.ApiPropertyOptional)({
|
|
624
594
|
example: true,
|
package/cjs/dtos/index.js
CHANGED
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
_export_star(require("./authentication.dto"), exports);
|
|
6
6
|
_export_star(require("./company-branch.dto"), exports);
|
|
7
7
|
_export_star(require("./company.dto"), exports);
|
|
8
|
-
_export_star(require("./user-company-permission.dto"), exports);
|
|
9
8
|
_export_star(require("./user.dto"), exports);
|
|
10
9
|
_export_star(require("./user-permission.dto"), exports);
|
|
11
10
|
function _export_star(from, to) {
|