@flusys/nestjs-auth 2.0.0 → 3.0.0
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 +610 -95
- package/cjs/controllers/authentication.controller.js +2 -173
- package/cjs/controllers/email-verification.controller.js +220 -0
- package/cjs/controllers/index.js +1 -0
- package/cjs/dtos/authentication.dto.js +12 -2
- package/cjs/entities/index.js +16 -17
- package/cjs/entities/pending-registration.entity.js +9 -0
- package/cjs/entities/user-company-permission.entity.js +3 -3
- package/cjs/modules/auth.module.js +33 -24
- package/cjs/services/auth-config.service.js +11 -7
- package/cjs/services/auth-datasource.provider.js +15 -27
- package/cjs/services/auth-email.service.js +8 -33
- package/cjs/services/authentication.service.js +123 -99
- package/cjs/services/user.service.js +28 -83
- package/controllers/authentication.controller.d.ts +2 -10
- package/controllers/email-verification.controller.d.ts +20 -0
- package/controllers/index.d.ts +1 -0
- package/dtos/authentication.dto.d.ts +1 -0
- package/entities/index.d.ts +5 -10
- package/entities/pending-registration.entity.d.ts +1 -0
- package/entities/user-company-permission.entity.d.ts +1 -1
- package/fesm/controllers/authentication.controller.js +3 -174
- package/fesm/controllers/email-verification.controller.js +210 -0
- package/fesm/controllers/index.js +1 -0
- package/fesm/dtos/authentication.dto.js +32 -25
- package/fesm/entities/index.js +17 -9
- package/fesm/entities/pending-registration.entity.js +9 -0
- package/fesm/entities/user-company-permission.entity.js +3 -3
- package/fesm/interfaces/user-enricher.interface.js +2 -24
- package/fesm/modules/auth.module.js +35 -26
- package/fesm/services/auth-config.service.js +11 -7
- package/fesm/services/auth-datasource.provider.js +15 -27
- package/fesm/services/auth-email.service.js +8 -33
- package/fesm/services/authentication.service.js +124 -100
- package/fesm/services/user.service.js +28 -83
- package/interfaces/user-enricher.interface.d.ts +3 -2
- package/modules/auth.module.d.ts +3 -1
- package/package.json +3 -3
- package/services/auth-config.service.d.ts +1 -0
- package/services/auth-datasource.provider.d.ts +1 -0
- package/services/auth-email.service.d.ts +1 -0
- package/services/authentication.service.d.ts +4 -1
- package/services/user.service.d.ts +5 -0
|
@@ -14,6 +14,7 @@ const _common = require("@nestjs/common");
|
|
|
14
14
|
const _jwt = require("@nestjs/jwt");
|
|
15
15
|
const _bcrypt = /*#__PURE__*/ _interop_require_wildcard(require("bcrypt"));
|
|
16
16
|
const _config = require("../config");
|
|
17
|
+
const _userenricherinterface = require("../interfaces/user-enricher.interface");
|
|
17
18
|
const _companybranchentity = require("../entities/company-branch.entity");
|
|
18
19
|
const _companyentity = require("../entities/company.entity");
|
|
19
20
|
const _usercompanypermissionentity = require("../entities/user-company-permission.entity");
|
|
@@ -92,11 +93,14 @@ function _ts_param(paramIndex, decorator) {
|
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
let AuthenticationService = class AuthenticationService {
|
|
95
|
-
|
|
96
|
-
/** Check if company feature is enabled (tenant-aware with global fallback) */ isCompanyFeatureEnabled() {
|
|
96
|
+
isCompanyFeatureEnabled() {
|
|
97
97
|
return this.dataSourceProvider?.isCompanyFeatureEnabled() ?? this.authConfig.isCompanyFeatureEnabled();
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
isEmailVerificationEnabled() {
|
|
100
|
+
const featureEnabled = this.dataSourceProvider?.isEmailVerificationEnabled() ?? this.authConfig.isEmailVerificationEnabled();
|
|
101
|
+
const providerAvailable = this.authEmailService?.isEmailEnabled() ?? false;
|
|
102
|
+
return featureEnabled && providerAvailable;
|
|
103
|
+
}
|
|
100
104
|
async getUserRepository() {
|
|
101
105
|
if (!this.dataSourceProvider) {
|
|
102
106
|
throw new Error('User repository not available');
|
|
@@ -115,10 +119,8 @@ let AuthenticationService = class AuthenticationService {
|
|
|
115
119
|
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
116
120
|
return this.dataSourceProvider.getRepository(_companybranchentity.CompanyBranch);
|
|
117
121
|
}
|
|
118
|
-
// Login
|
|
119
122
|
async login(email, password) {
|
|
120
|
-
|
|
121
|
-
if (await this.authEmailService?.hasPendingRegistration(email)) {
|
|
123
|
+
if (this.isEmailVerificationEnabled() && await this.authEmailService.hasPendingRegistration(email)) {
|
|
122
124
|
return {
|
|
123
125
|
requiresEmailVerification: true,
|
|
124
126
|
email,
|
|
@@ -129,7 +131,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
129
131
|
if (!user.isActive) {
|
|
130
132
|
throw new _common.UnauthorizedException('User account is deactivated');
|
|
131
133
|
}
|
|
132
|
-
if (this.
|
|
134
|
+
if (this.isEmailVerificationEnabled() && !user.emailVerified) {
|
|
133
135
|
return {
|
|
134
136
|
requiresEmailVerification: true,
|
|
135
137
|
email: user.email,
|
|
@@ -141,20 +143,18 @@ let AuthenticationService = class AuthenticationService {
|
|
|
141
143
|
}
|
|
142
144
|
return this.handleCompanyBasedLogin(user);
|
|
143
145
|
}
|
|
144
|
-
|
|
146
|
+
async handleCompanyBasedLogin(user) {
|
|
145
147
|
const permissionRepository = await this.getPermissionRepository();
|
|
146
148
|
const branchRepository = await this.getBranchRepository();
|
|
147
149
|
if (!permissionRepository || !branchRepository) {
|
|
148
150
|
return this.generateLoginResponse(user);
|
|
149
151
|
}
|
|
150
|
-
// Get company permissions
|
|
151
152
|
const companyPermissions = await permissionRepository.find({
|
|
152
153
|
where: {
|
|
153
154
|
userId: user.id,
|
|
154
155
|
permissionType: _enums.PermissionType.COMPANY
|
|
155
156
|
}
|
|
156
157
|
});
|
|
157
|
-
// Load companies
|
|
158
158
|
const companyRepository = await this.getCompanyRepository();
|
|
159
159
|
if (!companyRepository) {
|
|
160
160
|
return this.generateLoginResponse(user);
|
|
@@ -165,12 +165,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
165
165
|
}).andWhere('c.is_active = :active', {
|
|
166
166
|
active: true
|
|
167
167
|
}).getMany() : [];
|
|
168
|
-
// If user has no company assignments yet, return simple login response
|
|
169
|
-
// This allows users to login and be assigned to companies later
|
|
170
168
|
if (companies.length === 0) {
|
|
171
169
|
return this.generateLoginResponse(user);
|
|
172
170
|
}
|
|
173
|
-
// Get branch permissions
|
|
174
171
|
const branchPermissions = await permissionRepository.find({
|
|
175
172
|
where: {
|
|
176
173
|
userId: user.id,
|
|
@@ -183,32 +180,25 @@ let AuthenticationService = class AuthenticationService {
|
|
|
183
180
|
}).andWhere('b.is_active = :active', {
|
|
184
181
|
active: true
|
|
185
182
|
}).getMany() : [];
|
|
186
|
-
// Case 1: Single company, single branch → Direct login
|
|
187
183
|
if (companies.length === 1 && branches.length === 1) {
|
|
188
184
|
return this.generateLoginResponseWithCompany(user, companies[0], branches[0]);
|
|
189
185
|
}
|
|
190
|
-
// Case 2: Multiple options → Selection required (frontend handles UI)
|
|
191
|
-
// Returns all companies with their branches for frontend to display
|
|
192
186
|
return await this.generateCompanySelectionResponse(user, companies, branches);
|
|
193
187
|
}
|
|
194
|
-
|
|
195
|
-
/** Register a new user. If email enabled, creates pending registration. Otherwise creates user directly. */ async register(dto, verifyUrlBase) {
|
|
188
|
+
async register(dto, verifyUrlBase) {
|
|
196
189
|
const userRepository = await this.getUserRepository();
|
|
197
190
|
const existingUser = await userRepository.findOne({
|
|
198
191
|
where: {
|
|
199
192
|
email: dto.email
|
|
200
193
|
}
|
|
201
194
|
});
|
|
202
|
-
// When company feature is enabled and user exists, allow joining/creating company
|
|
203
195
|
if (existingUser && this.isCompanyFeatureEnabled()) {
|
|
204
196
|
return this.handleExistingUserCompanyRegistration(existingUser, dto);
|
|
205
197
|
}
|
|
206
|
-
// User exists but company feature is off - email must be unique
|
|
207
198
|
if (existingUser) {
|
|
208
199
|
throw new _common.BadRequestException('Registration failed due to email exists. Please try again or contact support.');
|
|
209
200
|
}
|
|
210
|
-
|
|
211
|
-
if (this.authEmailService?.isEmailEnabled() && verifyUrlBase) {
|
|
201
|
+
if (this.isEmailVerificationEnabled() && verifyUrlBase) {
|
|
212
202
|
const companyData = this.isCompanyFeatureEnabled() ? {
|
|
213
203
|
companySlug: dto.companySlug,
|
|
214
204
|
branchSlug: dto.branchSlug,
|
|
@@ -222,6 +212,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
222
212
|
phone: dto.phone,
|
|
223
213
|
password: dto.password,
|
|
224
214
|
companyData,
|
|
215
|
+
additionalFields: dto.additionalFields,
|
|
225
216
|
verifyUrlBase
|
|
226
217
|
});
|
|
227
218
|
return {
|
|
@@ -229,10 +220,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
229
220
|
message: result.message
|
|
230
221
|
};
|
|
231
222
|
}
|
|
232
|
-
// No email verification - create user directly
|
|
233
223
|
return this.createUserDirectly(dto);
|
|
234
224
|
}
|
|
235
|
-
|
|
225
|
+
async handleExistingUserCompanyRegistration(existingUser, dto) {
|
|
236
226
|
if (!dto.companySlug && !dto.newCompanyName) {
|
|
237
227
|
throw new _common.BadRequestException('Email already registered. Please login or provide a company to join/create.');
|
|
238
228
|
}
|
|
@@ -241,7 +231,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
241
231
|
if (!permissionRepository || !companyRepository) {
|
|
242
232
|
throw new _common.BadRequestException('Company feature repositories not available');
|
|
243
233
|
}
|
|
244
|
-
// For existing users joining a company, check if already assigned
|
|
245
234
|
if (dto.companySlug) {
|
|
246
235
|
const company = await companyRepository.findOne({
|
|
247
236
|
where: {
|
|
@@ -264,50 +253,92 @@ let AuthenticationService = class AuthenticationService {
|
|
|
264
253
|
}
|
|
265
254
|
return this.processCompanyRegistration(existingUser, dto, true);
|
|
266
255
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
256
|
+
async createUserDirectly(dto) {
|
|
257
|
+
if (!this.dataSourceProvider) {
|
|
258
|
+
throw new _common.BadRequestException('Data source not available');
|
|
259
|
+
}
|
|
260
|
+
const dataSource = await this.dataSourceProvider.getDataSource();
|
|
261
|
+
const queryRunner = dataSource.createQueryRunner();
|
|
262
|
+
await queryRunner.connect();
|
|
263
|
+
await queryRunner.startTransaction();
|
|
264
|
+
try {
|
|
265
|
+
const hashedPassword = await _bcrypt.hash(dto.password, _config.BCRYPT_SALT_ROUNDS);
|
|
266
|
+
const user = queryRunner.manager.create(_userentity.User, {
|
|
267
|
+
name: dto.name,
|
|
268
|
+
email: dto.email,
|
|
269
|
+
phone: dto.phone,
|
|
270
|
+
password: hashedPassword,
|
|
271
|
+
isActive: true,
|
|
272
|
+
emailVerified: false,
|
|
273
|
+
phoneVerified: false
|
|
274
|
+
});
|
|
275
|
+
await queryRunner.manager.save(_userentity.User, user);
|
|
276
|
+
if (this.userEnricher?.onUserCreated) {
|
|
277
|
+
await this.userEnricher.onUserCreated(user.id, dto.additionalFields ?? null, queryRunner);
|
|
278
|
+
}
|
|
279
|
+
await queryRunner.commitTransaction();
|
|
280
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
281
|
+
return this.generateRegistrationResponse(user);
|
|
282
|
+
}
|
|
283
|
+
return this.processCompanyRegistration(user, dto);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
await queryRunner.rollbackTransaction();
|
|
286
|
+
if (error instanceof _common.BadRequestException) {
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
_utils.ErrorHandler.logError(this.logger, error, 'createUserDirectly');
|
|
290
|
+
throw new _common.BadRequestException('Registration failed. Please try again.');
|
|
291
|
+
} finally{
|
|
292
|
+
await queryRunner.release();
|
|
282
293
|
}
|
|
283
|
-
return this.processCompanyRegistration(user, dto);
|
|
284
294
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
295
|
+
async createUserFromPendingRegistration(pending) {
|
|
296
|
+
if (!this.dataSourceProvider) {
|
|
297
|
+
throw new _common.BadRequestException('Data source not available');
|
|
298
|
+
}
|
|
299
|
+
const dataSource = await this.dataSourceProvider.getDataSource();
|
|
300
|
+
const queryRunner = dataSource.createQueryRunner();
|
|
301
|
+
await queryRunner.connect();
|
|
302
|
+
await queryRunner.startTransaction();
|
|
303
|
+
try {
|
|
304
|
+
const existingUser = await queryRunner.manager.findOne(_userentity.User, {
|
|
305
|
+
where: {
|
|
306
|
+
email: pending.email
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
if (existingUser) {
|
|
310
|
+
throw new _common.BadRequestException('This email has already been registered.');
|
|
290
311
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
312
|
+
const user = queryRunner.manager.create(_userentity.User, {
|
|
313
|
+
name: pending.name,
|
|
314
|
+
email: pending.email,
|
|
315
|
+
phone: pending.phone,
|
|
316
|
+
password: pending.passwordHash,
|
|
317
|
+
isActive: true,
|
|
318
|
+
emailVerified: true,
|
|
319
|
+
phoneVerified: false
|
|
320
|
+
});
|
|
321
|
+
await queryRunner.manager.save(_userentity.User, user);
|
|
322
|
+
if (this.userEnricher?.onUserCreated) {
|
|
323
|
+
await this.userEnricher.onUserCreated(user.id, pending.additionalFields ?? null, queryRunner);
|
|
324
|
+
}
|
|
325
|
+
await queryRunner.commitTransaction();
|
|
326
|
+
if (this.isCompanyFeatureEnabled() && pending.companyData) {
|
|
327
|
+
return this.processCompanyRegistration(user, pending.companyData);
|
|
328
|
+
}
|
|
329
|
+
return this.generateRegistrationResponse(user);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
await queryRunner.rollbackTransaction();
|
|
332
|
+
if (error instanceof _common.BadRequestException) {
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
_utils.ErrorHandler.logError(this.logger, error, 'createUserFromPendingRegistration');
|
|
336
|
+
throw new _common.BadRequestException('Registration failed. Please try again.');
|
|
337
|
+
} finally{
|
|
338
|
+
await queryRunner.release();
|
|
307
339
|
}
|
|
308
|
-
return this.generateRegistrationResponse(user);
|
|
309
340
|
}
|
|
310
|
-
|
|
341
|
+
async processCompanyRegistration(user, data, throwOnUnavailable = false) {
|
|
311
342
|
const companyRepository = await this.getCompanyRepository();
|
|
312
343
|
const branchRepository = await this.getBranchRepository();
|
|
313
344
|
const permissionRepository = await this.getPermissionRepository();
|
|
@@ -322,7 +353,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
322
353
|
}
|
|
323
354
|
return this.generateRegistrationResponse(user);
|
|
324
355
|
}
|
|
325
|
-
|
|
356
|
+
async findOrCreateCompanyAndBranch(data, companyRepo, branchRepo) {
|
|
326
357
|
if (data.companySlug) {
|
|
327
358
|
const company = await companyRepo.findOne({
|
|
328
359
|
where: {
|
|
@@ -386,7 +417,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
386
417
|
branch: null
|
|
387
418
|
};
|
|
388
419
|
}
|
|
389
|
-
|
|
420
|
+
async assignUserPermissions(userId, companyId, branchId, permissionRepo) {
|
|
390
421
|
await permissionRepo.save(permissionRepo.create({
|
|
391
422
|
userId,
|
|
392
423
|
permissionType: _enums.PermissionType.COMPANY,
|
|
@@ -400,8 +431,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
400
431
|
}));
|
|
401
432
|
}
|
|
402
433
|
}
|
|
403
|
-
|
|
404
|
-
/** Select company and branch (step 2 of login). Frontend receives all options and user selects both. */ async select(sessionId, companyId, branchId) {
|
|
434
|
+
async select(sessionId, companyId, branchId) {
|
|
405
435
|
this.ensureCompanyFeatureEnabled();
|
|
406
436
|
if (!this.sessionService) {
|
|
407
437
|
throw new _common.BadRequestException('Session service not available');
|
|
@@ -412,11 +442,11 @@ let AuthenticationService = class AuthenticationService {
|
|
|
412
442
|
}
|
|
413
443
|
return this.validateAndLoginWithCompany(session.userId, companyId, branchId);
|
|
414
444
|
}
|
|
415
|
-
|
|
445
|
+
async switchCompany(userId, companyId, branchId) {
|
|
416
446
|
this.ensureCompanyFeatureEnabled();
|
|
417
447
|
return this.validateAndLoginWithCompany(userId, companyId, branchId);
|
|
418
448
|
}
|
|
419
|
-
|
|
449
|
+
async validateAndLoginWithCompany(userId, companyId, branchId) {
|
|
420
450
|
const userRepository = await this.getUserRepository();
|
|
421
451
|
const user = await userRepository.findOne({
|
|
422
452
|
where: {
|
|
@@ -432,7 +462,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
432
462
|
if (!permissionRepository || !companyRepository || !branchRepository) {
|
|
433
463
|
throw new _common.BadRequestException('Repositories not available');
|
|
434
464
|
}
|
|
435
|
-
// Validate company access
|
|
436
465
|
const hasCompanyAccess = await permissionRepository.findOne({
|
|
437
466
|
where: {
|
|
438
467
|
userId,
|
|
@@ -452,7 +481,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
452
481
|
if (!company) {
|
|
453
482
|
throw new _common.UnauthorizedException('Company not found or inactive');
|
|
454
483
|
}
|
|
455
|
-
// Validate branch access
|
|
456
484
|
const hasBranchAccess = await permissionRepository.findOne({
|
|
457
485
|
where: {
|
|
458
486
|
userId,
|
|
@@ -475,8 +503,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
475
503
|
}
|
|
476
504
|
return this.generateLoginResponseWithCompany(user, company, branch);
|
|
477
505
|
}
|
|
478
|
-
|
|
479
|
-
/** Refresh access token (with token rotation). Returns new access token and new refresh token. */ async refreshToken(refreshToken) {
|
|
506
|
+
async refreshToken(refreshToken) {
|
|
480
507
|
try {
|
|
481
508
|
const payload = this.jwtService.verify(refreshToken, {
|
|
482
509
|
secret: this.authConfig.getRefreshTokenSecret()
|
|
@@ -510,7 +537,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
510
537
|
throw new _common.UnauthorizedException('Invalid or expired refresh token');
|
|
511
538
|
}
|
|
512
539
|
}
|
|
513
|
-
|
|
540
|
+
async changePassword(userId, currentPassword, newPassword) {
|
|
514
541
|
const userRepository = await this.getUserRepository();
|
|
515
542
|
const user = await userRepository.findOne({
|
|
516
543
|
where: {
|
|
@@ -524,21 +551,19 @@ let AuthenticationService = class AuthenticationService {
|
|
|
524
551
|
user.password = await _bcrypt.hash(newPassword, _config.BCRYPT_SALT_ROUNDS);
|
|
525
552
|
await userRepository.save(user);
|
|
526
553
|
}
|
|
527
|
-
|
|
554
|
+
async logout(userId) {
|
|
528
555
|
if (!this.cacheManager) {
|
|
529
|
-
// Cache is required for secure logout - tokens cannot be revoked without it
|
|
530
556
|
this.logger.error(`SECURITY: Cache not available for logout (userId: ${userId}). ` + 'Token revocation failed - tokens will remain valid until expiry. ' + 'Configure cache (Redis) to enable proper token revocation.');
|
|
531
557
|
throw new _common.BadRequestException('Logout service temporarily unavailable. Please try again later.');
|
|
532
558
|
}
|
|
533
|
-
const revokedAt = Math.floor(Date.now() / 1000);
|
|
559
|
+
const revokedAt = Math.floor(Date.now() / 1000);
|
|
534
560
|
const cacheKey = `${_config.TOKEN_REVOKED_PREFIX}:${userId}`;
|
|
535
|
-
// TTL matches refresh token expiry (tokens older than this are already expired)
|
|
536
561
|
const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
|
|
537
562
|
const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
|
|
538
563
|
await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
|
|
539
564
|
this.logger.log(`User ${userId} logged out - all tokens revoked`);
|
|
540
565
|
}
|
|
541
|
-
|
|
566
|
+
async isTokenRevoked(userId, tokenIssuedAt) {
|
|
542
567
|
if (!this.cacheManager || !tokenIssuedAt) {
|
|
543
568
|
return false;
|
|
544
569
|
}
|
|
@@ -547,12 +572,11 @@ let AuthenticationService = class AuthenticationService {
|
|
|
547
572
|
if (!revokedAt) {
|
|
548
573
|
return false;
|
|
549
574
|
}
|
|
550
|
-
// Token is revoked if it was issued before the revocation timestamp
|
|
551
575
|
return tokenIssuedAt < revokedAt;
|
|
552
576
|
}
|
|
553
|
-
|
|
577
|
+
parseExpiryToMs(expiry) {
|
|
554
578
|
const match = expiry.match(/^(\d+)([smhd])$/);
|
|
555
|
-
if (!match) return 7 * 24 * 60 * 60 * 1000;
|
|
579
|
+
if (!match) return 7 * 24 * 60 * 60 * 1000;
|
|
556
580
|
const value = parseInt(match[1], 10);
|
|
557
581
|
const unit = match[2];
|
|
558
582
|
switch(unit){
|
|
@@ -568,8 +592,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
568
592
|
return 7 * 24 * 60 * 60 * 1000;
|
|
569
593
|
}
|
|
570
594
|
}
|
|
571
|
-
|
|
572
|
-
/** Get user's companies */ async getUserCompanies(userId) {
|
|
595
|
+
async getUserCompanies(userId) {
|
|
573
596
|
this.ensureCompanyFeatureEnabled();
|
|
574
597
|
const permissionRepository = await this.getPermissionRepository();
|
|
575
598
|
const companyRepository = await this.getCompanyRepository();
|
|
@@ -590,14 +613,13 @@ let AuthenticationService = class AuthenticationService {
|
|
|
590
613
|
active: true
|
|
591
614
|
}).orderBy('c.name', 'ASC').getMany();
|
|
592
615
|
}
|
|
593
|
-
|
|
616
|
+
async getUserBranches(userId, companyId) {
|
|
594
617
|
this.ensureCompanyFeatureEnabled();
|
|
595
618
|
const permissionRepository = await this.getPermissionRepository();
|
|
596
619
|
const branchRepository = await this.getBranchRepository();
|
|
597
620
|
if (!permissionRepository || !branchRepository) {
|
|
598
621
|
throw new _common.BadRequestException('Repositories not available');
|
|
599
622
|
}
|
|
600
|
-
// Verify company access
|
|
601
623
|
const companyPermission = await permissionRepository.findOne({
|
|
602
624
|
where: {
|
|
603
625
|
userId,
|
|
@@ -608,7 +630,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
608
630
|
if (!companyPermission) {
|
|
609
631
|
throw new _common.UnauthorizedException('No access to this company');
|
|
610
632
|
}
|
|
611
|
-
// Get branch permissions
|
|
612
633
|
const branchPermissions = await permissionRepository.find({
|
|
613
634
|
where: {
|
|
614
635
|
userId,
|
|
@@ -625,7 +646,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
625
646
|
active: true
|
|
626
647
|
}).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
|
|
627
648
|
}
|
|
628
|
-
|
|
649
|
+
async getCompanyById(companyId) {
|
|
629
650
|
const companyRepository = await this.getCompanyRepository();
|
|
630
651
|
if (!companyRepository) {
|
|
631
652
|
return null;
|
|
@@ -636,7 +657,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
636
657
|
}
|
|
637
658
|
});
|
|
638
659
|
}
|
|
639
|
-
|
|
660
|
+
async getBranchById(branchId) {
|
|
640
661
|
const branchRepository = await this.getBranchRepository();
|
|
641
662
|
if (!branchRepository) {
|
|
642
663
|
return null;
|
|
@@ -647,7 +668,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
647
668
|
}
|
|
648
669
|
});
|
|
649
670
|
}
|
|
650
|
-
|
|
671
|
+
async getUserInfo(userId, companyId, branchId) {
|
|
651
672
|
const userRepository = await this.getUserRepository();
|
|
652
673
|
const user = await userRepository.findOne({
|
|
653
674
|
where: {
|
|
@@ -673,7 +694,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
673
694
|
}
|
|
674
695
|
return response;
|
|
675
696
|
}
|
|
676
|
-
// Helper Methods
|
|
677
697
|
ensureCompanyFeatureEnabled() {
|
|
678
698
|
if (!this.isCompanyFeatureEnabled()) {
|
|
679
699
|
throw new _common.BadRequestException('Company feature is not enabled');
|
|
@@ -693,8 +713,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
693
713
|
await userRepository.save(user);
|
|
694
714
|
return user;
|
|
695
715
|
}
|
|
696
|
-
|
|
697
|
-
/** Create user info object */ toUserInfo(user) {
|
|
716
|
+
toUserInfo(user) {
|
|
698
717
|
return {
|
|
699
718
|
id: user.id,
|
|
700
719
|
email: user.email,
|
|
@@ -703,7 +722,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
703
722
|
profilePictureId: user.profilePictureId ?? null
|
|
704
723
|
};
|
|
705
724
|
}
|
|
706
|
-
|
|
725
|
+
toCompanyInfo(company) {
|
|
707
726
|
return {
|
|
708
727
|
id: company.id,
|
|
709
728
|
name: company.name,
|
|
@@ -711,7 +730,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
711
730
|
logoId: company.logoId ?? null
|
|
712
731
|
};
|
|
713
732
|
}
|
|
714
|
-
|
|
733
|
+
toBranchInfo(branch) {
|
|
715
734
|
return {
|
|
716
735
|
id: branch.id,
|
|
717
736
|
name: branch.name,
|
|
@@ -719,7 +738,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
719
738
|
logoId: branch.logoId ?? null
|
|
720
739
|
};
|
|
721
740
|
}
|
|
722
|
-
|
|
741
|
+
generateTokens(payload) {
|
|
723
742
|
const accessToken = this.jwtService.sign({
|
|
724
743
|
...payload,
|
|
725
744
|
type: 'access'
|
|
@@ -801,13 +820,14 @@ let AuthenticationService = class AuthenticationService {
|
|
|
801
820
|
};
|
|
802
821
|
}
|
|
803
822
|
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
804
|
-
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService){
|
|
823
|
+
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService, userEnricher){
|
|
805
824
|
_define_property(this, "jwtService", void 0);
|
|
806
825
|
_define_property(this, "authConfig", void 0);
|
|
807
826
|
_define_property(this, "cacheManager", void 0);
|
|
808
827
|
_define_property(this, "dataSourceProvider", void 0);
|
|
809
828
|
_define_property(this, "sessionService", void 0);
|
|
810
829
|
_define_property(this, "authEmailService", void 0);
|
|
830
|
+
_define_property(this, "userEnricher", void 0);
|
|
811
831
|
_define_property(this, "logger", void 0);
|
|
812
832
|
this.jwtService = jwtService;
|
|
813
833
|
this.authConfig = authConfig;
|
|
@@ -815,6 +835,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
815
835
|
this.dataSourceProvider = dataSourceProvider;
|
|
816
836
|
this.sessionService = sessionService;
|
|
817
837
|
this.authEmailService = authEmailService;
|
|
838
|
+
this.userEnricher = userEnricher;
|
|
818
839
|
this.logger = new _common.Logger(AuthenticationService.name);
|
|
819
840
|
}
|
|
820
841
|
};
|
|
@@ -832,6 +853,8 @@ AuthenticationService = _ts_decorate([
|
|
|
832
853
|
_ts_param(4, (0, _common.Inject)(_companyselectionsessionservice.CompanySelectionSessionService)),
|
|
833
854
|
_ts_param(5, (0, _common.Optional)()),
|
|
834
855
|
_ts_param(5, (0, _common.Inject)(_authemailservice.AuthEmailService)),
|
|
856
|
+
_ts_param(6, (0, _common.Optional)()),
|
|
857
|
+
_ts_param(6, (0, _common.Inject)(_config.USER_ENRICHER)),
|
|
835
858
|
_ts_metadata("design:type", Function),
|
|
836
859
|
_ts_metadata("design:paramtypes", [
|
|
837
860
|
typeof _jwt.JwtService === "undefined" ? Object : _jwt.JwtService,
|
|
@@ -839,6 +862,7 @@ AuthenticationService = _ts_decorate([
|
|
|
839
862
|
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
840
863
|
typeof _authdatasourceprovider.AuthDataSourceProvider === "undefined" ? Object : _authdatasourceprovider.AuthDataSourceProvider,
|
|
841
864
|
typeof _companyselectionsessionservice.CompanySelectionSessionService === "undefined" ? Object : _companyselectionsessionservice.CompanySelectionSessionService,
|
|
842
|
-
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService
|
|
865
|
+
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService,
|
|
866
|
+
typeof _userenricherinterface.IUserEnricher === "undefined" ? Object : _userenricherinterface.IUserEnricher
|
|
843
867
|
])
|
|
844
868
|
], AuthenticationService);
|