@ciscode/authentication-kit 1.2.0 → 1.4.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 +13 -3
- package/dist/auth-kit.module.js +9 -0
- package/dist/dtos/auth/register.dto.d.ts +3 -1
- package/dist/dtos/auth/register.dto.js +11 -0
- package/dist/filters/http-exception.filter.d.ts +5 -0
- package/dist/filters/http-exception.filter.js +89 -0
- package/dist/middleware/authenticate.guard.d.ts +3 -1
- package/dist/middleware/authenticate.guard.js +30 -18
- package/dist/models/user.model.d.ts +2 -0
- package/dist/models/user.model.js +8 -0
- package/dist/services/admin-role.service.d.ts +3 -1
- package/dist/services/admin-role.service.js +22 -8
- package/dist/services/auth.service.d.ts +8 -1
- package/dist/services/auth.service.js +270 -106
- package/dist/services/logger.service.d.ts +8 -0
- package/dist/services/logger.service.js +38 -0
- package/dist/services/mail.service.d.ts +3 -0
- package/dist/services/mail.service.js +49 -17
- package/dist/services/oauth.service.d.ts +4 -1
- package/dist/services/oauth.service.js +175 -71
- package/dist/services/permissions.service.d.ts +3 -1
- package/dist/services/permissions.service.js +56 -14
- package/dist/services/roles.service.d.ts +3 -1
- package/dist/services/roles.service.js +76 -24
- package/dist/services/users.service.d.ts +3 -1
- package/dist/services/users.service.js +109 -40
- package/dist/utils/helper.d.ts +1 -0
- package/dist/utils/helper.js +4 -0
- package/package.json +1 -1
|
@@ -20,22 +20,30 @@ const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
|
|
|
20
20
|
const user_repository_1 = require("../repositories/user.repository");
|
|
21
21
|
const role_repository_1 = require("../repositories/role.repository");
|
|
22
22
|
const auth_service_1 = require("./auth.service");
|
|
23
|
+
const logger_service_1 = require("./logger.service");
|
|
23
24
|
let OAuthService = class OAuthService {
|
|
24
|
-
constructor(users, roles, auth) {
|
|
25
|
+
constructor(users, roles, auth, logger) {
|
|
25
26
|
this.users = users;
|
|
26
27
|
this.roles = roles;
|
|
27
28
|
this.auth = auth;
|
|
29
|
+
this.logger = logger;
|
|
28
30
|
this.msJwks = (0, jwks_rsa_1.default)({
|
|
29
31
|
jwksUri: 'https://login.microsoftonline.com/common/discovery/v2.0/keys',
|
|
30
32
|
cache: true,
|
|
31
33
|
rateLimit: true,
|
|
32
34
|
jwksRequestsPerMinute: 5,
|
|
33
35
|
});
|
|
36
|
+
// Configure axios with timeout
|
|
37
|
+
this.axiosConfig = {
|
|
38
|
+
timeout: 10000, // 10 seconds
|
|
39
|
+
};
|
|
34
40
|
}
|
|
35
41
|
async getDefaultRoleId() {
|
|
36
42
|
const role = await this.roles.findByName('user');
|
|
37
|
-
if (!role)
|
|
38
|
-
|
|
43
|
+
if (!role) {
|
|
44
|
+
this.logger.error('Default user role not found - seed data missing', 'OAuthService');
|
|
45
|
+
throw new common_1.InternalServerErrorException('System configuration error');
|
|
46
|
+
}
|
|
39
47
|
return role._id;
|
|
40
48
|
}
|
|
41
49
|
verifyMicrosoftIdToken(idToken) {
|
|
@@ -44,89 +52,184 @@ let OAuthService = class OAuthService {
|
|
|
44
52
|
this.msJwks
|
|
45
53
|
.getSigningKey(header.kid)
|
|
46
54
|
.then((k) => cb(null, k.getPublicKey()))
|
|
47
|
-
.catch(
|
|
55
|
+
.catch((err) => {
|
|
56
|
+
this.logger.error(`Failed to get Microsoft signing key: ${err.message}`, err.stack, 'OAuthService');
|
|
57
|
+
cb(err);
|
|
58
|
+
});
|
|
48
59
|
};
|
|
49
|
-
jsonwebtoken_1.default.verify(idToken, getKey, { algorithms: ['RS256'], audience: process.env.MICROSOFT_CLIENT_ID }, (err, payload) =>
|
|
60
|
+
jsonwebtoken_1.default.verify(idToken, getKey, { algorithms: ['RS256'], audience: process.env.MICROSOFT_CLIENT_ID }, (err, payload) => {
|
|
61
|
+
if (err) {
|
|
62
|
+
this.logger.error(`Microsoft token verification failed: ${err.message}`, err.stack, 'OAuthService');
|
|
63
|
+
reject(new common_1.UnauthorizedException('Invalid Microsoft token'));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
resolve(payload);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
50
69
|
});
|
|
51
70
|
}
|
|
52
71
|
async loginWithMicrosoft(idToken) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
try {
|
|
73
|
+
const ms = await this.verifyMicrosoftIdToken(idToken);
|
|
74
|
+
const email = ms.preferred_username || ms.email;
|
|
75
|
+
if (!email) {
|
|
76
|
+
throw new common_1.BadRequestException('Email not provided by Microsoft');
|
|
77
|
+
}
|
|
78
|
+
return this.findOrCreateOAuthUser(email, ms.name);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof common_1.UnauthorizedException || error instanceof common_1.BadRequestException) {
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
this.logger.error(`Microsoft login failed: ${error.message}`, error.stack, 'OAuthService');
|
|
85
|
+
throw new common_1.UnauthorizedException('Microsoft authentication failed');
|
|
86
|
+
}
|
|
58
87
|
}
|
|
59
88
|
async loginWithGoogleIdToken(idToken) {
|
|
60
89
|
var _a, _b;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
try {
|
|
91
|
+
const verifyResp = await axios_1.default.get('https://oauth2.googleapis.com/tokeninfo', {
|
|
92
|
+
params: { id_token: idToken },
|
|
93
|
+
...this.axiosConfig,
|
|
94
|
+
});
|
|
95
|
+
const email = (_a = verifyResp.data) === null || _a === void 0 ? void 0 : _a.email;
|
|
96
|
+
if (!email) {
|
|
97
|
+
throw new common_1.BadRequestException('Email not provided by Google');
|
|
98
|
+
}
|
|
99
|
+
return this.findOrCreateOAuthUser(email, (_b = verifyResp.data) === null || _b === void 0 ? void 0 : _b.name);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (error instanceof common_1.BadRequestException) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
const axiosError = error;
|
|
106
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
107
|
+
this.logger.error('Google API timeout', axiosError.stack, 'OAuthService');
|
|
108
|
+
throw new common_1.InternalServerErrorException('Authentication service timeout');
|
|
109
|
+
}
|
|
110
|
+
this.logger.error(`Google ID token login failed: ${error.message}`, error.stack, 'OAuthService');
|
|
111
|
+
throw new common_1.UnauthorizedException('Google authentication failed');
|
|
112
|
+
}
|
|
68
113
|
}
|
|
69
114
|
async loginWithGoogleCode(code) {
|
|
70
115
|
var _a, _b;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
116
|
+
try {
|
|
117
|
+
const tokenResp = await axios_1.default.post('https://oauth2.googleapis.com/token', {
|
|
118
|
+
code,
|
|
119
|
+
client_id: process.env.GOOGLE_CLIENT_ID,
|
|
120
|
+
client_secret: process.env.GOOGLE_CLIENT_SECRET,
|
|
121
|
+
redirect_uri: 'postmessage',
|
|
122
|
+
grant_type: 'authorization_code',
|
|
123
|
+
}, this.axiosConfig);
|
|
124
|
+
const { access_token } = tokenResp.data || {};
|
|
125
|
+
if (!access_token) {
|
|
126
|
+
throw new common_1.BadRequestException('Failed to exchange authorization code');
|
|
127
|
+
}
|
|
128
|
+
const profileResp = await axios_1.default.get('https://www.googleapis.com/oauth2/v2/userinfo', {
|
|
129
|
+
headers: { Authorization: `Bearer ${access_token}` },
|
|
130
|
+
...this.axiosConfig,
|
|
131
|
+
});
|
|
132
|
+
const email = (_a = profileResp.data) === null || _a === void 0 ? void 0 : _a.email;
|
|
133
|
+
if (!email) {
|
|
134
|
+
throw new common_1.BadRequestException('Email not provided by Google');
|
|
135
|
+
}
|
|
136
|
+
return this.findOrCreateOAuthUser(email, (_b = profileResp.data) === null || _b === void 0 ? void 0 : _b.name);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (error instanceof common_1.BadRequestException) {
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
const axiosError = error;
|
|
143
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
144
|
+
this.logger.error('Google API timeout', axiosError.stack, 'OAuthService');
|
|
145
|
+
throw new common_1.InternalServerErrorException('Authentication service timeout');
|
|
146
|
+
}
|
|
147
|
+
this.logger.error(`Google code exchange failed: ${error.message}`, error.stack, 'OAuthService');
|
|
148
|
+
throw new common_1.UnauthorizedException('Google authentication failed');
|
|
149
|
+
}
|
|
88
150
|
}
|
|
89
151
|
async loginWithFacebook(accessToken) {
|
|
90
152
|
var _a, _b, _c, _d, _e;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
153
|
+
try {
|
|
154
|
+
const appTokenResp = await axios_1.default.get('https://graph.facebook.com/oauth/access_token', {
|
|
155
|
+
params: {
|
|
156
|
+
client_id: process.env.FB_CLIENT_ID,
|
|
157
|
+
client_secret: process.env.FB_CLIENT_SECRET,
|
|
158
|
+
grant_type: 'client_credentials',
|
|
159
|
+
},
|
|
160
|
+
...this.axiosConfig,
|
|
161
|
+
});
|
|
162
|
+
const appAccessToken = (_a = appTokenResp.data) === null || _a === void 0 ? void 0 : _a.access_token;
|
|
163
|
+
if (!appAccessToken) {
|
|
164
|
+
throw new common_1.InternalServerErrorException('Failed to get Facebook app token');
|
|
165
|
+
}
|
|
166
|
+
const debug = await axios_1.default.get('https://graph.facebook.com/debug_token', {
|
|
167
|
+
params: { input_token: accessToken, access_token: appAccessToken },
|
|
168
|
+
...this.axiosConfig,
|
|
169
|
+
});
|
|
170
|
+
if (!((_c = (_b = debug.data) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.is_valid)) {
|
|
171
|
+
throw new common_1.UnauthorizedException('Invalid Facebook access token');
|
|
172
|
+
}
|
|
173
|
+
const me = await axios_1.default.get('https://graph.facebook.com/me', {
|
|
174
|
+
params: { access_token: accessToken, fields: 'id,name,email' },
|
|
175
|
+
...this.axiosConfig,
|
|
176
|
+
});
|
|
177
|
+
const email = (_d = me.data) === null || _d === void 0 ? void 0 : _d.email;
|
|
178
|
+
if (!email) {
|
|
179
|
+
throw new common_1.BadRequestException('Email not provided by Facebook');
|
|
180
|
+
}
|
|
181
|
+
return this.findOrCreateOAuthUser(email, (_e = me.data) === null || _e === void 0 ? void 0 : _e.name);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error instanceof common_1.UnauthorizedException || error instanceof common_1.BadRequestException || error instanceof common_1.InternalServerErrorException) {
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
const axiosError = error;
|
|
188
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
189
|
+
this.logger.error('Facebook API timeout', axiosError.stack, 'OAuthService');
|
|
190
|
+
throw new common_1.InternalServerErrorException('Authentication service timeout');
|
|
191
|
+
}
|
|
192
|
+
this.logger.error(`Facebook login failed: ${error.message}`, error.stack, 'OAuthService');
|
|
193
|
+
throw new common_1.UnauthorizedException('Facebook authentication failed');
|
|
194
|
+
}
|
|
111
195
|
}
|
|
112
196
|
async findOrCreateOAuthUser(email, name) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
197
|
+
try {
|
|
198
|
+
let user = await this.users.findByEmail(email);
|
|
199
|
+
if (!user) {
|
|
200
|
+
const [fname, ...rest] = (name || 'User OAuth').split(' ');
|
|
201
|
+
const lname = rest.join(' ') || 'OAuth';
|
|
202
|
+
const defaultRoleId = await this.getDefaultRoleId();
|
|
203
|
+
user = await this.users.create({
|
|
204
|
+
fullname: { fname, lname },
|
|
205
|
+
username: email.split('@')[0],
|
|
206
|
+
email,
|
|
207
|
+
roles: [defaultRoleId],
|
|
208
|
+
isVerified: true,
|
|
209
|
+
isBanned: false,
|
|
210
|
+
passwordChangedAt: new Date()
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const { accessToken, refreshToken } = await this.auth.issueTokensForUser(user._id.toString());
|
|
214
|
+
return { accessToken, refreshToken };
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === 11000) {
|
|
218
|
+
// Race condition - user was created between check and insert, retry once
|
|
219
|
+
try {
|
|
220
|
+
const user = await this.users.findByEmail(email);
|
|
221
|
+
if (user) {
|
|
222
|
+
const { accessToken, refreshToken } = await this.auth.issueTokensForUser(user._id.toString());
|
|
223
|
+
return { accessToken, refreshToken };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (retryError) {
|
|
227
|
+
this.logger.error(`OAuth user retry failed: ${retryError.message}`, retryError.stack, 'OAuthService');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this.logger.error(`OAuth user creation/login failed: ${error.message}`, error.stack, 'OAuthService');
|
|
231
|
+
throw new common_1.InternalServerErrorException('Authentication failed');
|
|
127
232
|
}
|
|
128
|
-
const { accessToken, refreshToken } = await this.auth.issueTokensForUser(user._id.toString());
|
|
129
|
-
return { accessToken, refreshToken };
|
|
130
233
|
}
|
|
131
234
|
};
|
|
132
235
|
exports.OAuthService = OAuthService;
|
|
@@ -134,5 +237,6 @@ exports.OAuthService = OAuthService = __decorate([
|
|
|
134
237
|
(0, common_1.Injectable)(),
|
|
135
238
|
__metadata("design:paramtypes", [user_repository_1.UserRepository,
|
|
136
239
|
role_repository_1.RoleRepository,
|
|
137
|
-
auth_service_1.AuthService
|
|
240
|
+
auth_service_1.AuthService,
|
|
241
|
+
logger_service_1.LoggerService])
|
|
138
242
|
], OAuthService);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { PermissionRepository } from '../repositories/permission.repository';
|
|
2
2
|
import { CreatePermissionDto } from '../dtos/permission/create-permission.dto';
|
|
3
3
|
import { UpdatePermissionDto } from '../dtos/permission/update-permission.dto';
|
|
4
|
+
import { LoggerService } from './logger.service';
|
|
4
5
|
export declare class PermissionsService {
|
|
5
6
|
private readonly perms;
|
|
6
|
-
|
|
7
|
+
private readonly logger;
|
|
8
|
+
constructor(perms: PermissionRepository, logger: LoggerService);
|
|
7
9
|
create(dto: CreatePermissionDto): Promise<import("mongoose").Document<unknown, {}, import("../models/permission.model").PermissionDocument> & import("../models/permission.model").Permission & import("mongoose").Document<any, any, any> & {
|
|
8
10
|
_id: import("mongoose").Types.ObjectId;
|
|
9
11
|
}>;
|
|
@@ -12,33 +12,75 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.PermissionsService = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const permission_repository_1 = require("../repositories/permission.repository");
|
|
15
|
+
const logger_service_1 = require("./logger.service");
|
|
15
16
|
let PermissionsService = class PermissionsService {
|
|
16
|
-
constructor(perms) {
|
|
17
|
+
constructor(perms, logger) {
|
|
17
18
|
this.perms = perms;
|
|
19
|
+
this.logger = logger;
|
|
18
20
|
}
|
|
19
21
|
async create(dto) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
try {
|
|
23
|
+
if (await this.perms.findByName(dto.name)) {
|
|
24
|
+
throw new common_1.ConflictException('Permission already exists');
|
|
25
|
+
}
|
|
26
|
+
return this.perms.create(dto);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error instanceof common_1.ConflictException) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === 11000) {
|
|
33
|
+
throw new common_1.ConflictException('Permission already exists');
|
|
34
|
+
}
|
|
35
|
+
this.logger.error(`Permission creation failed: ${error.message}`, error.stack, 'PermissionsService');
|
|
36
|
+
throw new common_1.InternalServerErrorException('Failed to create permission');
|
|
37
|
+
}
|
|
23
38
|
}
|
|
24
39
|
async list() {
|
|
25
|
-
|
|
40
|
+
try {
|
|
41
|
+
return this.perms.list();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
this.logger.error(`Permission list failed: ${error.message}`, error.stack, 'PermissionsService');
|
|
45
|
+
throw new common_1.InternalServerErrorException('Failed to retrieve permissions');
|
|
46
|
+
}
|
|
26
47
|
}
|
|
27
48
|
async update(id, dto) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
49
|
+
try {
|
|
50
|
+
const perm = await this.perms.updateById(id, dto);
|
|
51
|
+
if (!perm) {
|
|
52
|
+
throw new common_1.NotFoundException('Permission not found');
|
|
53
|
+
}
|
|
54
|
+
return perm;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof common_1.NotFoundException) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
this.logger.error(`Permission update failed: ${error.message}`, error.stack, 'PermissionsService');
|
|
61
|
+
throw new common_1.InternalServerErrorException('Failed to update permission');
|
|
62
|
+
}
|
|
32
63
|
}
|
|
33
64
|
async delete(id) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
65
|
+
try {
|
|
66
|
+
const perm = await this.perms.deleteById(id);
|
|
67
|
+
if (!perm) {
|
|
68
|
+
throw new common_1.NotFoundException('Permission not found');
|
|
69
|
+
}
|
|
70
|
+
return { ok: true };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof common_1.NotFoundException) {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
this.logger.error(`Permission deletion failed: ${error.message}`, error.stack, 'PermissionsService');
|
|
77
|
+
throw new common_1.InternalServerErrorException('Failed to delete permission');
|
|
78
|
+
}
|
|
38
79
|
}
|
|
39
80
|
};
|
|
40
81
|
exports.PermissionsService = PermissionsService;
|
|
41
82
|
exports.PermissionsService = PermissionsService = __decorate([
|
|
42
83
|
(0, common_1.Injectable)(),
|
|
43
|
-
__metadata("design:paramtypes", [permission_repository_1.PermissionRepository
|
|
84
|
+
__metadata("design:paramtypes", [permission_repository_1.PermissionRepository,
|
|
85
|
+
logger_service_1.LoggerService])
|
|
44
86
|
], PermissionsService);
|
|
@@ -2,9 +2,11 @@ import { RoleRepository } from '../repositories/role.repository';
|
|
|
2
2
|
import { CreateRoleDto } from '../dtos/role/create-role.dto';
|
|
3
3
|
import { UpdateRoleDto } from '../dtos/role/update-role.dto';
|
|
4
4
|
import { Types } from 'mongoose';
|
|
5
|
+
import { LoggerService } from './logger.service';
|
|
5
6
|
export declare class RolesService {
|
|
6
7
|
private readonly roles;
|
|
7
|
-
|
|
8
|
+
private readonly logger;
|
|
9
|
+
constructor(roles: RoleRepository, logger: LoggerService);
|
|
8
10
|
create(dto: CreateRoleDto): Promise<import("mongoose").Document<unknown, {}, import("../models/role.model").RoleDocument> & import("../models/role.model").Role & import("mongoose").Document<any, any, any> & {
|
|
9
11
|
_id: Types.ObjectId;
|
|
10
12
|
}>;
|
|
@@ -13,45 +13,97 @@ exports.RolesService = void 0;
|
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const role_repository_1 = require("../repositories/role.repository");
|
|
15
15
|
const mongoose_1 = require("mongoose");
|
|
16
|
+
const logger_service_1 = require("./logger.service");
|
|
16
17
|
let RolesService = class RolesService {
|
|
17
|
-
constructor(roles) {
|
|
18
|
+
constructor(roles, logger) {
|
|
18
19
|
this.roles = roles;
|
|
20
|
+
this.logger = logger;
|
|
19
21
|
}
|
|
20
22
|
async create(dto) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
try {
|
|
24
|
+
if (await this.roles.findByName(dto.name)) {
|
|
25
|
+
throw new common_1.ConflictException('Role already exists');
|
|
26
|
+
}
|
|
27
|
+
const permIds = (dto.permissions || []).map((p) => new mongoose_1.Types.ObjectId(p));
|
|
28
|
+
return this.roles.create({ name: dto.name, permissions: permIds });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof common_1.ConflictException) {
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === 11000) {
|
|
35
|
+
throw new common_1.ConflictException('Role already exists');
|
|
36
|
+
}
|
|
37
|
+
this.logger.error(`Role creation failed: ${error.message}`, error.stack, 'RolesService');
|
|
38
|
+
throw new common_1.InternalServerErrorException('Failed to create role');
|
|
39
|
+
}
|
|
25
40
|
}
|
|
26
41
|
async list() {
|
|
27
|
-
|
|
42
|
+
try {
|
|
43
|
+
return this.roles.list();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
this.logger.error(`Role list failed: ${error.message}`, error.stack, 'RolesService');
|
|
47
|
+
throw new common_1.InternalServerErrorException('Failed to retrieve roles');
|
|
48
|
+
}
|
|
28
49
|
}
|
|
29
50
|
async update(id, dto) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
try {
|
|
52
|
+
const data = { ...dto };
|
|
53
|
+
if (dto.permissions) {
|
|
54
|
+
data.permissions = dto.permissions.map((p) => new mongoose_1.Types.ObjectId(p));
|
|
55
|
+
}
|
|
56
|
+
const role = await this.roles.updateById(id, data);
|
|
57
|
+
if (!role) {
|
|
58
|
+
throw new common_1.NotFoundException('Role not found');
|
|
59
|
+
}
|
|
60
|
+
return role;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof common_1.NotFoundException) {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
this.logger.error(`Role update failed: ${error.message}`, error.stack, 'RolesService');
|
|
67
|
+
throw new common_1.InternalServerErrorException('Failed to update role');
|
|
68
|
+
}
|
|
38
69
|
}
|
|
39
70
|
async delete(id) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
try {
|
|
72
|
+
const role = await this.roles.deleteById(id);
|
|
73
|
+
if (!role) {
|
|
74
|
+
throw new common_1.NotFoundException('Role not found');
|
|
75
|
+
}
|
|
76
|
+
return { ok: true };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof common_1.NotFoundException) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
this.logger.error(`Role deletion failed: ${error.message}`, error.stack, 'RolesService');
|
|
83
|
+
throw new common_1.InternalServerErrorException('Failed to delete role');
|
|
84
|
+
}
|
|
44
85
|
}
|
|
45
86
|
async setPermissions(roleId, permissionIds) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
87
|
+
try {
|
|
88
|
+
const permIds = permissionIds.map((p) => new mongoose_1.Types.ObjectId(p));
|
|
89
|
+
const role = await this.roles.updateById(roleId, { permissions: permIds });
|
|
90
|
+
if (!role) {
|
|
91
|
+
throw new common_1.NotFoundException('Role not found');
|
|
92
|
+
}
|
|
93
|
+
return role;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error instanceof common_1.NotFoundException) {
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
this.logger.error(`Set permissions failed: ${error.message}`, error.stack, 'RolesService');
|
|
100
|
+
throw new common_1.InternalServerErrorException('Failed to set permissions');
|
|
101
|
+
}
|
|
51
102
|
}
|
|
52
103
|
};
|
|
53
104
|
exports.RolesService = RolesService;
|
|
54
105
|
exports.RolesService = RolesService = __decorate([
|
|
55
106
|
(0, common_1.Injectable)(),
|
|
56
|
-
__metadata("design:paramtypes", [role_repository_1.RoleRepository
|
|
107
|
+
__metadata("design:paramtypes", [role_repository_1.RoleRepository,
|
|
108
|
+
logger_service_1.LoggerService])
|
|
57
109
|
], RolesService);
|
|
@@ -2,10 +2,12 @@ import { UserRepository } from '../repositories/user.repository';
|
|
|
2
2
|
import { RoleRepository } from '../repositories/role.repository';
|
|
3
3
|
import { RegisterDto } from '../dtos/auth/register.dto';
|
|
4
4
|
import { Types } from 'mongoose';
|
|
5
|
+
import { LoggerService } from './logger.service';
|
|
5
6
|
export declare class UsersService {
|
|
6
7
|
private readonly users;
|
|
7
8
|
private readonly rolesRepo;
|
|
8
|
-
|
|
9
|
+
private readonly logger;
|
|
10
|
+
constructor(users: UserRepository, rolesRepo: RoleRepository, logger: LoggerService);
|
|
9
11
|
create(dto: RegisterDto): Promise<{
|
|
10
12
|
id: any;
|
|
11
13
|
email: string;
|