@flusys/nestjs-auth 1.1.0-beta → 1.1.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 +633 -468
- package/cjs/config/auth.constants.js +8 -0
- package/cjs/controllers/authentication.controller.js +175 -167
- 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/email-verification.controller.js +220 -0
- package/cjs/controllers/index.js +1 -0
- package/cjs/controllers/user-permission.controller.js +82 -154
- package/cjs/controllers/user.controller.js +68 -15
- package/cjs/docs/auth-swagger.config.js +14 -7
- package/cjs/dtos/authentication.dto.js +16 -43
- package/cjs/dtos/index.js +0 -1
- package/cjs/dtos/user-permission.dto.js +28 -0
- package/cjs/dtos/user.dto.js +19 -4
- package/cjs/entities/index.js +16 -17
- package/cjs/entities/user-company-permission.entity.js +3 -9
- package/cjs/interceptors/clear-token.interceptor.js +10 -23
- package/cjs/interceptors/set-token.interceptor.js +15 -55
- package/cjs/interfaces/auth-email-provider.interface.js +1 -1
- package/cjs/modules/auth.module.js +79 -154
- package/cjs/services/auth-config.service.js +33 -35
- package/cjs/services/auth-datasource.provider.js +18 -42
- package/cjs/services/auth-email.service.js +89 -85
- package/cjs/services/authentication.service.js +248 -414
- package/cjs/services/branch.service.js +9 -4
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/user-permission.service.js +43 -73
- package/cjs/services/user.service.js +78 -64
- package/cjs/strategies/jwt.strategy.js +44 -44
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +2 -0
- package/controllers/authentication.controller.d.ts +4 -10
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/email-verification.controller.d.ts +20 -0
- package/controllers/index.d.ts +1 -0
- package/controllers/user-permission.controller.d.ts +5 -4
- package/controllers/user.controller.d.ts +6 -0
- package/dtos/authentication.dto.d.ts +0 -4
- package/dtos/company-branch.dto.d.ts +0 -1
- package/dtos/company.dto.d.ts +0 -1
- package/dtos/index.d.ts +0 -1
- package/dtos/user-permission.dto.d.ts +4 -0
- package/dtos/user.dto.d.ts +1 -3
- package/entities/index.d.ts +5 -10
- package/entities/user-company-permission.entity.d.ts +1 -3
- package/fesm/config/auth.constants.js +6 -13
- package/fesm/controllers/authentication.controller.js +178 -170
- 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/email-verification.controller.js +210 -0
- package/fesm/controllers/index.js +1 -0
- package/fesm/controllers/user-permission.controller.js +84 -156
- package/fesm/controllers/user.controller.js +71 -18
- package/fesm/docs/auth-swagger.config.js +14 -7
- package/fesm/dtos/authentication.dto.js +17 -44
- package/fesm/dtos/index.js +0 -1
- package/fesm/dtos/user-permission.dto.js +28 -0
- package/fesm/dtos/user.dto.js +20 -5
- package/fesm/entities/index.js +17 -9
- package/fesm/entities/user-company-permission.entity.js +3 -9
- package/fesm/interceptors/clear-token.interceptor.js +9 -22
- package/fesm/interceptors/set-token.interceptor.js +14 -54
- package/fesm/interfaces/auth-email-provider.interface.js +1 -1
- package/fesm/modules/auth.module.js +82 -157
- package/fesm/services/auth-config.service.js +34 -36
- package/fesm/services/auth-datasource.provider.js +19 -43
- package/fesm/services/auth-email.service.js +90 -86
- package/fesm/services/authentication.service.js +248 -414
- package/fesm/services/branch.service.js +9 -4
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/user-permission.service.js +44 -74
- package/fesm/services/user.service.js +79 -65
- package/fesm/strategies/jwt.strategy.js +44 -44
- package/fesm/validators/password.validator.js +48 -0
- package/interceptors/clear-token.interceptor.d.ts +0 -1
- package/interceptors/set-token.interceptor.d.ts +1 -1
- package/interfaces/authentication.interface.d.ts +0 -4
- package/interfaces/user-enricher.interface.d.ts +1 -4
- package/modules/auth.module.d.ts +9 -4
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +7 -8
- package/services/auth-datasource.provider.d.ts +3 -4
- package/services/auth-email.service.d.ts +8 -4
- package/services/authentication.service.d.ts +16 -16
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/user-permission.service.d.ts +6 -9
- package/services/user.service.d.ts +3 -0
- package/strategies/jwt.strategy.d.ts +4 -1
- package/validators/password.validator.d.ts +10 -0
- package/cjs/dtos/user-company-permission.dto.js +0 -110
- package/dtos/user-company-permission.dto.d.ts +0 -10
- package/fesm/dtos/user-company-permission.dto.js +0 -98
|
@@ -8,22 +8,20 @@ Object.defineProperty(exports, "AuthenticationService", {
|
|
|
8
8
|
return AuthenticationService;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _utils = require("@flusys/nestjs-shared/utils");
|
|
11
13
|
const _common = require("@nestjs/common");
|
|
12
14
|
const _jwt = require("@nestjs/jwt");
|
|
13
|
-
const _typeorm = require("@nestjs/typeorm");
|
|
14
15
|
const _bcrypt = /*#__PURE__*/ _interop_require_wildcard(require("bcrypt"));
|
|
15
|
-
const _typeorm1 = require("typeorm");
|
|
16
|
-
const _utils = require("@flusys/nestjs-shared/utils");
|
|
17
|
-
const _authconfigservice = require("./auth-config.service");
|
|
18
|
-
const _authdatasourceprovider = require("./auth-datasource.provider");
|
|
19
|
-
const _enums = require("../enums");
|
|
20
16
|
const _config = require("../config");
|
|
21
|
-
const _classes = require("@flusys/nestjs-shared/classes");
|
|
22
|
-
const _authemailservice = require("./auth-email.service");
|
|
23
17
|
const _companybranchentity = require("../entities/company-branch.entity");
|
|
24
18
|
const _companyentity = require("../entities/company.entity");
|
|
25
19
|
const _usercompanypermissionentity = require("../entities/user-company-permission.entity");
|
|
26
20
|
const _userentity = require("../entities/user.entity");
|
|
21
|
+
const _enums = require("../enums");
|
|
22
|
+
const _authconfigservice = require("./auth-config.service");
|
|
23
|
+
const _authdatasourceprovider = require("./auth-datasource.provider");
|
|
24
|
+
const _authemailservice = require("./auth-email.service");
|
|
27
25
|
const _companyselectionsessionservice = require("./company-selection-session.service");
|
|
28
26
|
function _define_property(obj, key, value) {
|
|
29
27
|
if (key in obj) {
|
|
@@ -94,57 +92,61 @@ function _ts_param(paramIndex, decorator) {
|
|
|
94
92
|
};
|
|
95
93
|
}
|
|
96
94
|
let AuthenticationService = class AuthenticationService {
|
|
95
|
+
// Feature Flags
|
|
96
|
+
isCompanyFeatureEnabled() {
|
|
97
|
+
return this.dataSourceProvider?.isCompanyFeatureEnabled() ?? this.authConfig.isCompanyFeatureEnabled();
|
|
98
|
+
}
|
|
99
|
+
isEmailVerificationEnabled() {
|
|
100
|
+
const featureEnabled = this.dataSourceProvider?.isEmailVerificationEnabled() ?? this.authConfig.isEmailVerificationEnabled();
|
|
101
|
+
const providerAvailable = this.authEmailService?.isEmailEnabled() ?? false;
|
|
102
|
+
return featureEnabled && providerAvailable;
|
|
103
|
+
}
|
|
97
104
|
// Repository Getters
|
|
98
105
|
async getUserRepository() {
|
|
99
|
-
if (this.dataSourceProvider) {
|
|
100
|
-
|
|
106
|
+
if (!this.dataSourceProvider) {
|
|
107
|
+
throw new Error('User repository not available');
|
|
101
108
|
}
|
|
102
|
-
|
|
103
|
-
return this.injectedUserRepository;
|
|
104
|
-
}
|
|
105
|
-
throw new Error('User repository not available');
|
|
109
|
+
return this.dataSourceProvider.getRepository(_userentity.User);
|
|
106
110
|
}
|
|
107
111
|
async getPermissionRepository() {
|
|
108
|
-
if (!this.
|
|
109
|
-
|
|
110
|
-
return this.dataSourceProvider.getRepository(_usercompanypermissionentity.UserCompanyPermission);
|
|
111
|
-
}
|
|
112
|
-
return this.injectedPermissionRepository ?? null;
|
|
112
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
113
|
+
return this.dataSourceProvider.getRepository(_usercompanypermissionentity.UserCompanyPermission);
|
|
113
114
|
}
|
|
114
115
|
async getCompanyRepository() {
|
|
115
|
-
if (!this.
|
|
116
|
-
|
|
117
|
-
return this.dataSourceProvider.getRepository(_companyentity.Company);
|
|
118
|
-
}
|
|
119
|
-
return this.injectedCompanyRepository ?? null;
|
|
116
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
117
|
+
return this.dataSourceProvider.getRepository(_companyentity.Company);
|
|
120
118
|
}
|
|
121
119
|
async getBranchRepository() {
|
|
122
|
-
if (!this.
|
|
123
|
-
|
|
124
|
-
return this.dataSourceProvider.getRepository(_companybranchentity.CompanyBranch);
|
|
125
|
-
}
|
|
126
|
-
return this.injectedBranchRepository ?? null;
|
|
120
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
121
|
+
return this.dataSourceProvider.getRepository(_companybranchentity.CompanyBranch);
|
|
127
122
|
}
|
|
128
123
|
// Login
|
|
129
|
-
|
|
124
|
+
async login(email, password) {
|
|
125
|
+
// Check for pending registration first (user registered but hasn't verified email yet)
|
|
126
|
+
if (this.isEmailVerificationEnabled() && await this.authEmailService.hasPendingRegistration(email)) {
|
|
127
|
+
return {
|
|
128
|
+
requiresEmailVerification: true,
|
|
129
|
+
email,
|
|
130
|
+
message: 'Please verify your email address to complete registration.'
|
|
131
|
+
};
|
|
132
|
+
}
|
|
130
133
|
const user = await this.validateUser(email, password);
|
|
131
134
|
if (!user.isActive) {
|
|
132
135
|
throw new _common.UnauthorizedException('User account is deactivated');
|
|
133
136
|
}
|
|
134
|
-
|
|
135
|
-
if (this.authEmailService?.isEmailEnabled() && !user.emailVerified) {
|
|
137
|
+
if (this.isEmailVerificationEnabled() && !user.emailVerified) {
|
|
136
138
|
return {
|
|
137
139
|
requiresEmailVerification: true,
|
|
138
140
|
email: user.email,
|
|
139
141
|
message: 'Please verify your email address before logging in.'
|
|
140
142
|
};
|
|
141
143
|
}
|
|
142
|
-
if (!this.
|
|
144
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
143
145
|
return this.generateLoginResponse(user);
|
|
144
146
|
}
|
|
145
147
|
return this.handleCompanyBasedLogin(user);
|
|
146
148
|
}
|
|
147
|
-
|
|
149
|
+
async handleCompanyBasedLogin(user) {
|
|
148
150
|
const permissionRepository = await this.getPermissionRepository();
|
|
149
151
|
const branchRepository = await this.getBranchRepository();
|
|
150
152
|
if (!permissionRepository || !branchRepository) {
|
|
@@ -171,7 +173,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
171
173
|
// If user has no company assignments yet, return simple login response
|
|
172
174
|
// This allows users to login and be assigned to companies later
|
|
173
175
|
if (companies.length === 0) {
|
|
174
|
-
return this.generateLoginResponse(user
|
|
176
|
+
return this.generateLoginResponse(user);
|
|
175
177
|
}
|
|
176
178
|
// Get branch permissions
|
|
177
179
|
const branchPermissions = await permissionRepository.find({
|
|
@@ -195,19 +197,24 @@ let AuthenticationService = class AuthenticationService {
|
|
|
195
197
|
return await this.generateCompanySelectionResponse(user, companies, branches);
|
|
196
198
|
}
|
|
197
199
|
// Registration
|
|
198
|
-
|
|
200
|
+
async register(dto, verifyUrlBase) {
|
|
199
201
|
const userRepository = await this.getUserRepository();
|
|
200
202
|
const existingUser = await userRepository.findOne({
|
|
201
203
|
where: {
|
|
202
204
|
email: dto.email
|
|
203
205
|
}
|
|
204
206
|
});
|
|
207
|
+
// When company feature is enabled and user exists, allow joining/creating company
|
|
208
|
+
if (existingUser && this.isCompanyFeatureEnabled()) {
|
|
209
|
+
return this.handleExistingUserCompanyRegistration(existingUser, dto);
|
|
210
|
+
}
|
|
211
|
+
// User exists but company feature is off - email must be unique
|
|
205
212
|
if (existingUser) {
|
|
206
|
-
throw new _common.BadRequestException('Registration failed. Please try again or contact support.');
|
|
213
|
+
throw new _common.BadRequestException('Registration failed due to email exists. Please try again or contact support.');
|
|
207
214
|
}
|
|
208
215
|
// If email verification is enabled, create pending registration instead of user
|
|
209
|
-
if (this.
|
|
210
|
-
const companyData = this.
|
|
216
|
+
if (this.isEmailVerificationEnabled() && verifyUrlBase) {
|
|
217
|
+
const companyData = this.isCompanyFeatureEnabled() ? {
|
|
211
218
|
companySlug: dto.companySlug,
|
|
212
219
|
branchSlug: dto.branchSlug,
|
|
213
220
|
newCompanyName: dto.newCompanyName,
|
|
@@ -230,7 +237,39 @@ let AuthenticationService = class AuthenticationService {
|
|
|
230
237
|
// No email verification - create user directly
|
|
231
238
|
return this.createUserDirectly(dto);
|
|
232
239
|
}
|
|
233
|
-
|
|
240
|
+
async handleExistingUserCompanyRegistration(existingUser, dto) {
|
|
241
|
+
if (!dto.companySlug && !dto.newCompanyName) {
|
|
242
|
+
throw new _common.BadRequestException('Email already registered. Please login or provide a company to join/create.');
|
|
243
|
+
}
|
|
244
|
+
const permissionRepository = await this.getPermissionRepository();
|
|
245
|
+
const companyRepository = await this.getCompanyRepository();
|
|
246
|
+
if (!permissionRepository || !companyRepository) {
|
|
247
|
+
throw new _common.BadRequestException('Company feature repositories not available');
|
|
248
|
+
}
|
|
249
|
+
// For existing users joining a company, check if already assigned
|
|
250
|
+
if (dto.companySlug) {
|
|
251
|
+
const company = await companyRepository.findOne({
|
|
252
|
+
where: {
|
|
253
|
+
slug: dto.companySlug,
|
|
254
|
+
isActive: true
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
if (company) {
|
|
258
|
+
const existingPermission = await permissionRepository.findOne({
|
|
259
|
+
where: {
|
|
260
|
+
userId: existingUser.id,
|
|
261
|
+
permissionType: _enums.PermissionType.COMPANY,
|
|
262
|
+
targetId: company.id
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
if (existingPermission) {
|
|
266
|
+
throw new _common.BadRequestException('You are already assigned to this company. Please login.');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return this.processCompanyRegistration(existingUser, dto, true);
|
|
271
|
+
}
|
|
272
|
+
async createUserDirectly(dto) {
|
|
234
273
|
const userRepository = await this.getUserRepository();
|
|
235
274
|
const hashedPassword = await _bcrypt.hash(dto.password, _config.BCRYPT_SALT_ROUNDS);
|
|
236
275
|
const user = userRepository.create({
|
|
@@ -243,14 +282,13 @@ let AuthenticationService = class AuthenticationService {
|
|
|
243
282
|
phoneVerified: false
|
|
244
283
|
});
|
|
245
284
|
await userRepository.save(user);
|
|
246
|
-
if (!this.
|
|
247
|
-
return this.generateRegistrationResponse(user
|
|
285
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
286
|
+
return this.generateRegistrationResponse(user);
|
|
248
287
|
}
|
|
249
|
-
return this.
|
|
288
|
+
return this.processCompanyRegistration(user, dto);
|
|
250
289
|
}
|
|
251
|
-
|
|
290
|
+
async createUserFromPendingRegistration(pending) {
|
|
252
291
|
const userRepository = await this.getUserRepository();
|
|
253
|
-
// Check if user already exists (race condition protection)
|
|
254
292
|
const existingUser = await userRepository.findOne({
|
|
255
293
|
where: {
|
|
256
294
|
email: pending.email
|
|
@@ -259,7 +297,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
259
297
|
if (existingUser) {
|
|
260
298
|
throw new _common.BadRequestException('This email has already been registered.');
|
|
261
299
|
}
|
|
262
|
-
// Create user with verified email
|
|
263
300
|
const user = userRepository.create({
|
|
264
301
|
name: pending.name,
|
|
265
302
|
email: pending.email,
|
|
@@ -270,110 +307,106 @@ let AuthenticationService = class AuthenticationService {
|
|
|
270
307
|
phoneVerified: false
|
|
271
308
|
});
|
|
272
309
|
await userRepository.save(user);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return this.handleCompanyRegistrationFromPending(user, pending.companyData);
|
|
310
|
+
if (this.isCompanyFeatureEnabled() && pending.companyData) {
|
|
311
|
+
return this.processCompanyRegistration(user, pending.companyData);
|
|
276
312
|
}
|
|
277
|
-
return this.generateRegistrationResponse(user
|
|
278
|
-
}
|
|
279
|
-
/** Handle company registration from pending registration data */ async handleCompanyRegistrationFromPending(user, companyData) {
|
|
280
|
-
return this.processCompanyRegistration(user, companyData, false);
|
|
313
|
+
return this.generateRegistrationResponse(user);
|
|
281
314
|
}
|
|
282
|
-
|
|
283
|
-
return this.processCompanyRegistration(user, dto, requiresEmailVerification);
|
|
284
|
-
}
|
|
285
|
-
/** Shared logic for company registration (join existing or create new) */ async processCompanyRegistration(user, data, requiresEmailVerification) {
|
|
315
|
+
async processCompanyRegistration(user, data, throwOnUnavailable = false) {
|
|
286
316
|
const companyRepository = await this.getCompanyRepository();
|
|
287
317
|
const branchRepository = await this.getBranchRepository();
|
|
288
318
|
const permissionRepository = await this.getPermissionRepository();
|
|
289
319
|
if (!companyRepository || !branchRepository || !permissionRepository) {
|
|
290
|
-
|
|
320
|
+
if (throwOnUnavailable) throw new _common.BadRequestException('Company feature repositories not available');
|
|
321
|
+
return this.generateRegistrationResponse(user);
|
|
322
|
+
}
|
|
323
|
+
const { company, branch } = await this.findOrCreateCompanyAndBranch(data, companyRepository, branchRepository);
|
|
324
|
+
if (company) {
|
|
325
|
+
await this.assignUserPermissions(user.id, company.id, branch?.id, permissionRepository);
|
|
326
|
+
return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined);
|
|
291
327
|
}
|
|
292
|
-
|
|
293
|
-
|
|
328
|
+
return this.generateRegistrationResponse(user);
|
|
329
|
+
}
|
|
330
|
+
async findOrCreateCompanyAndBranch(data, companyRepo, branchRepo) {
|
|
294
331
|
if (data.companySlug) {
|
|
295
|
-
company = await
|
|
332
|
+
const company = await companyRepo.findOne({
|
|
296
333
|
where: {
|
|
297
334
|
slug: data.companySlug,
|
|
298
335
|
isActive: true
|
|
299
336
|
}
|
|
300
337
|
});
|
|
301
|
-
if (!company)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
slug: data.branchSlug,
|
|
308
|
-
companyId: company.id,
|
|
309
|
-
isActive: true
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
if (!branch) {
|
|
313
|
-
throw new _common.BadRequestException('Branch not found or inactive');
|
|
338
|
+
if (!company) throw new _common.BadRequestException('Company not found or inactive');
|
|
339
|
+
const branch = data.branchSlug ? await branchRepo.findOne({
|
|
340
|
+
where: {
|
|
341
|
+
slug: data.branchSlug,
|
|
342
|
+
companyId: company.id,
|
|
343
|
+
isActive: true
|
|
314
344
|
}
|
|
315
|
-
}
|
|
316
|
-
branch = await branchRepository.findOne({
|
|
317
|
-
where: {
|
|
318
|
-
companyId: company.id,
|
|
319
|
-
isActive: true
|
|
320
|
-
},
|
|
321
|
-
order: {
|
|
322
|
-
serial: 'ASC',
|
|
323
|
-
createdAt: 'ASC'
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
} else if (data.newCompanyName) {
|
|
328
|
-
const slug = this.generateSlug(data.newCompanyName);
|
|
329
|
-
const existingCompany = await companyRepository.findOne({
|
|
345
|
+
}) : await branchRepo.findOne({
|
|
330
346
|
where: {
|
|
331
|
-
|
|
347
|
+
companyId: company.id,
|
|
348
|
+
isActive: true
|
|
349
|
+
},
|
|
350
|
+
order: {
|
|
351
|
+
serial: 'ASC',
|
|
352
|
+
createdAt: 'ASC'
|
|
332
353
|
}
|
|
333
354
|
});
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
355
|
+
if (data.branchSlug && !branch) throw new _common.BadRequestException('Branch not found or inactive');
|
|
356
|
+
return {
|
|
357
|
+
company,
|
|
358
|
+
branch
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
if (data.newCompanyName) {
|
|
362
|
+
const slug = await (0, _utils.generateUniqueSlug)(data.newCompanyName, async (baseSlug)=>{
|
|
363
|
+
const rows = await companyRepo.createQueryBuilder('c').select('c.slug').where('c.slug = :base OR c.slug LIKE :pattern', {
|
|
364
|
+
base: baseSlug,
|
|
365
|
+
pattern: `${baseSlug}-%`
|
|
366
|
+
}).getMany();
|
|
367
|
+
return rows.map((r)=>r.slug);
|
|
368
|
+
});
|
|
369
|
+
const company = companyRepo.create({
|
|
338
370
|
name: data.newCompanyName,
|
|
339
371
|
slug,
|
|
340
372
|
phone: data.newCompanyPhone,
|
|
341
373
|
address: data.newCompanyAddress,
|
|
342
374
|
isActive: true
|
|
343
375
|
});
|
|
344
|
-
await
|
|
345
|
-
branch =
|
|
376
|
+
await companyRepo.save(company);
|
|
377
|
+
const branch = branchRepo.create({
|
|
346
378
|
name: 'Main Branch',
|
|
347
379
|
slug: 'main-branch',
|
|
348
380
|
companyId: company.id,
|
|
349
381
|
isActive: true
|
|
350
382
|
});
|
|
351
|
-
await
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
permissionType: _enums.PermissionType.COMPANY,
|
|
357
|
-
targetId: company.id
|
|
358
|
-
});
|
|
359
|
-
await permissionRepository.save(companyPermission);
|
|
360
|
-
if (branch) {
|
|
361
|
-
const branchPermission = permissionRepository.create({
|
|
362
|
-
userId: user.id,
|
|
363
|
-
permissionType: _enums.PermissionType.BRANCH,
|
|
364
|
-
targetId: branch.id
|
|
365
|
-
});
|
|
366
|
-
await permissionRepository.save(branchPermission);
|
|
367
|
-
}
|
|
368
|
-
return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined, requiresEmailVerification);
|
|
383
|
+
await branchRepo.save(branch);
|
|
384
|
+
return {
|
|
385
|
+
company,
|
|
386
|
+
branch
|
|
387
|
+
};
|
|
369
388
|
}
|
|
370
|
-
return
|
|
389
|
+
return {
|
|
390
|
+
company: null,
|
|
391
|
+
branch: null
|
|
392
|
+
};
|
|
371
393
|
}
|
|
372
|
-
|
|
373
|
-
|
|
394
|
+
async assignUserPermissions(userId, companyId, branchId, permissionRepo) {
|
|
395
|
+
await permissionRepo.save(permissionRepo.create({
|
|
396
|
+
userId,
|
|
397
|
+
permissionType: _enums.PermissionType.COMPANY,
|
|
398
|
+
targetId: companyId
|
|
399
|
+
}));
|
|
400
|
+
if (branchId) {
|
|
401
|
+
await permissionRepo.save(permissionRepo.create({
|
|
402
|
+
userId,
|
|
403
|
+
permissionType: _enums.PermissionType.BRANCH,
|
|
404
|
+
targetId: branchId
|
|
405
|
+
}));
|
|
406
|
+
}
|
|
374
407
|
}
|
|
375
408
|
// Company/Branch Selection
|
|
376
|
-
|
|
409
|
+
async select(sessionId, companyId, branchId) {
|
|
377
410
|
this.ensureCompanyFeatureEnabled();
|
|
378
411
|
if (!this.sessionService) {
|
|
379
412
|
throw new _common.BadRequestException('Session service not available');
|
|
@@ -382,66 +415,13 @@ let AuthenticationService = class AuthenticationService {
|
|
|
382
415
|
if (!session) {
|
|
383
416
|
throw new _common.UnauthorizedException('Invalid or expired session');
|
|
384
417
|
}
|
|
385
|
-
|
|
386
|
-
const user = await userRepository.findOne({
|
|
387
|
-
where: {
|
|
388
|
-
id: session.userId
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
if (!user) {
|
|
392
|
-
throw new _common.NotFoundException('User not found');
|
|
393
|
-
}
|
|
394
|
-
const permissionRepository = await this.getPermissionRepository();
|
|
395
|
-
const companyRepository = await this.getCompanyRepository();
|
|
396
|
-
const branchRepository = await this.getBranchRepository();
|
|
397
|
-
if (!permissionRepository || !companyRepository || !branchRepository) {
|
|
398
|
-
throw new _common.BadRequestException('Repositories not available');
|
|
399
|
-
}
|
|
400
|
-
// Validate company access
|
|
401
|
-
const companyPermission = await permissionRepository.findOne({
|
|
402
|
-
where: {
|
|
403
|
-
userId: user.id,
|
|
404
|
-
permissionType: _enums.PermissionType.COMPANY,
|
|
405
|
-
targetId: companyId
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
if (!companyPermission) {
|
|
409
|
-
throw new _common.UnauthorizedException('No access to this company');
|
|
410
|
-
}
|
|
411
|
-
const company = await companyRepository.findOne({
|
|
412
|
-
where: {
|
|
413
|
-
id: companyId,
|
|
414
|
-
isActive: true
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
if (!company) {
|
|
418
|
-
throw new _common.UnauthorizedException('Company not found or inactive');
|
|
419
|
-
}
|
|
420
|
-
// Validate branch access
|
|
421
|
-
const branchPermission = await permissionRepository.findOne({
|
|
422
|
-
where: {
|
|
423
|
-
userId: user.id,
|
|
424
|
-
permissionType: _enums.PermissionType.BRANCH,
|
|
425
|
-
targetId: branchId
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
if (!branchPermission) {
|
|
429
|
-
throw new _common.UnauthorizedException('No access to this branch');
|
|
430
|
-
}
|
|
431
|
-
const branch = await branchRepository.findOne({
|
|
432
|
-
where: {
|
|
433
|
-
id: branchId,
|
|
434
|
-
companyId,
|
|
435
|
-
isActive: true
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
if (!branch) {
|
|
439
|
-
throw new _common.UnauthorizedException('Branch not found or inactive');
|
|
440
|
-
}
|
|
441
|
-
return this.generateLoginResponseWithCompany(user, company, branch);
|
|
418
|
+
return this.validateAndLoginWithCompany(session.userId, companyId, branchId);
|
|
442
419
|
}
|
|
443
|
-
|
|
420
|
+
async switchCompany(userId, companyId, branchId) {
|
|
444
421
|
this.ensureCompanyFeatureEnabled();
|
|
422
|
+
return this.validateAndLoginWithCompany(userId, companyId, branchId);
|
|
423
|
+
}
|
|
424
|
+
async validateAndLoginWithCompany(userId, companyId, branchId) {
|
|
445
425
|
const userRepository = await this.getUserRepository();
|
|
446
426
|
const user = await userRepository.findOne({
|
|
447
427
|
where: {
|
|
@@ -458,14 +438,14 @@ let AuthenticationService = class AuthenticationService {
|
|
|
458
438
|
throw new _common.BadRequestException('Repositories not available');
|
|
459
439
|
}
|
|
460
440
|
// Validate company access
|
|
461
|
-
const
|
|
441
|
+
const hasCompanyAccess = await permissionRepository.findOne({
|
|
462
442
|
where: {
|
|
463
443
|
userId,
|
|
464
444
|
permissionType: _enums.PermissionType.COMPANY,
|
|
465
445
|
targetId: companyId
|
|
466
446
|
}
|
|
467
447
|
});
|
|
468
|
-
if (!
|
|
448
|
+
if (!hasCompanyAccess) {
|
|
469
449
|
throw new _common.UnauthorizedException('No access to this company');
|
|
470
450
|
}
|
|
471
451
|
const company = await companyRepository.findOne({
|
|
@@ -477,14 +457,15 @@ let AuthenticationService = class AuthenticationService {
|
|
|
477
457
|
if (!company) {
|
|
478
458
|
throw new _common.UnauthorizedException('Company not found or inactive');
|
|
479
459
|
}
|
|
480
|
-
|
|
460
|
+
// Validate branch access
|
|
461
|
+
const hasBranchAccess = await permissionRepository.findOne({
|
|
481
462
|
where: {
|
|
482
463
|
userId,
|
|
483
464
|
permissionType: _enums.PermissionType.BRANCH,
|
|
484
465
|
targetId: branchId
|
|
485
466
|
}
|
|
486
467
|
});
|
|
487
|
-
if (!
|
|
468
|
+
if (!hasBranchAccess) {
|
|
488
469
|
throw new _common.UnauthorizedException('No access to this branch');
|
|
489
470
|
}
|
|
490
471
|
const branch = await branchRepository.findOne({
|
|
@@ -500,11 +481,14 @@ let AuthenticationService = class AuthenticationService {
|
|
|
500
481
|
return this.generateLoginResponseWithCompany(user, company, branch);
|
|
501
482
|
}
|
|
502
483
|
// Token Management
|
|
503
|
-
|
|
484
|
+
async refreshToken(refreshToken) {
|
|
504
485
|
try {
|
|
505
486
|
const payload = this.jwtService.verify(refreshToken, {
|
|
506
487
|
secret: this.authConfig.getRefreshTokenSecret()
|
|
507
488
|
});
|
|
489
|
+
if (await this.isTokenRevoked(payload.id, payload.iat)) {
|
|
490
|
+
throw new _common.UnauthorizedException('Token has been revoked');
|
|
491
|
+
}
|
|
508
492
|
const userRepository = await this.getUserRepository();
|
|
509
493
|
const user = await userRepository.findOne({
|
|
510
494
|
where: {
|
|
@@ -514,7 +498,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
514
498
|
if (!user || !user.isActive) {
|
|
515
499
|
throw new _common.UnauthorizedException('Invalid refresh token');
|
|
516
500
|
}
|
|
517
|
-
|
|
501
|
+
return this.generateTokens({
|
|
518
502
|
id: user.id,
|
|
519
503
|
email: user.email,
|
|
520
504
|
type: 'access',
|
|
@@ -524,69 +508,32 @@ let AuthenticationService = class AuthenticationService {
|
|
|
524
508
|
},
|
|
525
509
|
...payload.branchId && {
|
|
526
510
|
branchId: payload.branchId
|
|
527
|
-
},
|
|
528
|
-
...payload.companyLogoId && {
|
|
529
|
-
companyLogoId: payload.companyLogoId
|
|
530
|
-
},
|
|
531
|
-
...payload.branchLogoId && {
|
|
532
|
-
branchLogoId: payload.branchLogoId
|
|
533
511
|
}
|
|
534
|
-
};
|
|
535
|
-
const refreshPayload = {
|
|
536
|
-
id: user.id,
|
|
537
|
-
email: user.email,
|
|
538
|
-
type: 'refresh',
|
|
539
|
-
profilePictureId: user.profilePictureId ?? undefined,
|
|
540
|
-
...payload.companyId && {
|
|
541
|
-
companyId: payload.companyId
|
|
542
|
-
},
|
|
543
|
-
...payload.branchId && {
|
|
544
|
-
branchId: payload.branchId
|
|
545
|
-
},
|
|
546
|
-
...payload.companyLogoId && {
|
|
547
|
-
companyLogoId: payload.companyLogoId
|
|
548
|
-
},
|
|
549
|
-
...payload.branchLogoId && {
|
|
550
|
-
branchLogoId: payload.branchLogoId
|
|
551
|
-
}
|
|
552
|
-
};
|
|
553
|
-
return {
|
|
554
|
-
accessToken: this.jwtService.sign(accessPayload, {
|
|
555
|
-
secret: this.authConfig.getJwtSecret(),
|
|
556
|
-
expiresIn: this.authConfig.getJwtExpiration()
|
|
557
|
-
}),
|
|
558
|
-
refreshToken: this.jwtService.sign(refreshPayload, {
|
|
559
|
-
secret: this.authConfig.getRefreshTokenSecret(),
|
|
560
|
-
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
561
|
-
})
|
|
562
|
-
};
|
|
512
|
+
});
|
|
563
513
|
} catch (error) {
|
|
564
|
-
// Log error details for debugging (not exposed to client)
|
|
565
514
|
_utils.ErrorHandler.logError(this.logger, error, 'refreshToken');
|
|
566
515
|
throw new _common.UnauthorizedException('Invalid or expired refresh token');
|
|
567
516
|
}
|
|
568
517
|
}
|
|
569
|
-
|
|
518
|
+
async changePassword(userId, currentPassword, newPassword) {
|
|
570
519
|
const userRepository = await this.getUserRepository();
|
|
571
520
|
const user = await userRepository.findOne({
|
|
572
521
|
where: {
|
|
573
522
|
id: userId
|
|
574
523
|
}
|
|
575
524
|
});
|
|
576
|
-
if (!user)
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
const isPasswordValid = await _bcrypt.compare(currentPassword, user.password || '');
|
|
580
|
-
if (!isPasswordValid) {
|
|
525
|
+
if (!user) throw new _common.UnauthorizedException('User not found');
|
|
526
|
+
if (!await _bcrypt.compare(currentPassword, user.password || '')) {
|
|
581
527
|
throw new _common.UnauthorizedException('Current password is incorrect');
|
|
582
528
|
}
|
|
583
529
|
user.password = await _bcrypt.hash(newPassword, _config.BCRYPT_SALT_ROUNDS);
|
|
584
530
|
await userRepository.save(user);
|
|
585
531
|
}
|
|
586
|
-
|
|
532
|
+
async logout(userId) {
|
|
587
533
|
if (!this.cacheManager) {
|
|
588
|
-
// Cache
|
|
589
|
-
|
|
534
|
+
// Cache is required for secure logout - tokens cannot be revoked without it
|
|
535
|
+
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.');
|
|
536
|
+
throw new _common.BadRequestException('Logout service temporarily unavailable. Please try again later.');
|
|
590
537
|
}
|
|
591
538
|
const revokedAt = Math.floor(Date.now() / 1000); // Unix timestamp in seconds
|
|
592
539
|
const cacheKey = `${_config.TOKEN_REVOKED_PREFIX}:${userId}`;
|
|
@@ -594,8 +541,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
594
541
|
const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
|
|
595
542
|
const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
|
|
596
543
|
await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
|
|
544
|
+
this.logger.log(`User ${userId} logged out - all tokens revoked`);
|
|
597
545
|
}
|
|
598
|
-
|
|
546
|
+
async isTokenRevoked(userId, tokenIssuedAt) {
|
|
599
547
|
if (!this.cacheManager || !tokenIssuedAt) {
|
|
600
548
|
return false;
|
|
601
549
|
}
|
|
@@ -607,7 +555,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
607
555
|
// Token is revoked if it was issued before the revocation timestamp
|
|
608
556
|
return tokenIssuedAt < revokedAt;
|
|
609
557
|
}
|
|
610
|
-
|
|
558
|
+
parseExpiryToMs(expiry) {
|
|
611
559
|
const match = expiry.match(/^(\d+)([smhd])$/);
|
|
612
560
|
if (!match) return 7 * 24 * 60 * 60 * 1000; // Default 7 days
|
|
613
561
|
const value = parseInt(match[1], 10);
|
|
@@ -626,7 +574,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
626
574
|
}
|
|
627
575
|
}
|
|
628
576
|
// Query Methods
|
|
629
|
-
|
|
577
|
+
async getUserCompanies(userId) {
|
|
630
578
|
this.ensureCompanyFeatureEnabled();
|
|
631
579
|
const permissionRepository = await this.getPermissionRepository();
|
|
632
580
|
const companyRepository = await this.getCompanyRepository();
|
|
@@ -647,7 +595,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
647
595
|
active: true
|
|
648
596
|
}).orderBy('c.name', 'ASC').getMany();
|
|
649
597
|
}
|
|
650
|
-
|
|
598
|
+
async getUserBranches(userId, companyId) {
|
|
651
599
|
this.ensureCompanyFeatureEnabled();
|
|
652
600
|
const permissionRepository = await this.getPermissionRepository();
|
|
653
601
|
const branchRepository = await this.getBranchRepository();
|
|
@@ -682,7 +630,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
682
630
|
active: true
|
|
683
631
|
}).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
|
|
684
632
|
}
|
|
685
|
-
|
|
633
|
+
async getCompanyById(companyId) {
|
|
686
634
|
const companyRepository = await this.getCompanyRepository();
|
|
687
635
|
if (!companyRepository) {
|
|
688
636
|
return null;
|
|
@@ -693,7 +641,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
693
641
|
}
|
|
694
642
|
});
|
|
695
643
|
}
|
|
696
|
-
|
|
644
|
+
async getBranchById(branchId) {
|
|
697
645
|
const branchRepository = await this.getBranchRepository();
|
|
698
646
|
if (!branchRepository) {
|
|
699
647
|
return null;
|
|
@@ -704,61 +652,35 @@ let AuthenticationService = class AuthenticationService {
|
|
|
704
652
|
}
|
|
705
653
|
});
|
|
706
654
|
}
|
|
707
|
-
|
|
655
|
+
async getUserInfo(userId, companyId, branchId) {
|
|
708
656
|
const userRepository = await this.getUserRepository();
|
|
709
657
|
const user = await userRepository.findOne({
|
|
710
658
|
where: {
|
|
711
659
|
id: userId
|
|
712
660
|
}
|
|
713
661
|
});
|
|
714
|
-
if (!user)
|
|
715
|
-
throw new _common.UnauthorizedException('User not found');
|
|
716
|
-
}
|
|
717
|
-
// Build response (no tokens)
|
|
662
|
+
if (!user) throw new _common.UnauthorizedException('User not found');
|
|
718
663
|
const response = {
|
|
719
|
-
user:
|
|
720
|
-
id: user.id,
|
|
721
|
-
email: user.email,
|
|
722
|
-
name: user.name ?? undefined,
|
|
723
|
-
phone: user.phone ?? undefined,
|
|
724
|
-
profilePictureId: user.profilePictureId ?? undefined
|
|
725
|
-
}
|
|
664
|
+
user: this.toUserInfo(user)
|
|
726
665
|
};
|
|
727
|
-
|
|
728
|
-
if (this.authConfig.isCompanyFeatureEnabled()) {
|
|
729
|
-
// When company feature is enabled, companyId MUST be present
|
|
666
|
+
if (this.isCompanyFeatureEnabled()) {
|
|
730
667
|
if (!companyId) {
|
|
731
|
-
throw new _common.UnauthorizedException('Company feature is enabled but user has no company assigned.
|
|
668
|
+
throw new _common.UnauthorizedException('Company feature is enabled but user has no company assigned.');
|
|
732
669
|
}
|
|
733
670
|
const company = await this.getCompanyById(companyId);
|
|
734
|
-
if (!company)
|
|
735
|
-
|
|
736
|
-
}
|
|
737
|
-
response.company = {
|
|
738
|
-
id: company.id,
|
|
739
|
-
name: company.name,
|
|
740
|
-
slug: company.slug,
|
|
741
|
-
logoId: company.logoId ?? null
|
|
742
|
-
};
|
|
743
|
-
// Branch is optional in some configurations, but if provided it must exist
|
|
671
|
+
if (!company) throw new _common.UnauthorizedException('Company not found.');
|
|
672
|
+
response.company = this.toCompanyInfo(company);
|
|
744
673
|
if (branchId) {
|
|
745
674
|
const branch = await this.getBranchById(branchId);
|
|
746
|
-
if (!branch)
|
|
747
|
-
|
|
748
|
-
}
|
|
749
|
-
response.branch = {
|
|
750
|
-
id: branch.id,
|
|
751
|
-
name: branch.name,
|
|
752
|
-
slug: branch.slug,
|
|
753
|
-
logoId: branch.logoId ?? null
|
|
754
|
-
};
|
|
675
|
+
if (!branch) throw new _common.UnauthorizedException('Branch not found.');
|
|
676
|
+
response.branch = this.toBranchInfo(branch);
|
|
755
677
|
}
|
|
756
678
|
}
|
|
757
679
|
return response;
|
|
758
680
|
}
|
|
759
681
|
// Helper Methods
|
|
760
682
|
ensureCompanyFeatureEnabled() {
|
|
761
|
-
if (!this.
|
|
683
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
762
684
|
throw new _common.BadRequestException('Company feature is not enabled');
|
|
763
685
|
}
|
|
764
686
|
}
|
|
@@ -769,11 +691,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
769
691
|
email
|
|
770
692
|
}
|
|
771
693
|
});
|
|
772
|
-
if (!user) {
|
|
773
|
-
throw new _common.UnauthorizedException('Invalid credentials');
|
|
774
|
-
}
|
|
775
|
-
const isPasswordValid = await _bcrypt.compare(password, user.password || '');
|
|
776
|
-
if (!isPasswordValid) {
|
|
694
|
+
if (!user || !await _bcrypt.compare(password, user.password || '')) {
|
|
777
695
|
throw new _common.UnauthorizedException('Invalid credentials');
|
|
778
696
|
}
|
|
779
697
|
user.lastLoginAt = new Date();
|
|
@@ -781,84 +699,77 @@ let AuthenticationService = class AuthenticationService {
|
|
|
781
699
|
return user;
|
|
782
700
|
}
|
|
783
701
|
// Response Generators
|
|
784
|
-
|
|
785
|
-
|
|
702
|
+
toUserInfo(user) {
|
|
703
|
+
return {
|
|
786
704
|
id: user.id,
|
|
787
705
|
email: user.email,
|
|
788
|
-
|
|
706
|
+
name: user.name ?? undefined,
|
|
707
|
+
phone: user.phone ?? null,
|
|
708
|
+
profilePictureId: user.profilePictureId ?? null
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
toCompanyInfo(company) {
|
|
712
|
+
return {
|
|
713
|
+
id: company.id,
|
|
714
|
+
name: company.name,
|
|
715
|
+
slug: company.slug,
|
|
716
|
+
logoId: company.logoId ?? null
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
toBranchInfo(branch) {
|
|
720
|
+
return {
|
|
721
|
+
id: branch.id,
|
|
722
|
+
name: branch.name,
|
|
723
|
+
slug: branch.slug,
|
|
724
|
+
logoId: branch.logoId ?? null
|
|
789
725
|
};
|
|
790
|
-
|
|
726
|
+
}
|
|
727
|
+
generateTokens(payload) {
|
|
728
|
+
const accessToken = this.jwtService.sign({
|
|
729
|
+
...payload,
|
|
730
|
+
type: 'access'
|
|
731
|
+
}, {
|
|
791
732
|
secret: this.authConfig.getJwtSecret(),
|
|
792
733
|
expiresIn: this.authConfig.getJwtExpiration()
|
|
793
734
|
});
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
email: user.email,
|
|
735
|
+
const refreshToken = this.jwtService.sign({
|
|
736
|
+
...payload,
|
|
797
737
|
type: 'refresh'
|
|
798
|
-
}
|
|
799
|
-
const refreshToken = this.jwtService.sign(refreshPayload, {
|
|
738
|
+
}, {
|
|
800
739
|
secret: this.authConfig.getRefreshTokenSecret(),
|
|
801
740
|
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
802
741
|
});
|
|
803
742
|
return {
|
|
804
743
|
accessToken,
|
|
805
|
-
refreshToken
|
|
806
|
-
user: {
|
|
807
|
-
id: user.id,
|
|
808
|
-
email: user.email,
|
|
809
|
-
name: user.name ?? undefined,
|
|
810
|
-
phone: user.phone ?? null,
|
|
811
|
-
profilePictureId: user.profilePictureId ?? null
|
|
812
|
-
},
|
|
813
|
-
companyFeatureEnabled
|
|
744
|
+
refreshToken
|
|
814
745
|
};
|
|
815
746
|
}
|
|
816
|
-
|
|
817
|
-
const
|
|
747
|
+
generateLoginResponse(user) {
|
|
748
|
+
const { accessToken, refreshToken } = this.generateTokens({
|
|
818
749
|
id: user.id,
|
|
819
750
|
email: user.email,
|
|
820
|
-
type: 'access'
|
|
821
|
-
companyId: company.id,
|
|
822
|
-
branchId: branch?.id
|
|
823
|
-
};
|
|
824
|
-
const accessToken = this.jwtService.sign(payload, {
|
|
825
|
-
secret: this.authConfig.getJwtSecret(),
|
|
826
|
-
expiresIn: this.authConfig.getJwtExpiration()
|
|
751
|
+
type: 'access'
|
|
827
752
|
});
|
|
828
|
-
|
|
753
|
+
return {
|
|
754
|
+
accessToken,
|
|
755
|
+
refreshToken,
|
|
756
|
+
user: this.toUserInfo(user)
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
generateLoginResponseWithCompany(user, company, branch) {
|
|
760
|
+
const { accessToken, refreshToken } = this.generateTokens({
|
|
829
761
|
id: user.id,
|
|
830
762
|
email: user.email,
|
|
831
|
-
type: '
|
|
763
|
+
type: 'access',
|
|
832
764
|
companyId: company.id,
|
|
833
765
|
branchId: branch?.id
|
|
834
|
-
};
|
|
835
|
-
const refreshToken = this.jwtService.sign(refreshPayload, {
|
|
836
|
-
secret: this.authConfig.getRefreshTokenSecret(),
|
|
837
|
-
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
838
766
|
});
|
|
839
767
|
return {
|
|
840
768
|
accessToken,
|
|
841
769
|
refreshToken,
|
|
842
|
-
user:
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
name: user.name ?? undefined,
|
|
846
|
-
phone: user.phone ?? null,
|
|
847
|
-
profilePictureId: user.profilePictureId ?? null
|
|
848
|
-
},
|
|
849
|
-
company: {
|
|
850
|
-
id: company.id,
|
|
851
|
-
name: company.name,
|
|
852
|
-
slug: company.slug,
|
|
853
|
-
logoId: company.logoId ?? null
|
|
854
|
-
},
|
|
855
|
-
branch: branch ? {
|
|
856
|
-
id: branch.id,
|
|
857
|
-
name: branch.name,
|
|
858
|
-
slug: branch.slug,
|
|
859
|
-
logoId: branch.logoId ?? null
|
|
860
|
-
} : undefined,
|
|
861
|
-
companyFeatureEnabled: true
|
|
770
|
+
user: this.toUserInfo(user),
|
|
771
|
+
company: this.toCompanyInfo(company),
|
|
772
|
+
branch: branch ? this.toBranchInfo(branch) : undefined
|
|
862
773
|
};
|
|
863
774
|
}
|
|
864
775
|
async generateCompanySelectionResponse(user, companies, branches) {
|
|
@@ -866,103 +777,42 @@ let AuthenticationService = class AuthenticationService {
|
|
|
866
777
|
throw new _common.BadRequestException('Session service not available');
|
|
867
778
|
}
|
|
868
779
|
const sessionId = await this.sessionService.createSession(user.id);
|
|
869
|
-
// Build companies with their branches
|
|
870
780
|
const companiesWithBranches = companies.map((company)=>({
|
|
871
|
-
|
|
872
|
-
name: company.name,
|
|
873
|
-
slug: company.slug,
|
|
781
|
+
...this.toCompanyInfo(company),
|
|
874
782
|
isActive: company.isActive,
|
|
875
|
-
logoId: company.logoId ?? null,
|
|
876
783
|
branches: branches.filter((b)=>b.companyId === company.id).map((b)=>({
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
slug: b.slug,
|
|
880
|
-
isActive: b.isActive,
|
|
881
|
-
logoId: b.logoId ?? null
|
|
784
|
+
...this.toBranchInfo(b),
|
|
785
|
+
isActive: b.isActive
|
|
882
786
|
}))
|
|
883
787
|
}));
|
|
884
788
|
return {
|
|
885
789
|
requiresSelection: true,
|
|
886
790
|
sessionId,
|
|
887
791
|
expiresAt: new Date(Date.now() + 5 * 60 * 1000),
|
|
888
|
-
user:
|
|
889
|
-
id: user.id,
|
|
890
|
-
email: user.email,
|
|
891
|
-
name: user.name ?? undefined,
|
|
892
|
-
phone: user.phone ?? null,
|
|
893
|
-
profilePictureId: user.profilePictureId ?? null
|
|
894
|
-
},
|
|
792
|
+
user: this.toUserInfo(user),
|
|
895
793
|
companies: companiesWithBranches
|
|
896
794
|
};
|
|
897
795
|
}
|
|
898
|
-
|
|
899
|
-
const userInfo = {
|
|
900
|
-
id: user.id,
|
|
901
|
-
email: user.email,
|
|
902
|
-
name: user.name ?? undefined,
|
|
903
|
-
phone: user.phone ?? null,
|
|
904
|
-
profilePictureId: user.profilePictureId ?? null
|
|
905
|
-
};
|
|
906
|
-
if (requiresEmailVerification) {
|
|
907
|
-
return {
|
|
908
|
-
user: userInfo,
|
|
909
|
-
companyFeatureEnabled,
|
|
910
|
-
requiresEmailVerification: true
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
const loginResponse = this.generateLoginResponse(user, companyFeatureEnabled);
|
|
796
|
+
generateRegistrationResponse(user) {
|
|
914
797
|
return {
|
|
915
|
-
...
|
|
798
|
+
...this.generateLoginResponse(user),
|
|
916
799
|
requiresEmailVerification: false
|
|
917
800
|
};
|
|
918
801
|
}
|
|
919
|
-
|
|
920
|
-
const userInfo = {
|
|
921
|
-
id: user.id,
|
|
922
|
-
email: user.email,
|
|
923
|
-
name: user.name ?? undefined,
|
|
924
|
-
phone: user.phone ?? null,
|
|
925
|
-
profilePictureId: user.profilePictureId ?? null
|
|
926
|
-
};
|
|
927
|
-
const companyInfo = {
|
|
928
|
-
id: company.id,
|
|
929
|
-
name: company.name,
|
|
930
|
-
slug: company.slug,
|
|
931
|
-
logoId: company.logoId ?? null
|
|
932
|
-
};
|
|
933
|
-
const branchInfo = branch ? {
|
|
934
|
-
id: branch.id,
|
|
935
|
-
name: branch.name,
|
|
936
|
-
slug: branch.slug,
|
|
937
|
-
logoId: branch.logoId ?? null
|
|
938
|
-
} : undefined;
|
|
939
|
-
if (requiresEmailVerification) {
|
|
940
|
-
return {
|
|
941
|
-
user: userInfo,
|
|
942
|
-
company: companyInfo,
|
|
943
|
-
branch: branchInfo,
|
|
944
|
-
companyFeatureEnabled: true,
|
|
945
|
-
requiresEmailVerification: true
|
|
946
|
-
};
|
|
947
|
-
}
|
|
948
|
-
const loginResponse = this.generateLoginResponseWithCompany(user, company, branch);
|
|
802
|
+
generateRegistrationResponseWithCompany(user, company, branch) {
|
|
949
803
|
return {
|
|
950
|
-
...
|
|
804
|
+
...this.generateLoginResponseWithCompany(user, company, branch),
|
|
951
805
|
requiresEmailVerification: false
|
|
952
806
|
};
|
|
953
807
|
}
|
|
954
808
|
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
955
|
-
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService
|
|
809
|
+
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService){
|
|
956
810
|
_define_property(this, "jwtService", void 0);
|
|
957
811
|
_define_property(this, "authConfig", void 0);
|
|
958
812
|
_define_property(this, "cacheManager", void 0);
|
|
959
813
|
_define_property(this, "dataSourceProvider", void 0);
|
|
960
814
|
_define_property(this, "sessionService", void 0);
|
|
961
815
|
_define_property(this, "authEmailService", void 0);
|
|
962
|
-
_define_property(this, "injectedUserRepository", void 0);
|
|
963
|
-
_define_property(this, "injectedPermissionRepository", void 0);
|
|
964
|
-
_define_property(this, "injectedCompanyRepository", void 0);
|
|
965
|
-
_define_property(this, "injectedBranchRepository", void 0);
|
|
966
816
|
_define_property(this, "logger", void 0);
|
|
967
817
|
this.jwtService = jwtService;
|
|
968
818
|
this.authConfig = authConfig;
|
|
@@ -970,10 +820,6 @@ let AuthenticationService = class AuthenticationService {
|
|
|
970
820
|
this.dataSourceProvider = dataSourceProvider;
|
|
971
821
|
this.sessionService = sessionService;
|
|
972
822
|
this.authEmailService = authEmailService;
|
|
973
|
-
this.injectedUserRepository = injectedUserRepository;
|
|
974
|
-
this.injectedPermissionRepository = injectedPermissionRepository;
|
|
975
|
-
this.injectedCompanyRepository = injectedCompanyRepository;
|
|
976
|
-
this.injectedBranchRepository = injectedBranchRepository;
|
|
977
823
|
this.logger = new _common.Logger(AuthenticationService.name);
|
|
978
824
|
}
|
|
979
825
|
};
|
|
@@ -991,14 +837,6 @@ AuthenticationService = _ts_decorate([
|
|
|
991
837
|
_ts_param(4, (0, _common.Inject)(_companyselectionsessionservice.CompanySelectionSessionService)),
|
|
992
838
|
_ts_param(5, (0, _common.Optional)()),
|
|
993
839
|
_ts_param(5, (0, _common.Inject)(_authemailservice.AuthEmailService)),
|
|
994
|
-
_ts_param(6, (0, _common.Optional)()),
|
|
995
|
-
_ts_param(6, (0, _typeorm.InjectRepository)(_userentity.User)),
|
|
996
|
-
_ts_param(7, (0, _common.Optional)()),
|
|
997
|
-
_ts_param(7, (0, _typeorm.InjectRepository)(_usercompanypermissionentity.UserCompanyPermission)),
|
|
998
|
-
_ts_param(8, (0, _common.Optional)()),
|
|
999
|
-
_ts_param(8, (0, _typeorm.InjectRepository)(_companyentity.Company)),
|
|
1000
|
-
_ts_param(9, (0, _common.Optional)()),
|
|
1001
|
-
_ts_param(9, (0, _typeorm.InjectRepository)(_companybranchentity.CompanyBranch)),
|
|
1002
840
|
_ts_metadata("design:type", Function),
|
|
1003
841
|
_ts_metadata("design:paramtypes", [
|
|
1004
842
|
typeof _jwt.JwtService === "undefined" ? Object : _jwt.JwtService,
|
|
@@ -1006,10 +844,6 @@ AuthenticationService = _ts_decorate([
|
|
|
1006
844
|
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
1007
845
|
typeof _authdatasourceprovider.AuthDataSourceProvider === "undefined" ? Object : _authdatasourceprovider.AuthDataSourceProvider,
|
|
1008
846
|
typeof _companyselectionsessionservice.CompanySelectionSessionService === "undefined" ? Object : _companyselectionsessionservice.CompanySelectionSessionService,
|
|
1009
|
-
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService
|
|
1010
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
|
|
1011
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
|
|
1012
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
|
|
1013
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository
|
|
847
|
+
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService
|
|
1014
848
|
])
|
|
1015
849
|
], AuthenticationService);
|