@flusys/nestjs-auth 6.3.0 → 6.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -130,10 +130,13 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
130
130
|
await this.repository.update(id, {
|
|
131
131
|
emailVerified: true
|
|
132
132
|
});
|
|
133
|
-
await
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
await Promise.all([
|
|
134
|
+
this.clearCacheForAll(),
|
|
135
|
+
this.clearCacheForId([
|
|
136
|
+
{
|
|
137
|
+
id
|
|
138
|
+
}
|
|
139
|
+
])
|
|
137
140
|
]);
|
|
138
141
|
}
|
|
139
142
|
async verifyPhone(id) {
|
|
@@ -141,10 +144,13 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
141
144
|
await this.repository.update(id, {
|
|
142
145
|
phoneVerified: true
|
|
143
146
|
});
|
|
144
|
-
await
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
await Promise.all([
|
|
148
|
+
this.clearCacheForAll(),
|
|
149
|
+
this.clearCacheForId([
|
|
150
|
+
{
|
|
151
|
+
id
|
|
152
|
+
}
|
|
153
|
+
])
|
|
148
154
|
]);
|
|
149
155
|
}
|
|
150
156
|
async updateStatus(id, isActive, user) {
|
|
@@ -174,10 +180,13 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
174
180
|
isActive
|
|
175
181
|
});
|
|
176
182
|
}
|
|
177
|
-
await
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
await Promise.all([
|
|
184
|
+
this.clearCacheForAll(),
|
|
185
|
+
this.clearCacheForId([
|
|
186
|
+
{
|
|
187
|
+
id
|
|
188
|
+
}
|
|
189
|
+
])
|
|
181
190
|
]);
|
|
182
191
|
}
|
|
183
192
|
async convertSingleDtoToEntity(dto, user) {
|
|
@@ -401,8 +410,11 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
401
410
|
}
|
|
402
411
|
}
|
|
403
412
|
await queryRunner.commitTransaction();
|
|
404
|
-
await
|
|
405
|
-
|
|
413
|
+
await Promise.all([
|
|
414
|
+
this.clearCacheForAll(),
|
|
415
|
+
this.clearCacheForId([
|
|
416
|
+
savedUser
|
|
417
|
+
])
|
|
406
418
|
]);
|
|
407
419
|
return this.convertEntityToResponseDto(savedUser, false);
|
|
408
420
|
} catch (error) {
|
|
@@ -471,8 +483,11 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
471
483
|
try {
|
|
472
484
|
await this.userEnricher.updateProfileSection(userId, sectionId, data, queryRunner);
|
|
473
485
|
await queryRunner.commitTransaction();
|
|
474
|
-
await
|
|
475
|
-
|
|
486
|
+
await Promise.all([
|
|
487
|
+
this.clearCacheForAll(),
|
|
488
|
+
this.clearCacheForId([
|
|
489
|
+
userEntity
|
|
490
|
+
])
|
|
476
491
|
]);
|
|
477
492
|
} catch (error) {
|
|
478
493
|
await queryRunner.rollbackTransaction();
|
|
@@ -541,8 +556,11 @@ let UserService = class UserService extends _classes.ApiService {
|
|
|
541
556
|
await this.userEnricher.updateProfileExtras(userId, extras, queryRunner);
|
|
542
557
|
}
|
|
543
558
|
await queryRunner.commitTransaction();
|
|
544
|
-
await
|
|
545
|
-
|
|
559
|
+
await Promise.all([
|
|
560
|
+
this.clearCacheForAll(),
|
|
561
|
+
this.clearCacheForId([
|
|
562
|
+
findUser
|
|
563
|
+
])
|
|
546
564
|
]);
|
|
547
565
|
return findUser.id;
|
|
548
566
|
} catch (error) {
|
|
@@ -124,6 +124,13 @@ describe('UserService', ()=>{
|
|
|
124
124
|
};
|
|
125
125
|
service = new _userservice.UserService({}, mockUtilsService, mockDataSourceProvider, mockAuthConfig, mockUserEnricher);
|
|
126
126
|
});
|
|
127
|
+
/**
|
|
128
|
+
* Every write path has to drop both the list cache and the row's own cache, or a
|
|
129
|
+
* stale user keeps being served from `get-all`.
|
|
130
|
+
*/ function expectCacheCleared(id) {
|
|
131
|
+
expect(mockUtilsService.clearCache).toHaveBeenCalledWith('appuser', expect.anything());
|
|
132
|
+
expect(mockUtilsService.clearCache).toHaveBeenCalledWith('appuser', expect.anything(), id);
|
|
133
|
+
}
|
|
127
134
|
describe('ensureDataSourceRepository', ()=>{
|
|
128
135
|
it('does not load the permission repository when the company feature is disabled', async ()=>{
|
|
129
136
|
await service.ensureDataSourceRepository();
|
|
@@ -142,13 +149,14 @@ describe('UserService', ()=>{
|
|
|
142
149
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
143
150
|
emailVerified: true
|
|
144
151
|
});
|
|
145
|
-
|
|
152
|
+
expectCacheCleared('user-1');
|
|
146
153
|
});
|
|
147
154
|
it('marks the phone as verified and clears the cache', async ()=>{
|
|
148
155
|
await service.verifyPhone('user-1');
|
|
149
156
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
150
157
|
phoneVerified: true
|
|
151
158
|
});
|
|
159
|
+
expectCacheCleared('user-1');
|
|
152
160
|
});
|
|
153
161
|
});
|
|
154
162
|
describe('updateStatus', ()=>{
|
|
@@ -157,6 +165,7 @@ describe('UserService', ()=>{
|
|
|
157
165
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
158
166
|
isActive: false
|
|
159
167
|
});
|
|
168
|
+
expectCacheCleared('user-1');
|
|
160
169
|
});
|
|
161
170
|
it('throws NotFoundException when the company permission is missing', async ()=>{
|
|
162
171
|
companyFeatureEnabled = true;
|
|
@@ -179,6 +188,7 @@ describe('UserService', ()=>{
|
|
|
179
188
|
isActive: false
|
|
180
189
|
}));
|
|
181
190
|
expect(userRepo.update).not.toHaveBeenCalled();
|
|
191
|
+
expectCacheCleared('user-1');
|
|
182
192
|
});
|
|
183
193
|
});
|
|
184
194
|
describe('convertSingleDtoToEntity', ()=>{
|
|
@@ -389,6 +399,7 @@ describe('UserService', ()=>{
|
|
|
389
399
|
expect(result).toEqual(expect.objectContaining({
|
|
390
400
|
id: 'user-1'
|
|
391
401
|
}));
|
|
402
|
+
expectCacheCleared(savedUser.id);
|
|
392
403
|
});
|
|
393
404
|
it('rolls back the transaction if permission assignment fails', async ()=>{
|
|
394
405
|
companyFeatureEnabled = true;
|
|
@@ -577,6 +588,7 @@ describe('UserService', ()=>{
|
|
|
577
588
|
foo: 'bar'
|
|
578
589
|
}, queryRunner);
|
|
579
590
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
591
|
+
expectCacheCleared('user-1');
|
|
580
592
|
});
|
|
581
593
|
it('rolls back the transaction when the enricher throws', async ()=>{
|
|
582
594
|
userRepo.findOne.mockResolvedValue(buildAppUser());
|
|
@@ -670,6 +682,7 @@ describe('UserService', ()=>{
|
|
|
670
682
|
expect(queryRunner.manager.save).toHaveBeenCalled();
|
|
671
683
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
672
684
|
expect(result).toBe('user-1');
|
|
685
|
+
expectCacheCleared('user-1');
|
|
673
686
|
});
|
|
674
687
|
it('does not require the current password when an admin updates another user profile', async ()=>{
|
|
675
688
|
service.dataSource = mockDataSource;
|
|
@@ -686,6 +699,7 @@ describe('UserService', ()=>{
|
|
|
686
699
|
}));
|
|
687
700
|
expect(queryRunner.manager.save).toHaveBeenCalled();
|
|
688
701
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
702
|
+
expectCacheCleared('other-user');
|
|
689
703
|
});
|
|
690
704
|
it('rolls back the transaction when save fails', async ()=>{
|
|
691
705
|
service.dataSource = mockDataSource;
|
|
@@ -79,10 +79,13 @@ export class UserService extends ApiService {
|
|
|
79
79
|
await this.repository.update(id, {
|
|
80
80
|
emailVerified: true
|
|
81
81
|
});
|
|
82
|
-
await
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
await Promise.all([
|
|
83
|
+
this.clearCacheForAll(),
|
|
84
|
+
this.clearCacheForId([
|
|
85
|
+
{
|
|
86
|
+
id
|
|
87
|
+
}
|
|
88
|
+
])
|
|
86
89
|
]);
|
|
87
90
|
}
|
|
88
91
|
async verifyPhone(id) {
|
|
@@ -90,10 +93,13 @@ export class UserService extends ApiService {
|
|
|
90
93
|
await this.repository.update(id, {
|
|
91
94
|
phoneVerified: true
|
|
92
95
|
});
|
|
93
|
-
await
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
await Promise.all([
|
|
97
|
+
this.clearCacheForAll(),
|
|
98
|
+
this.clearCacheForId([
|
|
99
|
+
{
|
|
100
|
+
id
|
|
101
|
+
}
|
|
102
|
+
])
|
|
97
103
|
]);
|
|
98
104
|
}
|
|
99
105
|
async updateStatus(id, isActive, user) {
|
|
@@ -123,10 +129,13 @@ export class UserService extends ApiService {
|
|
|
123
129
|
isActive
|
|
124
130
|
});
|
|
125
131
|
}
|
|
126
|
-
await
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
await Promise.all([
|
|
133
|
+
this.clearCacheForAll(),
|
|
134
|
+
this.clearCacheForId([
|
|
135
|
+
{
|
|
136
|
+
id
|
|
137
|
+
}
|
|
138
|
+
])
|
|
130
139
|
]);
|
|
131
140
|
}
|
|
132
141
|
async convertSingleDtoToEntity(dto, user) {
|
|
@@ -350,8 +359,11 @@ export class UserService extends ApiService {
|
|
|
350
359
|
}
|
|
351
360
|
}
|
|
352
361
|
await queryRunner.commitTransaction();
|
|
353
|
-
await
|
|
354
|
-
|
|
362
|
+
await Promise.all([
|
|
363
|
+
this.clearCacheForAll(),
|
|
364
|
+
this.clearCacheForId([
|
|
365
|
+
savedUser
|
|
366
|
+
])
|
|
355
367
|
]);
|
|
356
368
|
return this.convertEntityToResponseDto(savedUser, false);
|
|
357
369
|
} catch (error) {
|
|
@@ -420,8 +432,11 @@ export class UserService extends ApiService {
|
|
|
420
432
|
try {
|
|
421
433
|
await this.userEnricher.updateProfileSection(userId, sectionId, data, queryRunner);
|
|
422
434
|
await queryRunner.commitTransaction();
|
|
423
|
-
await
|
|
424
|
-
|
|
435
|
+
await Promise.all([
|
|
436
|
+
this.clearCacheForAll(),
|
|
437
|
+
this.clearCacheForId([
|
|
438
|
+
userEntity
|
|
439
|
+
])
|
|
425
440
|
]);
|
|
426
441
|
} catch (error) {
|
|
427
442
|
await queryRunner.rollbackTransaction();
|
|
@@ -490,8 +505,11 @@ export class UserService extends ApiService {
|
|
|
490
505
|
await this.userEnricher.updateProfileExtras(userId, extras, queryRunner);
|
|
491
506
|
}
|
|
492
507
|
await queryRunner.commitTransaction();
|
|
493
|
-
await
|
|
494
|
-
|
|
508
|
+
await Promise.all([
|
|
509
|
+
this.clearCacheForAll(),
|
|
510
|
+
this.clearCacheForId([
|
|
511
|
+
findUser
|
|
512
|
+
])
|
|
495
513
|
]);
|
|
496
514
|
return findUser.id;
|
|
497
515
|
} catch (error) {
|
|
@@ -79,6 +79,13 @@ describe('UserService', ()=>{
|
|
|
79
79
|
};
|
|
80
80
|
service = new UserService({}, mockUtilsService, mockDataSourceProvider, mockAuthConfig, mockUserEnricher);
|
|
81
81
|
});
|
|
82
|
+
/**
|
|
83
|
+
* Every write path has to drop both the list cache and the row's own cache, or a
|
|
84
|
+
* stale user keeps being served from `get-all`.
|
|
85
|
+
*/ function expectCacheCleared(id) {
|
|
86
|
+
expect(mockUtilsService.clearCache).toHaveBeenCalledWith('appuser', expect.anything());
|
|
87
|
+
expect(mockUtilsService.clearCache).toHaveBeenCalledWith('appuser', expect.anything(), id);
|
|
88
|
+
}
|
|
82
89
|
describe('ensureDataSourceRepository', ()=>{
|
|
83
90
|
it('does not load the permission repository when the company feature is disabled', async ()=>{
|
|
84
91
|
await service.ensureDataSourceRepository();
|
|
@@ -97,13 +104,14 @@ describe('UserService', ()=>{
|
|
|
97
104
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
98
105
|
emailVerified: true
|
|
99
106
|
});
|
|
100
|
-
|
|
107
|
+
expectCacheCleared('user-1');
|
|
101
108
|
});
|
|
102
109
|
it('marks the phone as verified and clears the cache', async ()=>{
|
|
103
110
|
await service.verifyPhone('user-1');
|
|
104
111
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
105
112
|
phoneVerified: true
|
|
106
113
|
});
|
|
114
|
+
expectCacheCleared('user-1');
|
|
107
115
|
});
|
|
108
116
|
});
|
|
109
117
|
describe('updateStatus', ()=>{
|
|
@@ -112,6 +120,7 @@ describe('UserService', ()=>{
|
|
|
112
120
|
expect(userRepo.update).toHaveBeenCalledWith('user-1', {
|
|
113
121
|
isActive: false
|
|
114
122
|
});
|
|
123
|
+
expectCacheCleared('user-1');
|
|
115
124
|
});
|
|
116
125
|
it('throws NotFoundException when the company permission is missing', async ()=>{
|
|
117
126
|
companyFeatureEnabled = true;
|
|
@@ -134,6 +143,7 @@ describe('UserService', ()=>{
|
|
|
134
143
|
isActive: false
|
|
135
144
|
}));
|
|
136
145
|
expect(userRepo.update).not.toHaveBeenCalled();
|
|
146
|
+
expectCacheCleared('user-1');
|
|
137
147
|
});
|
|
138
148
|
});
|
|
139
149
|
describe('convertSingleDtoToEntity', ()=>{
|
|
@@ -344,6 +354,7 @@ describe('UserService', ()=>{
|
|
|
344
354
|
expect(result).toEqual(expect.objectContaining({
|
|
345
355
|
id: 'user-1'
|
|
346
356
|
}));
|
|
357
|
+
expectCacheCleared(savedUser.id);
|
|
347
358
|
});
|
|
348
359
|
it('rolls back the transaction if permission assignment fails', async ()=>{
|
|
349
360
|
companyFeatureEnabled = true;
|
|
@@ -532,6 +543,7 @@ describe('UserService', ()=>{
|
|
|
532
543
|
foo: 'bar'
|
|
533
544
|
}, queryRunner);
|
|
534
545
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
546
|
+
expectCacheCleared('user-1');
|
|
535
547
|
});
|
|
536
548
|
it('rolls back the transaction when the enricher throws', async ()=>{
|
|
537
549
|
userRepo.findOne.mockResolvedValue(buildAppUser());
|
|
@@ -625,6 +637,7 @@ describe('UserService', ()=>{
|
|
|
625
637
|
expect(queryRunner.manager.save).toHaveBeenCalled();
|
|
626
638
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
627
639
|
expect(result).toBe('user-1');
|
|
640
|
+
expectCacheCleared('user-1');
|
|
628
641
|
});
|
|
629
642
|
it('does not require the current password when an admin updates another user profile', async ()=>{
|
|
630
643
|
service.dataSource = mockDataSource;
|
|
@@ -641,6 +654,7 @@ describe('UserService', ()=>{
|
|
|
641
654
|
}));
|
|
642
655
|
expect(queryRunner.manager.save).toHaveBeenCalled();
|
|
643
656
|
expect(queryRunner.commitTransaction).toHaveBeenCalled();
|
|
657
|
+
expectCacheCleared('other-user');
|
|
644
658
|
});
|
|
645
659
|
it('rolls back the transaction when save fails', async ()=>{
|
|
646
660
|
service.dataSource = mockDataSource;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-auth",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.1",
|
|
4
4
|
"description": "Authentication and authorization infrastructure for NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"rxjs": "^7.8.0"
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
|
-
"@flusys/nestjs-core": "6.
|
|
102
|
-
"@flusys/nestjs-shared": "6.
|
|
101
|
+
"@flusys/nestjs-core": "6.4.1",
|
|
102
|
+
"@flusys/nestjs-shared": "6.4.1"
|
|
103
103
|
}
|
|
104
104
|
}
|