@flusys/nestjs-auth 1.0.0-beta → 1.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 +590 -473
- package/cjs/config/auth.constants.js +12 -0
- package/cjs/controllers/authentication.controller.js +365 -24
- package/cjs/controllers/branch.controller.js +44 -1
- package/cjs/controllers/company-selection.controller.js +27 -20
- package/cjs/controllers/company.controller.js +44 -1
- package/cjs/controllers/user-permission.controller.js +82 -154
- package/cjs/controllers/user.controller.js +211 -7
- package/cjs/docs/auth-swagger.config.js +14 -7
- package/cjs/dtos/authentication.dto.js +114 -38
- 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 +5 -1
- package/cjs/entities/pending-registration.entity.js +125 -0
- package/cjs/entities/user-company-permission.entity.js +3 -9
- package/cjs/entities/user-token.entity.js +129 -0
- 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 +45 -0
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/user-enricher.interface.js +4 -0
- package/cjs/modules/auth.module.js +65 -143
- package/cjs/services/auth-config.service.js +25 -27
- package/cjs/services/auth-datasource.provider.js +13 -23
- package/cjs/services/auth-email.service.js +456 -0
- package/cjs/services/authentication.service.js +297 -349
- package/cjs/services/branch.service.js +9 -4
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +43 -73
- package/cjs/services/user.service.js +184 -34
- package/cjs/strategies/jwt.strategy.js +44 -44
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +3 -0
- package/controllers/authentication.controller.d.ts +16 -10
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/user-permission.controller.d.ts +5 -4
- package/controllers/user.controller.d.ts +33 -0
- package/dtos/authentication.dto.d.ts +20 -6
- 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 -2
- package/entities/index.d.ts +7 -3
- package/entities/pending-registration.entity.d.ts +17 -0
- package/entities/user-company-permission.entity.d.ts +1 -3
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +6 -2
- package/fesm/controllers/authentication.controller.js +368 -27
- package/fesm/controllers/branch.controller.js +45 -2
- package/fesm/controllers/company-selection.controller.js +28 -21
- package/fesm/controllers/company.controller.js +45 -2
- package/fesm/controllers/user-permission.controller.js +84 -156
- package/fesm/controllers/user.controller.js +214 -10
- package/fesm/docs/auth-swagger.config.js +14 -7
- package/fesm/dtos/authentication.dto.js +101 -39
- 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 +7 -1
- package/fesm/entities/pending-registration.entity.js +115 -0
- package/fesm/entities/user-company-permission.entity.js +3 -9
- package/fesm/entities/user-token.entity.js +113 -0
- 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 +38 -0
- package/fesm/interfaces/authentication.interface.js +1 -1
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/user-enricher.interface.js +26 -0
- package/fesm/modules/auth.module.js +67 -145
- package/fesm/services/auth-config.service.js +26 -28
- package/fesm/services/auth-datasource.provider.js +14 -24
- package/fesm/services/auth-email.service.js +405 -0
- package/fesm/services/authentication.service.js +297 -349
- package/fesm/services/branch.service.js +9 -4
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +44 -74
- package/fesm/services/user.service.js +186 -36
- 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/auth-email-provider.interface.d.ts +6 -0
- package/interfaces/auth-module-options.interface.d.ts +4 -1
- package/interfaces/authentication.interface.d.ts +13 -3
- package/interfaces/index.d.ts +2 -0
- package/interfaces/user-enricher.interface.d.ts +64 -0
- package/interfaces/user.interface.d.ts +1 -0
- package/modules/auth.module.d.ts +6 -3
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +7 -8
- package/services/auth-datasource.provider.d.ts +2 -4
- package/services/auth-email.service.d.ts +54 -0
- package/services/authentication.service.d.ts +27 -16
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/index.d.ts +1 -0
- package/services/user-permission.service.d.ts +6 -9
- package/services/user.service.d.ts +19 -3
- 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,21 +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
17
|
const _companybranchentity = require("../entities/company-branch.entity");
|
|
23
18
|
const _companyentity = require("../entities/company.entity");
|
|
24
19
|
const _usercompanypermissionentity = require("../entities/user-company-permission.entity");
|
|
25
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");
|
|
26
25
|
const _companyselectionsessionservice = require("./company-selection-session.service");
|
|
27
26
|
function _define_property(obj, key, value) {
|
|
28
27
|
if (key in obj) {
|
|
@@ -93,45 +92,51 @@ function _ts_param(paramIndex, decorator) {
|
|
|
93
92
|
};
|
|
94
93
|
}
|
|
95
94
|
let AuthenticationService = class AuthenticationService {
|
|
95
|
+
// Feature Flags
|
|
96
|
+
/** Check if company feature is enabled (tenant-aware with global fallback) */ isCompanyFeatureEnabled() {
|
|
97
|
+
return this.dataSourceProvider?.isCompanyFeatureEnabled() ?? this.authConfig.isCompanyFeatureEnabled();
|
|
98
|
+
}
|
|
96
99
|
// Repository Getters
|
|
97
100
|
async getUserRepository() {
|
|
98
|
-
if (this.dataSourceProvider) {
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
if (this.injectedUserRepository) {
|
|
102
|
-
return this.injectedUserRepository;
|
|
101
|
+
if (!this.dataSourceProvider) {
|
|
102
|
+
throw new Error('User repository not available');
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
return this.dataSourceProvider.getRepository(_userentity.User);
|
|
105
105
|
}
|
|
106
106
|
async getPermissionRepository() {
|
|
107
|
-
if (!this.
|
|
108
|
-
|
|
109
|
-
return this.dataSourceProvider.getRepository(_usercompanypermissionentity.UserCompanyPermission);
|
|
110
|
-
}
|
|
111
|
-
return this.injectedPermissionRepository ?? null;
|
|
107
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
108
|
+
return this.dataSourceProvider.getRepository(_usercompanypermissionentity.UserCompanyPermission);
|
|
112
109
|
}
|
|
113
110
|
async getCompanyRepository() {
|
|
114
|
-
if (!this.
|
|
115
|
-
|
|
116
|
-
return this.dataSourceProvider.getRepository(_companyentity.Company);
|
|
117
|
-
}
|
|
118
|
-
return this.injectedCompanyRepository ?? null;
|
|
111
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
112
|
+
return this.dataSourceProvider.getRepository(_companyentity.Company);
|
|
119
113
|
}
|
|
120
114
|
async getBranchRepository() {
|
|
121
|
-
if (!this.
|
|
122
|
-
|
|
123
|
-
return this.dataSourceProvider.getRepository(_companybranchentity.CompanyBranch);
|
|
124
|
-
}
|
|
125
|
-
return this.injectedBranchRepository ?? null;
|
|
115
|
+
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
116
|
+
return this.dataSourceProvider.getRepository(_companybranchentity.CompanyBranch);
|
|
126
117
|
}
|
|
127
118
|
// Login
|
|
128
|
-
|
|
119
|
+
async login(email, password) {
|
|
120
|
+
// Check for pending registration first (user registered but hasn't verified email yet)
|
|
121
|
+
if (await this.authEmailService?.hasPendingRegistration(email)) {
|
|
122
|
+
return {
|
|
123
|
+
requiresEmailVerification: true,
|
|
124
|
+
email,
|
|
125
|
+
message: 'Please verify your email address to complete registration.'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
129
128
|
const user = await this.validateUser(email, password);
|
|
130
129
|
if (!user.isActive) {
|
|
131
130
|
throw new _common.UnauthorizedException('User account is deactivated');
|
|
132
131
|
}
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
if (this.authEmailService?.isEmailEnabled() && !user.emailVerified) {
|
|
133
|
+
return {
|
|
134
|
+
requiresEmailVerification: true,
|
|
135
|
+
email: user.email,
|
|
136
|
+
message: 'Please verify your email address before logging in.'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
135
140
|
return this.generateLoginResponse(user);
|
|
136
141
|
}
|
|
137
142
|
return this.handleCompanyBasedLogin(user);
|
|
@@ -163,7 +168,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
163
168
|
// If user has no company assignments yet, return simple login response
|
|
164
169
|
// This allows users to login and be assigned to companies later
|
|
165
170
|
if (companies.length === 0) {
|
|
166
|
-
return this.generateLoginResponse(user
|
|
171
|
+
return this.generateLoginResponse(user);
|
|
167
172
|
}
|
|
168
173
|
// Get branch permissions
|
|
169
174
|
const branchPermissions = await permissionRepository.find({
|
|
@@ -187,19 +192,80 @@ let AuthenticationService = class AuthenticationService {
|
|
|
187
192
|
return await this.generateCompanySelectionResponse(user, companies, branches);
|
|
188
193
|
}
|
|
189
194
|
// Registration
|
|
190
|
-
/** Register a new user. If
|
|
195
|
+
/** Register a new user. If email enabled, creates pending registration. Otherwise creates user directly. */ async register(dto, verifyUrlBase) {
|
|
191
196
|
const userRepository = await this.getUserRepository();
|
|
192
|
-
// Check if user exists
|
|
193
|
-
// Note: Generic error message to prevent email enumeration attacks
|
|
194
197
|
const existingUser = await userRepository.findOne({
|
|
195
198
|
where: {
|
|
196
199
|
email: dto.email
|
|
197
200
|
}
|
|
198
201
|
});
|
|
202
|
+
// When company feature is enabled and user exists, allow joining/creating company
|
|
203
|
+
if (existingUser && this.isCompanyFeatureEnabled()) {
|
|
204
|
+
return this.handleExistingUserCompanyRegistration(existingUser, dto);
|
|
205
|
+
}
|
|
206
|
+
// User exists but company feature is off - email must be unique
|
|
199
207
|
if (existingUser) {
|
|
200
|
-
throw new _common.BadRequestException('Registration failed. Please try again or contact support.');
|
|
208
|
+
throw new _common.BadRequestException('Registration failed due to email exists. Please try again or contact support.');
|
|
209
|
+
}
|
|
210
|
+
// If email verification is enabled, create pending registration instead of user
|
|
211
|
+
if (this.authEmailService?.isEmailEnabled() && verifyUrlBase) {
|
|
212
|
+
const companyData = this.isCompanyFeatureEnabled() ? {
|
|
213
|
+
companySlug: dto.companySlug,
|
|
214
|
+
branchSlug: dto.branchSlug,
|
|
215
|
+
newCompanyName: dto.newCompanyName,
|
|
216
|
+
newCompanyPhone: dto.newCompanyPhone,
|
|
217
|
+
newCompanyAddress: dto.newCompanyAddress
|
|
218
|
+
} : undefined;
|
|
219
|
+
const result = await this.authEmailService.createPendingRegistration({
|
|
220
|
+
email: dto.email,
|
|
221
|
+
name: dto.name,
|
|
222
|
+
phone: dto.phone,
|
|
223
|
+
password: dto.password,
|
|
224
|
+
companyData,
|
|
225
|
+
verifyUrlBase
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
requiresEmailVerification: true,
|
|
229
|
+
message: result.message
|
|
230
|
+
};
|
|
201
231
|
}
|
|
202
|
-
//
|
|
232
|
+
// No email verification - create user directly
|
|
233
|
+
return this.createUserDirectly(dto);
|
|
234
|
+
}
|
|
235
|
+
/** Handle registration for existing user when company feature is enabled */ async handleExistingUserCompanyRegistration(existingUser, dto) {
|
|
236
|
+
if (!dto.companySlug && !dto.newCompanyName) {
|
|
237
|
+
throw new _common.BadRequestException('Email already registered. Please login or provide a company to join/create.');
|
|
238
|
+
}
|
|
239
|
+
const permissionRepository = await this.getPermissionRepository();
|
|
240
|
+
const companyRepository = await this.getCompanyRepository();
|
|
241
|
+
if (!permissionRepository || !companyRepository) {
|
|
242
|
+
throw new _common.BadRequestException('Company feature repositories not available');
|
|
243
|
+
}
|
|
244
|
+
// For existing users joining a company, check if already assigned
|
|
245
|
+
if (dto.companySlug) {
|
|
246
|
+
const company = await companyRepository.findOne({
|
|
247
|
+
where: {
|
|
248
|
+
slug: dto.companySlug,
|
|
249
|
+
isActive: true
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
if (company) {
|
|
253
|
+
const existingPermission = await permissionRepository.findOne({
|
|
254
|
+
where: {
|
|
255
|
+
userId: existingUser.id,
|
|
256
|
+
permissionType: _enums.PermissionType.COMPANY,
|
|
257
|
+
targetId: company.id
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
if (existingPermission) {
|
|
261
|
+
throw new _common.BadRequestException('You are already assigned to this company. Please login.');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return this.processCompanyRegistration(existingUser, dto, true);
|
|
266
|
+
}
|
|
267
|
+
/** Create user directly (no email verification) */ async createUserDirectly(dto) {
|
|
268
|
+
const userRepository = await this.getUserRepository();
|
|
203
269
|
const hashedPassword = await _bcrypt.hash(dto.password, _config.BCRYPT_SALT_ROUNDS);
|
|
204
270
|
const user = userRepository.create({
|
|
205
271
|
name: dto.name,
|
|
@@ -211,112 +277,128 @@ let AuthenticationService = class AuthenticationService {
|
|
|
211
277
|
phoneVerified: false
|
|
212
278
|
});
|
|
213
279
|
await userRepository.save(user);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return this.generateLoginResponse(user, false);
|
|
280
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
281
|
+
return this.generateRegistrationResponse(user);
|
|
217
282
|
}
|
|
218
|
-
|
|
219
|
-
return this.handleCompanyRegistration(user, dto);
|
|
283
|
+
return this.processCompanyRegistration(user, dto);
|
|
220
284
|
}
|
|
221
|
-
/**
|
|
285
|
+
/** Create user from pending registration (after email verification) */ async createUserFromPendingRegistration(pending) {
|
|
286
|
+
const userRepository = await this.getUserRepository();
|
|
287
|
+
const existingUser = await userRepository.findOne({
|
|
288
|
+
where: {
|
|
289
|
+
email: pending.email
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
if (existingUser) {
|
|
293
|
+
throw new _common.BadRequestException('This email has already been registered.');
|
|
294
|
+
}
|
|
295
|
+
const user = userRepository.create({
|
|
296
|
+
name: pending.name,
|
|
297
|
+
email: pending.email,
|
|
298
|
+
phone: pending.phone,
|
|
299
|
+
password: pending.passwordHash,
|
|
300
|
+
isActive: true,
|
|
301
|
+
emailVerified: true,
|
|
302
|
+
phoneVerified: false
|
|
303
|
+
});
|
|
304
|
+
await userRepository.save(user);
|
|
305
|
+
if (this.isCompanyFeatureEnabled() && pending.companyData) {
|
|
306
|
+
return this.processCompanyRegistration(user, pending.companyData);
|
|
307
|
+
}
|
|
308
|
+
return this.generateRegistrationResponse(user);
|
|
309
|
+
}
|
|
310
|
+
/** Process company registration (join existing or create new) */ async processCompanyRegistration(user, data, throwOnUnavailable = false) {
|
|
222
311
|
const companyRepository = await this.getCompanyRepository();
|
|
223
312
|
const branchRepository = await this.getBranchRepository();
|
|
224
313
|
const permissionRepository = await this.getPermissionRepository();
|
|
225
314
|
if (!companyRepository || !branchRepository || !permissionRepository) {
|
|
226
|
-
|
|
315
|
+
if (throwOnUnavailable) throw new _common.BadRequestException('Company feature repositories not available');
|
|
316
|
+
return this.generateRegistrationResponse(user);
|
|
227
317
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
318
|
+
const { company, branch } = await this.findOrCreateCompanyAndBranch(data, companyRepository, branchRepository);
|
|
319
|
+
if (company) {
|
|
320
|
+
await this.assignUserPermissions(user.id, company.id, branch?.id, permissionRepository);
|
|
321
|
+
return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined);
|
|
322
|
+
}
|
|
323
|
+
return this.generateRegistrationResponse(user);
|
|
324
|
+
}
|
|
325
|
+
/** Find existing company/branch or create new ones */ async findOrCreateCompanyAndBranch(data, companyRepo, branchRepo) {
|
|
326
|
+
if (data.companySlug) {
|
|
327
|
+
const company = await companyRepo.findOne({
|
|
233
328
|
where: {
|
|
234
|
-
slug:
|
|
329
|
+
slug: data.companySlug,
|
|
235
330
|
isActive: true
|
|
236
331
|
}
|
|
237
332
|
});
|
|
238
|
-
if (!company)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
where: {
|
|
245
|
-
slug: dto.branchSlug,
|
|
246
|
-
companyId: company.id,
|
|
247
|
-
isActive: true
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
if (!branch) {
|
|
251
|
-
throw new _common.BadRequestException('Branch not found or inactive');
|
|
333
|
+
if (!company) throw new _common.BadRequestException('Company not found or inactive');
|
|
334
|
+
const branch = data.branchSlug ? await branchRepo.findOne({
|
|
335
|
+
where: {
|
|
336
|
+
slug: data.branchSlug,
|
|
337
|
+
companyId: company.id,
|
|
338
|
+
isActive: true
|
|
252
339
|
}
|
|
253
|
-
}
|
|
254
|
-
// Get first active branch
|
|
255
|
-
branch = await branchRepository.findOne({
|
|
256
|
-
where: {
|
|
257
|
-
companyId: company.id,
|
|
258
|
-
isActive: true
|
|
259
|
-
},
|
|
260
|
-
order: {
|
|
261
|
-
serial: 'ASC',
|
|
262
|
-
createdAt: 'ASC'
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
} else if (dto.newCompanyName) {
|
|
267
|
-
const slug = this.generateSlug(dto.newCompanyName);
|
|
268
|
-
// Check if slug exists
|
|
269
|
-
const existingCompany = await companyRepository.findOne({
|
|
340
|
+
}) : await branchRepo.findOne({
|
|
270
341
|
where: {
|
|
271
|
-
|
|
342
|
+
companyId: company.id,
|
|
343
|
+
isActive: true
|
|
344
|
+
},
|
|
345
|
+
order: {
|
|
346
|
+
serial: 'ASC',
|
|
347
|
+
createdAt: 'ASC'
|
|
272
348
|
}
|
|
273
349
|
});
|
|
274
|
-
if (
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
350
|
+
if (data.branchSlug && !branch) throw new _common.BadRequestException('Branch not found or inactive');
|
|
351
|
+
return {
|
|
352
|
+
company,
|
|
353
|
+
branch
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
if (data.newCompanyName) {
|
|
357
|
+
const slug = await (0, _utils.generateUniqueSlug)(data.newCompanyName, async (baseSlug)=>{
|
|
358
|
+
const rows = await companyRepo.createQueryBuilder('c').select('c.slug').where('c.slug = :base OR c.slug LIKE :pattern', {
|
|
359
|
+
base: baseSlug,
|
|
360
|
+
pattern: `${baseSlug}-%`
|
|
361
|
+
}).getMany();
|
|
362
|
+
return rows.map((r)=>r.slug);
|
|
363
|
+
});
|
|
364
|
+
const company = companyRepo.create({
|
|
365
|
+
name: data.newCompanyName,
|
|
280
366
|
slug,
|
|
281
|
-
phone:
|
|
282
|
-
address:
|
|
367
|
+
phone: data.newCompanyPhone,
|
|
368
|
+
address: data.newCompanyAddress,
|
|
283
369
|
isActive: true
|
|
284
370
|
});
|
|
285
|
-
await
|
|
286
|
-
|
|
287
|
-
branch = branchRepository.create({
|
|
371
|
+
await companyRepo.save(company);
|
|
372
|
+
const branch = branchRepo.create({
|
|
288
373
|
name: 'Main Branch',
|
|
289
374
|
slug: 'main-branch',
|
|
290
375
|
companyId: company.id,
|
|
291
376
|
isActive: true
|
|
292
377
|
});
|
|
293
|
-
await
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const companyPermission = permissionRepository.create({
|
|
299
|
-
userId: user.id,
|
|
300
|
-
permissionType: _enums.PermissionType.COMPANY,
|
|
301
|
-
targetId: company.id
|
|
302
|
-
});
|
|
303
|
-
await permissionRepository.save(companyPermission);
|
|
304
|
-
// Create branch permission if branch exists
|
|
305
|
-
if (branch) {
|
|
306
|
-
const branchPermission = permissionRepository.create({
|
|
307
|
-
userId: user.id,
|
|
308
|
-
permissionType: _enums.PermissionType.BRANCH,
|
|
309
|
-
targetId: branch.id
|
|
310
|
-
});
|
|
311
|
-
await permissionRepository.save(branchPermission);
|
|
312
|
-
}
|
|
313
|
-
return this.generateLoginResponseWithCompany(user, company, branch ?? undefined);
|
|
378
|
+
await branchRepo.save(branch);
|
|
379
|
+
return {
|
|
380
|
+
company,
|
|
381
|
+
branch
|
|
382
|
+
};
|
|
314
383
|
}
|
|
315
|
-
|
|
316
|
-
|
|
384
|
+
return {
|
|
385
|
+
company: null,
|
|
386
|
+
branch: null
|
|
387
|
+
};
|
|
317
388
|
}
|
|
318
|
-
/**
|
|
319
|
-
|
|
389
|
+
/** Assign user to company and optionally branch */ async assignUserPermissions(userId, companyId, branchId, permissionRepo) {
|
|
390
|
+
await permissionRepo.save(permissionRepo.create({
|
|
391
|
+
userId,
|
|
392
|
+
permissionType: _enums.PermissionType.COMPANY,
|
|
393
|
+
targetId: companyId
|
|
394
|
+
}));
|
|
395
|
+
if (branchId) {
|
|
396
|
+
await permissionRepo.save(permissionRepo.create({
|
|
397
|
+
userId,
|
|
398
|
+
permissionType: _enums.PermissionType.BRANCH,
|
|
399
|
+
targetId: branchId
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
320
402
|
}
|
|
321
403
|
// Company/Branch Selection
|
|
322
404
|
/** Select company and branch (step 2 of login). Frontend receives all options and user selects both. */ async select(sessionId, companyId, branchId) {
|
|
@@ -328,66 +410,13 @@ let AuthenticationService = class AuthenticationService {
|
|
|
328
410
|
if (!session) {
|
|
329
411
|
throw new _common.UnauthorizedException('Invalid or expired session');
|
|
330
412
|
}
|
|
331
|
-
|
|
332
|
-
const user = await userRepository.findOne({
|
|
333
|
-
where: {
|
|
334
|
-
id: session.userId
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
if (!user) {
|
|
338
|
-
throw new _common.NotFoundException('User not found');
|
|
339
|
-
}
|
|
340
|
-
const permissionRepository = await this.getPermissionRepository();
|
|
341
|
-
const companyRepository = await this.getCompanyRepository();
|
|
342
|
-
const branchRepository = await this.getBranchRepository();
|
|
343
|
-
if (!permissionRepository || !companyRepository || !branchRepository) {
|
|
344
|
-
throw new _common.BadRequestException('Repositories not available');
|
|
345
|
-
}
|
|
346
|
-
// Validate company access
|
|
347
|
-
const companyPermission = await permissionRepository.findOne({
|
|
348
|
-
where: {
|
|
349
|
-
userId: user.id,
|
|
350
|
-
permissionType: _enums.PermissionType.COMPANY,
|
|
351
|
-
targetId: companyId
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
if (!companyPermission) {
|
|
355
|
-
throw new _common.UnauthorizedException('No access to this company');
|
|
356
|
-
}
|
|
357
|
-
const company = await companyRepository.findOne({
|
|
358
|
-
where: {
|
|
359
|
-
id: companyId,
|
|
360
|
-
isActive: true
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
if (!company) {
|
|
364
|
-
throw new _common.UnauthorizedException('Company not found or inactive');
|
|
365
|
-
}
|
|
366
|
-
// Validate branch access
|
|
367
|
-
const branchPermission = await permissionRepository.findOne({
|
|
368
|
-
where: {
|
|
369
|
-
userId: user.id,
|
|
370
|
-
permissionType: _enums.PermissionType.BRANCH,
|
|
371
|
-
targetId: branchId
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
if (!branchPermission) {
|
|
375
|
-
throw new _common.UnauthorizedException('No access to this branch');
|
|
376
|
-
}
|
|
377
|
-
const branch = await branchRepository.findOne({
|
|
378
|
-
where: {
|
|
379
|
-
id: branchId,
|
|
380
|
-
companyId,
|
|
381
|
-
isActive: true
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
if (!branch) {
|
|
385
|
-
throw new _common.UnauthorizedException('Branch not found or inactive');
|
|
386
|
-
}
|
|
387
|
-
return this.generateLoginResponseWithCompany(user, company, branch);
|
|
413
|
+
return this.validateAndLoginWithCompany(session.userId, companyId, branchId);
|
|
388
414
|
}
|
|
389
415
|
/** Switch company/branch after login */ async switchCompany(userId, companyId, branchId) {
|
|
390
416
|
this.ensureCompanyFeatureEnabled();
|
|
417
|
+
return this.validateAndLoginWithCompany(userId, companyId, branchId);
|
|
418
|
+
}
|
|
419
|
+
/** Shared: Validate user access to company/branch and generate login response */ async validateAndLoginWithCompany(userId, companyId, branchId) {
|
|
391
420
|
const userRepository = await this.getUserRepository();
|
|
392
421
|
const user = await userRepository.findOne({
|
|
393
422
|
where: {
|
|
@@ -404,14 +433,14 @@ let AuthenticationService = class AuthenticationService {
|
|
|
404
433
|
throw new _common.BadRequestException('Repositories not available');
|
|
405
434
|
}
|
|
406
435
|
// Validate company access
|
|
407
|
-
const
|
|
436
|
+
const hasCompanyAccess = await permissionRepository.findOne({
|
|
408
437
|
where: {
|
|
409
438
|
userId,
|
|
410
439
|
permissionType: _enums.PermissionType.COMPANY,
|
|
411
440
|
targetId: companyId
|
|
412
441
|
}
|
|
413
442
|
});
|
|
414
|
-
if (!
|
|
443
|
+
if (!hasCompanyAccess) {
|
|
415
444
|
throw new _common.UnauthorizedException('No access to this company');
|
|
416
445
|
}
|
|
417
446
|
const company = await companyRepository.findOne({
|
|
@@ -423,14 +452,15 @@ let AuthenticationService = class AuthenticationService {
|
|
|
423
452
|
if (!company) {
|
|
424
453
|
throw new _common.UnauthorizedException('Company not found or inactive');
|
|
425
454
|
}
|
|
426
|
-
|
|
455
|
+
// Validate branch access
|
|
456
|
+
const hasBranchAccess = await permissionRepository.findOne({
|
|
427
457
|
where: {
|
|
428
458
|
userId,
|
|
429
459
|
permissionType: _enums.PermissionType.BRANCH,
|
|
430
460
|
targetId: branchId
|
|
431
461
|
}
|
|
432
462
|
});
|
|
433
|
-
if (!
|
|
463
|
+
if (!hasBranchAccess) {
|
|
434
464
|
throw new _common.UnauthorizedException('No access to this branch');
|
|
435
465
|
}
|
|
436
466
|
const branch = await branchRepository.findOne({
|
|
@@ -451,6 +481,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
451
481
|
const payload = this.jwtService.verify(refreshToken, {
|
|
452
482
|
secret: this.authConfig.getRefreshTokenSecret()
|
|
453
483
|
});
|
|
484
|
+
if (await this.isTokenRevoked(payload.id, payload.iat)) {
|
|
485
|
+
throw new _common.UnauthorizedException('Token has been revoked');
|
|
486
|
+
}
|
|
454
487
|
const userRepository = await this.getUserRepository();
|
|
455
488
|
const user = await userRepository.findOne({
|
|
456
489
|
where: {
|
|
@@ -460,7 +493,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
460
493
|
if (!user || !user.isActive) {
|
|
461
494
|
throw new _common.UnauthorizedException('Invalid refresh token');
|
|
462
495
|
}
|
|
463
|
-
|
|
496
|
+
return this.generateTokens({
|
|
464
497
|
id: user.id,
|
|
465
498
|
email: user.email,
|
|
466
499
|
type: 'access',
|
|
@@ -470,44 +503,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
470
503
|
},
|
|
471
504
|
...payload.branchId && {
|
|
472
505
|
branchId: payload.branchId
|
|
473
|
-
},
|
|
474
|
-
...payload.companyLogoId && {
|
|
475
|
-
companyLogoId: payload.companyLogoId
|
|
476
|
-
},
|
|
477
|
-
...payload.branchLogoId && {
|
|
478
|
-
branchLogoId: payload.branchLogoId
|
|
479
506
|
}
|
|
480
|
-
};
|
|
481
|
-
const refreshPayload = {
|
|
482
|
-
id: user.id,
|
|
483
|
-
email: user.email,
|
|
484
|
-
type: 'refresh',
|
|
485
|
-
profilePictureId: user.profilePictureId ?? undefined,
|
|
486
|
-
...payload.companyId && {
|
|
487
|
-
companyId: payload.companyId
|
|
488
|
-
},
|
|
489
|
-
...payload.branchId && {
|
|
490
|
-
branchId: payload.branchId
|
|
491
|
-
},
|
|
492
|
-
...payload.companyLogoId && {
|
|
493
|
-
companyLogoId: payload.companyLogoId
|
|
494
|
-
},
|
|
495
|
-
...payload.branchLogoId && {
|
|
496
|
-
branchLogoId: payload.branchLogoId
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
return {
|
|
500
|
-
accessToken: this.jwtService.sign(accessPayload, {
|
|
501
|
-
secret: this.authConfig.getJwtSecret(),
|
|
502
|
-
expiresIn: this.authConfig.getJwtExpiration()
|
|
503
|
-
}),
|
|
504
|
-
refreshToken: this.jwtService.sign(refreshPayload, {
|
|
505
|
-
secret: this.authConfig.getRefreshTokenSecret(),
|
|
506
|
-
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
507
|
-
})
|
|
508
|
-
};
|
|
507
|
+
});
|
|
509
508
|
} catch (error) {
|
|
510
|
-
// Log error details for debugging (not exposed to client)
|
|
511
509
|
_utils.ErrorHandler.logError(this.logger, error, 'refreshToken');
|
|
512
510
|
throw new _common.UnauthorizedException('Invalid or expired refresh token');
|
|
513
511
|
}
|
|
@@ -519,11 +517,8 @@ let AuthenticationService = class AuthenticationService {
|
|
|
519
517
|
id: userId
|
|
520
518
|
}
|
|
521
519
|
});
|
|
522
|
-
if (!user)
|
|
523
|
-
|
|
524
|
-
}
|
|
525
|
-
const isPasswordValid = await _bcrypt.compare(currentPassword, user.password || '');
|
|
526
|
-
if (!isPasswordValid) {
|
|
520
|
+
if (!user) throw new _common.UnauthorizedException('User not found');
|
|
521
|
+
if (!await _bcrypt.compare(currentPassword, user.password || '')) {
|
|
527
522
|
throw new _common.UnauthorizedException('Current password is incorrect');
|
|
528
523
|
}
|
|
529
524
|
user.password = await _bcrypt.hash(newPassword, _config.BCRYPT_SALT_ROUNDS);
|
|
@@ -531,8 +526,9 @@ let AuthenticationService = class AuthenticationService {
|
|
|
531
526
|
}
|
|
532
527
|
/** Logout - Revokes all tokens. Stores revocation timestamp in cache. */ async logout(userId) {
|
|
533
528
|
if (!this.cacheManager) {
|
|
534
|
-
// Cache
|
|
535
|
-
|
|
529
|
+
// Cache is required for secure logout - tokens cannot be revoked without it
|
|
530
|
+
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
|
+
throw new _common.BadRequestException('Logout service temporarily unavailable. Please try again later.');
|
|
536
532
|
}
|
|
537
533
|
const revokedAt = Math.floor(Date.now() / 1000); // Unix timestamp in seconds
|
|
538
534
|
const cacheKey = `${_config.TOKEN_REVOKED_PREFIX}:${userId}`;
|
|
@@ -540,6 +536,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
540
536
|
const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
|
|
541
537
|
const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
|
|
542
538
|
await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
|
|
539
|
+
this.logger.log(`User ${userId} logged out - all tokens revoked`);
|
|
543
540
|
}
|
|
544
541
|
/** Check if a token is revoked (issued before user's revocation timestamp) */ async isTokenRevoked(userId, tokenIssuedAt) {
|
|
545
542
|
if (!this.cacheManager || !tokenIssuedAt) {
|
|
@@ -657,53 +654,28 @@ let AuthenticationService = class AuthenticationService {
|
|
|
657
654
|
id: userId
|
|
658
655
|
}
|
|
659
656
|
});
|
|
660
|
-
if (!user)
|
|
661
|
-
throw new _common.UnauthorizedException('User not found');
|
|
662
|
-
}
|
|
663
|
-
// Build response (no tokens)
|
|
657
|
+
if (!user) throw new _common.UnauthorizedException('User not found');
|
|
664
658
|
const response = {
|
|
665
|
-
user:
|
|
666
|
-
id: user.id,
|
|
667
|
-
email: user.email,
|
|
668
|
-
name: user.name ?? undefined,
|
|
669
|
-
profilePictureId: user.profilePictureId ?? undefined
|
|
670
|
-
}
|
|
659
|
+
user: this.toUserInfo(user)
|
|
671
660
|
};
|
|
672
|
-
|
|
673
|
-
if (this.authConfig.isCompanyFeatureEnabled()) {
|
|
674
|
-
// When company feature is enabled, companyId MUST be present
|
|
661
|
+
if (this.isCompanyFeatureEnabled()) {
|
|
675
662
|
if (!companyId) {
|
|
676
|
-
throw new _common.UnauthorizedException('Company feature is enabled but user has no company assigned.
|
|
663
|
+
throw new _common.UnauthorizedException('Company feature is enabled but user has no company assigned.');
|
|
677
664
|
}
|
|
678
665
|
const company = await this.getCompanyById(companyId);
|
|
679
|
-
if (!company)
|
|
680
|
-
|
|
681
|
-
}
|
|
682
|
-
response.company = {
|
|
683
|
-
id: company.id,
|
|
684
|
-
name: company.name,
|
|
685
|
-
slug: company.slug,
|
|
686
|
-
logoId: company.logoId ?? null
|
|
687
|
-
};
|
|
688
|
-
// Branch is optional in some configurations, but if provided it must exist
|
|
666
|
+
if (!company) throw new _common.UnauthorizedException('Company not found.');
|
|
667
|
+
response.company = this.toCompanyInfo(company);
|
|
689
668
|
if (branchId) {
|
|
690
669
|
const branch = await this.getBranchById(branchId);
|
|
691
|
-
if (!branch)
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
response.branch = {
|
|
695
|
-
id: branch.id,
|
|
696
|
-
name: branch.name,
|
|
697
|
-
slug: branch.slug,
|
|
698
|
-
logoId: branch.logoId ?? null
|
|
699
|
-
};
|
|
670
|
+
if (!branch) throw new _common.UnauthorizedException('Branch not found.');
|
|
671
|
+
response.branch = this.toBranchInfo(branch);
|
|
700
672
|
}
|
|
701
673
|
}
|
|
702
674
|
return response;
|
|
703
675
|
}
|
|
704
676
|
// Helper Methods
|
|
705
677
|
ensureCompanyFeatureEnabled() {
|
|
706
|
-
if (!this.
|
|
678
|
+
if (!this.isCompanyFeatureEnabled()) {
|
|
707
679
|
throw new _common.BadRequestException('Company feature is not enabled');
|
|
708
680
|
}
|
|
709
681
|
}
|
|
@@ -714,11 +686,7 @@ let AuthenticationService = class AuthenticationService {
|
|
|
714
686
|
email
|
|
715
687
|
}
|
|
716
688
|
});
|
|
717
|
-
if (!user) {
|
|
718
|
-
throw new _common.UnauthorizedException('Invalid credentials');
|
|
719
|
-
}
|
|
720
|
-
const isPasswordValid = await _bcrypt.compare(password, user.password || '');
|
|
721
|
-
if (!isPasswordValid) {
|
|
689
|
+
if (!user || !await _bcrypt.compare(password, user.password || '')) {
|
|
722
690
|
throw new _common.UnauthorizedException('Invalid credentials');
|
|
723
691
|
}
|
|
724
692
|
user.lastLoginAt = new Date();
|
|
@@ -726,82 +694,77 @@ let AuthenticationService = class AuthenticationService {
|
|
|
726
694
|
return user;
|
|
727
695
|
}
|
|
728
696
|
// Response Generators
|
|
729
|
-
|
|
730
|
-
|
|
697
|
+
/** Create user info object */ toUserInfo(user) {
|
|
698
|
+
return {
|
|
731
699
|
id: user.id,
|
|
732
700
|
email: user.email,
|
|
733
|
-
|
|
701
|
+
name: user.name ?? undefined,
|
|
702
|
+
phone: user.phone ?? null,
|
|
703
|
+
profilePictureId: user.profilePictureId ?? null
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
/** Create company info object */ toCompanyInfo(company) {
|
|
707
|
+
return {
|
|
708
|
+
id: company.id,
|
|
709
|
+
name: company.name,
|
|
710
|
+
slug: company.slug,
|
|
711
|
+
logoId: company.logoId ?? null
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
/** Create branch info object */ toBranchInfo(branch) {
|
|
715
|
+
return {
|
|
716
|
+
id: branch.id,
|
|
717
|
+
name: branch.name,
|
|
718
|
+
slug: branch.slug,
|
|
719
|
+
logoId: branch.logoId ?? null
|
|
734
720
|
};
|
|
735
|
-
|
|
721
|
+
}
|
|
722
|
+
/** Generate JWT tokens */ generateTokens(payload) {
|
|
723
|
+
const accessToken = this.jwtService.sign({
|
|
724
|
+
...payload,
|
|
725
|
+
type: 'access'
|
|
726
|
+
}, {
|
|
736
727
|
secret: this.authConfig.getJwtSecret(),
|
|
737
728
|
expiresIn: this.authConfig.getJwtExpiration()
|
|
738
729
|
});
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
email: user.email,
|
|
730
|
+
const refreshToken = this.jwtService.sign({
|
|
731
|
+
...payload,
|
|
742
732
|
type: 'refresh'
|
|
743
|
-
}
|
|
744
|
-
const refreshToken = this.jwtService.sign(refreshPayload, {
|
|
733
|
+
}, {
|
|
745
734
|
secret: this.authConfig.getRefreshTokenSecret(),
|
|
746
735
|
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
747
736
|
});
|
|
748
737
|
return {
|
|
749
738
|
accessToken,
|
|
750
|
-
refreshToken
|
|
751
|
-
user: {
|
|
752
|
-
id: user.id,
|
|
753
|
-
email: user.email,
|
|
754
|
-
name: user.name ?? undefined,
|
|
755
|
-
profilePictureId: user.profilePictureId ?? null
|
|
756
|
-
},
|
|
757
|
-
companyFeatureEnabled
|
|
739
|
+
refreshToken
|
|
758
740
|
};
|
|
759
741
|
}
|
|
760
|
-
|
|
761
|
-
const
|
|
742
|
+
generateLoginResponse(user) {
|
|
743
|
+
const { accessToken, refreshToken } = this.generateTokens({
|
|
762
744
|
id: user.id,
|
|
763
745
|
email: user.email,
|
|
764
|
-
type: 'access'
|
|
765
|
-
companyId: company.id,
|
|
766
|
-
branchId: branch?.id
|
|
767
|
-
};
|
|
768
|
-
const accessToken = this.jwtService.sign(payload, {
|
|
769
|
-
secret: this.authConfig.getJwtSecret(),
|
|
770
|
-
expiresIn: this.authConfig.getJwtExpiration()
|
|
746
|
+
type: 'access'
|
|
771
747
|
});
|
|
772
|
-
|
|
748
|
+
return {
|
|
749
|
+
accessToken,
|
|
750
|
+
refreshToken,
|
|
751
|
+
user: this.toUserInfo(user)
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
generateLoginResponseWithCompany(user, company, branch) {
|
|
755
|
+
const { accessToken, refreshToken } = this.generateTokens({
|
|
773
756
|
id: user.id,
|
|
774
757
|
email: user.email,
|
|
775
|
-
type: '
|
|
758
|
+
type: 'access',
|
|
776
759
|
companyId: company.id,
|
|
777
760
|
branchId: branch?.id
|
|
778
|
-
};
|
|
779
|
-
const refreshToken = this.jwtService.sign(refreshPayload, {
|
|
780
|
-
secret: this.authConfig.getRefreshTokenSecret(),
|
|
781
|
-
expiresIn: this.authConfig.getRefreshTokenExpiration()
|
|
782
761
|
});
|
|
783
762
|
return {
|
|
784
763
|
accessToken,
|
|
785
764
|
refreshToken,
|
|
786
|
-
user:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
name: user.name ?? undefined,
|
|
790
|
-
profilePictureId: user.profilePictureId ?? null
|
|
791
|
-
},
|
|
792
|
-
company: {
|
|
793
|
-
id: company.id,
|
|
794
|
-
name: company.name,
|
|
795
|
-
slug: company.slug,
|
|
796
|
-
logoId: company.logoId ?? null
|
|
797
|
-
},
|
|
798
|
-
branch: branch ? {
|
|
799
|
-
id: branch.id,
|
|
800
|
-
name: branch.name,
|
|
801
|
-
slug: branch.slug,
|
|
802
|
-
logoId: branch.logoId ?? null
|
|
803
|
-
} : undefined,
|
|
804
|
-
companyFeatureEnabled: true
|
|
765
|
+
user: this.toUserInfo(user),
|
|
766
|
+
company: this.toCompanyInfo(company),
|
|
767
|
+
branch: branch ? this.toBranchInfo(branch) : undefined
|
|
805
768
|
};
|
|
806
769
|
}
|
|
807
770
|
async generateCompanySelectionResponse(user, companies, branches) {
|
|
@@ -809,55 +772,49 @@ let AuthenticationService = class AuthenticationService {
|
|
|
809
772
|
throw new _common.BadRequestException('Session service not available');
|
|
810
773
|
}
|
|
811
774
|
const sessionId = await this.sessionService.createSession(user.id);
|
|
812
|
-
// Build companies with their branches
|
|
813
775
|
const companiesWithBranches = companies.map((company)=>({
|
|
814
|
-
|
|
815
|
-
name: company.name,
|
|
816
|
-
slug: company.slug,
|
|
776
|
+
...this.toCompanyInfo(company),
|
|
817
777
|
isActive: company.isActive,
|
|
818
|
-
logoId: company.logoId ?? null,
|
|
819
778
|
branches: branches.filter((b)=>b.companyId === company.id).map((b)=>({
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
slug: b.slug,
|
|
823
|
-
isActive: b.isActive,
|
|
824
|
-
logoId: b.logoId ?? null
|
|
779
|
+
...this.toBranchInfo(b),
|
|
780
|
+
isActive: b.isActive
|
|
825
781
|
}))
|
|
826
782
|
}));
|
|
827
783
|
return {
|
|
828
784
|
requiresSelection: true,
|
|
829
785
|
sessionId,
|
|
830
786
|
expiresAt: new Date(Date.now() + 5 * 60 * 1000),
|
|
831
|
-
user:
|
|
832
|
-
id: user.id,
|
|
833
|
-
email: user.email,
|
|
834
|
-
name: user.name ?? undefined,
|
|
835
|
-
profilePictureId: user.profilePictureId ?? null
|
|
836
|
-
},
|
|
787
|
+
user: this.toUserInfo(user),
|
|
837
788
|
companies: companiesWithBranches
|
|
838
789
|
};
|
|
839
790
|
}
|
|
791
|
+
generateRegistrationResponse(user) {
|
|
792
|
+
return {
|
|
793
|
+
...this.generateLoginResponse(user),
|
|
794
|
+
requiresEmailVerification: false
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
generateRegistrationResponseWithCompany(user, company, branch) {
|
|
798
|
+
return {
|
|
799
|
+
...this.generateLoginResponseWithCompany(user, company, branch),
|
|
800
|
+
requiresEmailVerification: false
|
|
801
|
+
};
|
|
802
|
+
}
|
|
840
803
|
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
841
|
-
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService,
|
|
804
|
+
constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService){
|
|
842
805
|
_define_property(this, "jwtService", void 0);
|
|
843
806
|
_define_property(this, "authConfig", void 0);
|
|
844
807
|
_define_property(this, "cacheManager", void 0);
|
|
845
808
|
_define_property(this, "dataSourceProvider", void 0);
|
|
846
809
|
_define_property(this, "sessionService", void 0);
|
|
847
|
-
_define_property(this, "
|
|
848
|
-
_define_property(this, "injectedPermissionRepository", void 0);
|
|
849
|
-
_define_property(this, "injectedCompanyRepository", void 0);
|
|
850
|
-
_define_property(this, "injectedBranchRepository", void 0);
|
|
810
|
+
_define_property(this, "authEmailService", void 0);
|
|
851
811
|
_define_property(this, "logger", void 0);
|
|
852
812
|
this.jwtService = jwtService;
|
|
853
813
|
this.authConfig = authConfig;
|
|
854
814
|
this.cacheManager = cacheManager;
|
|
855
815
|
this.dataSourceProvider = dataSourceProvider;
|
|
856
816
|
this.sessionService = sessionService;
|
|
857
|
-
this.
|
|
858
|
-
this.injectedPermissionRepository = injectedPermissionRepository;
|
|
859
|
-
this.injectedCompanyRepository = injectedCompanyRepository;
|
|
860
|
-
this.injectedBranchRepository = injectedBranchRepository;
|
|
817
|
+
this.authEmailService = authEmailService;
|
|
861
818
|
this.logger = new _common.Logger(AuthenticationService.name);
|
|
862
819
|
}
|
|
863
820
|
};
|
|
@@ -874,13 +831,7 @@ AuthenticationService = _ts_decorate([
|
|
|
874
831
|
_ts_param(4, (0, _common.Optional)()),
|
|
875
832
|
_ts_param(4, (0, _common.Inject)(_companyselectionsessionservice.CompanySelectionSessionService)),
|
|
876
833
|
_ts_param(5, (0, _common.Optional)()),
|
|
877
|
-
_ts_param(5, (0,
|
|
878
|
-
_ts_param(6, (0, _common.Optional)()),
|
|
879
|
-
_ts_param(6, (0, _typeorm.InjectRepository)(_usercompanypermissionentity.UserCompanyPermission)),
|
|
880
|
-
_ts_param(7, (0, _common.Optional)()),
|
|
881
|
-
_ts_param(7, (0, _typeorm.InjectRepository)(_companyentity.Company)),
|
|
882
|
-
_ts_param(8, (0, _common.Optional)()),
|
|
883
|
-
_ts_param(8, (0, _typeorm.InjectRepository)(_companybranchentity.CompanyBranch)),
|
|
834
|
+
_ts_param(5, (0, _common.Inject)(_authemailservice.AuthEmailService)),
|
|
884
835
|
_ts_metadata("design:type", Function),
|
|
885
836
|
_ts_metadata("design:paramtypes", [
|
|
886
837
|
typeof _jwt.JwtService === "undefined" ? Object : _jwt.JwtService,
|
|
@@ -888,9 +839,6 @@ AuthenticationService = _ts_decorate([
|
|
|
888
839
|
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
889
840
|
typeof _authdatasourceprovider.AuthDataSourceProvider === "undefined" ? Object : _authdatasourceprovider.AuthDataSourceProvider,
|
|
890
841
|
typeof _companyselectionsessionservice.CompanySelectionSessionService === "undefined" ? Object : _companyselectionsessionservice.CompanySelectionSessionService,
|
|
891
|
-
typeof
|
|
892
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
|
|
893
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
|
|
894
|
-
typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository
|
|
842
|
+
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService
|
|
895
843
|
])
|
|
896
844
|
], AuthenticationService);
|