Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06f4fd06ff | ||
|
|
1bba2b518e |
+131
@@ -0,0 +1,131 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.CoreApiClient = exports.CoreApiClientError = void 0;
|
||||||
|
class CoreApiClientError extends Error {
|
||||||
|
status;
|
||||||
|
constructor(message, status) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'CoreApiClientError';
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.CoreApiClientError = CoreApiClientError;
|
||||||
|
class CoreApiClient {
|
||||||
|
apiUrl;
|
||||||
|
clientId;
|
||||||
|
clientSecret;
|
||||||
|
timeoutMs;
|
||||||
|
cachedToken = null;
|
||||||
|
tokenExpiry = 0; // epoch ms
|
||||||
|
tokenMarginSec = 60; // safety margin in seconds
|
||||||
|
constructor(options) {
|
||||||
|
this.apiUrl = options?.apiUrl ?? process.env.RAYLAB_CORE_API_URL ?? 'http://localhost:3000';
|
||||||
|
this.clientId = options?.clientId ?? process.env.RAYLAB_BOT_CLIENT_ID ?? '';
|
||||||
|
this.clientSecret = options?.clientSecret ?? process.env.RAYLAB_BOT_CLIENT_SECRET ?? '';
|
||||||
|
this.timeoutMs = options?.timeoutMs ?? 5000;
|
||||||
|
if (!this.clientId || !this.clientSecret) {
|
||||||
|
// keep construction allowed but operations will fail with clear errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fetchWithTimeout(url, init) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const id = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, { ...init, signal: controller.signal });
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
clearTimeout(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isTokenValid() {
|
||||||
|
return !!this.cachedToken && Date.now() < this.tokenExpiry;
|
||||||
|
}
|
||||||
|
async requestAccessToken() {
|
||||||
|
if (!this.clientId || !this.clientSecret) {
|
||||||
|
throw new CoreApiClientError('Missing client credentials');
|
||||||
|
}
|
||||||
|
const url = `${this.apiUrl.replace(/\/$/, '')}/api/v1/auth/token`;
|
||||||
|
const body = JSON.stringify({ client_id: this.clientId, client_secret: this.clientSecret, grant_type: 'client_credentials' });
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await this.fetchWithTimeout(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
throw new CoreApiClientError('Request timeout');
|
||||||
|
}
|
||||||
|
throw new CoreApiClientError('Network error');
|
||||||
|
}
|
||||||
|
if (res.status === 401) {
|
||||||
|
throw new CoreApiClientError('Invalid client credentials', 401);
|
||||||
|
}
|
||||||
|
if (res.status >= 400) {
|
||||||
|
throw new CoreApiClientError(`Token request failed with status ${res.status}`, res.status);
|
||||||
|
}
|
||||||
|
const payload = await res.json();
|
||||||
|
// Expecting { success: true, data: { access_token, token_type, expires_in }, ... }
|
||||||
|
const data = payload?.data;
|
||||||
|
if (!data || !data.access_token) {
|
||||||
|
throw new CoreApiClientError('Invalid token response');
|
||||||
|
}
|
||||||
|
// Cache token
|
||||||
|
this.cachedToken = data.access_token;
|
||||||
|
const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : parseInt(data.expires_in, 10) || 3600;
|
||||||
|
const effective = Math.max(0, expiresIn - this.tokenMarginSec);
|
||||||
|
this.tokenExpiry = Date.now() + effective * 1000;
|
||||||
|
return { access_token: data.access_token, token_type: data.token_type ?? 'Bearer', expires_in: expiresIn };
|
||||||
|
}
|
||||||
|
async getToken() {
|
||||||
|
if (this.isTokenValid()) {
|
||||||
|
return this.cachedToken;
|
||||||
|
}
|
||||||
|
const tokenResp = await this.requestAccessToken();
|
||||||
|
return tokenResp.access_token;
|
||||||
|
}
|
||||||
|
async authenticatedRequest(input, init, retry = true) {
|
||||||
|
const token = await this.getToken();
|
||||||
|
const headers = new Headers(init?.headers);
|
||||||
|
headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
headers.set('Accept', 'application/json');
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await this.fetchWithTimeout(typeof input === 'string' ? input : input.url, {
|
||||||
|
...init,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
throw new CoreApiClientError('Request timeout');
|
||||||
|
}
|
||||||
|
throw new CoreApiClientError('Network error');
|
||||||
|
}
|
||||||
|
if (res.status === 401 && retry) {
|
||||||
|
// invalidate token and retry once
|
||||||
|
this.cachedToken = null;
|
||||||
|
this.tokenExpiry = 0;
|
||||||
|
try {
|
||||||
|
const newToken = await this.getToken();
|
||||||
|
const headers2 = new Headers(init?.headers);
|
||||||
|
headers2.set('Authorization', `Bearer ${newToken}`);
|
||||||
|
headers2.set('Accept', 'application/json');
|
||||||
|
const res2 = await this.fetchWithTimeout(typeof input === 'string' ? input : input.url, {
|
||||||
|
...init,
|
||||||
|
headers: headers2,
|
||||||
|
});
|
||||||
|
return res2;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.CoreApiClient = CoreApiClient;
|
||||||
|
//# sourceMappingURL=core-api-client.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"core-api-client.js","sourceRoot":"","sources":["../../../src/adapters/notification/core-api-client.ts"],"names":[],"mappings":"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"}
|
||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AppModule = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const config_1 = require("@nestjs/config");
|
||||||
|
const identity_module_1 = require("./modules/identity/identity.module");
|
||||||
|
let AppModule = class AppModule {
|
||||||
|
};
|
||||||
|
exports.AppModule = AppModule;
|
||||||
|
exports.AppModule = AppModule = __decorate([
|
||||||
|
(0, common_1.Module)({
|
||||||
|
imports: [
|
||||||
|
config_1.ConfigModule.forRoot({
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
|
identity_module_1.IdentityModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
], AppModule);
|
||||||
|
//# sourceMappingURL=app.module.js.map
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAE9C,wEAAoE;AAW7D,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IATrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;aACf,CAAC;YAEF,gCAAc;SACf;KACF,CAAC;GACW,SAAS,CAAG"}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.JwtAuthGuard = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const jwt_1 = require("@nestjs/jwt");
|
||||||
|
let JwtAuthGuard = class JwtAuthGuard {
|
||||||
|
jwtService;
|
||||||
|
constructor(jwtService) {
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
}
|
||||||
|
async canActivate(context) {
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const authHeader = request.headers.authorization;
|
||||||
|
if (!authHeader) {
|
||||||
|
throw new common_1.UnauthorizedException('Authorization header is missing.');
|
||||||
|
}
|
||||||
|
const [type, token] = authHeader.split(' ');
|
||||||
|
if (type !== 'Bearer' || !token) {
|
||||||
|
throw new common_1.UnauthorizedException('Invalid authorization header.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const payload = await this.jwtService.verifyAsync(token);
|
||||||
|
request['user'] = payload;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw new common_1.UnauthorizedException('Invalid or expired token.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.JwtAuthGuard = JwtAuthGuard;
|
||||||
|
exports.JwtAuthGuard = JwtAuthGuard = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [jwt_1.JwtService])
|
||||||
|
], JwtAuthGuard);
|
||||||
|
//# sourceMappingURL=jwt-auth.guard.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../../src/core/auth/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAKwB;AACxB,qCAAyC;AAIlC,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IADnB,YACmB,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;QAE7D,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAEjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,8BAAqB,CAAC,kCAAkC,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE5C,IAAI,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,IAAI,8BAAqB,CAAC,+BAA+B,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEzD,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;YAE1B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,8BAAqB,CAAC,2BAA2B,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;CACF,CAAA;AA9BY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGoB,gBAAU;GAF9B,YAAY,CA8BxB"}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=authenticated-request.interface.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"authenticated-request.interface.js","sourceRoot":"","sources":["../../../../src/core/auth/interfaces/authenticated-request.interface.ts"],"names":[],"mappings":""}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.default = () => ({
|
||||||
|
database: {
|
||||||
|
url: `postgresql://` +
|
||||||
|
`${process.env.DB_USER}:` +
|
||||||
|
`${process.env.DB_PASSWORD}@` +
|
||||||
|
`${process.env.SERVER_HOST}:` +
|
||||||
|
`${process.env.DB_PORT}/` +
|
||||||
|
`${process.env.DB_NAME}?schema=public`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=database.config.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"database.config.js","sourceRoot":"","sources":["../../../src/core/config/database.config.ts"],"names":[],"mappings":";;AAAA,kBAAe,GAAG,EAAE,CAAC,CAAC;IAClB,QAAQ,EAAE;QACN,GAAG,EACC,eAAe;YACf,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG;YACzB,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG;YAC7B,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG;YAC7B,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG;YACzB,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,gBAAgB;KAC7C;CACJ,CAAC,CAAC"}
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.EventDispatcher = void 0;
|
||||||
|
class EventDispatcher {
|
||||||
|
publisher = new (require('./event-publisher').InMemoryEventPublisher)();
|
||||||
|
register(handler) {
|
||||||
|
this.publisher.register(handler);
|
||||||
|
}
|
||||||
|
async dispatch(event) {
|
||||||
|
await this.publisher.publish(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.EventDispatcher = EventDispatcher;
|
||||||
|
//# sourceMappingURL=event-dispatcher.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"event-dispatcher.js","sourceRoot":"","sources":["../../../src/core/events/event-dispatcher.ts"],"names":[],"mappings":";;;AAEA,MAAa,eAAe;IAClB,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC;IAEhF,QAAQ,CAAC,OAA0C;QACjD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAkB;QAC/B,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;CACF;AAVD,0CAUC"}
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=event-handler.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"event-handler.js","sourceRoot":"","sources":["../../../src/core/events/event-handler.ts"],"names":[],"mappings":""}
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.InMemoryEventPublisher = void 0;
|
||||||
|
class InMemoryEventPublisher {
|
||||||
|
handlers = [];
|
||||||
|
register(handler) {
|
||||||
|
this.handlers.push(handler);
|
||||||
|
}
|
||||||
|
async publish(event) {
|
||||||
|
await Promise.all(this.handlers.map((h) => h(event)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.InMemoryEventPublisher = InMemoryEventPublisher;
|
||||||
|
//# sourceMappingURL=event-publisher.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"event-publisher.js","sourceRoot":"","sources":["../../../src/core/events/event-publisher.ts"],"names":[],"mappings":";;;AAMA,MAAa,sBAAsB;IACzB,QAAQ,GAA6C,EAAE,CAAC;IAEhE,QAAQ,CAAC,OAA0C;QACjD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAkB;QAC9B,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;CACF;AAVD,wDAUC"}
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=event.interface.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"event.interface.js","sourceRoot":"","sources":["../../../src/core/events/event.interface.ts"],"names":[],"mappings":""}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.HttpExceptionFilter = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
let HttpExceptionFilter = class HttpExceptionFilter {
|
||||||
|
catch(exception, host) {
|
||||||
|
const ctx = host.switchToHttp();
|
||||||
|
const response = ctx.getResponse();
|
||||||
|
const status = exception.getStatus ? exception.getStatus() : 500;
|
||||||
|
response.status(status).json({
|
||||||
|
success: false,
|
||||||
|
error: {
|
||||||
|
code: exception.code || 'INTERNAL_ERROR',
|
||||||
|
message: exception.message || 'Internal server error',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.HttpExceptionFilter = HttpExceptionFilter;
|
||||||
|
exports.HttpExceptionFilter = HttpExceptionFilter = __decorate([
|
||||||
|
(0, common_1.Catch)()
|
||||||
|
], HttpExceptionFilter);
|
||||||
|
//# sourceMappingURL=http-exception.filter.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["../../../src/core/exceptions/http-exception.filter.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAuE;AAGhE,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,KAAK,CAAC,SAAc,EAAE,IAAmB;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAEjE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,gBAAgB;gBACxC,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,uBAAuB;aACtD;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAdY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,cAAK,GAAE;GACK,mBAAmB,CAc/B"}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.logger = void 0;
|
||||||
|
const pino_1 = __importDefault(require("pino"));
|
||||||
|
exports.logger = (0, pino_1.default)({
|
||||||
|
level: process.env.LOG_LEVEL || 'info',
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=logger.service.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"logger.service.js","sourceRoot":"","sources":["../../../src/core/logger/logger.service.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAEX,QAAA,MAAM,GAAG,IAAA,cAAI,EAAC;IACzB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;CACvC,CAAC,CAAC"}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.RequestIdMiddleware = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const uuid_1 = require("uuid");
|
||||||
|
let RequestIdMiddleware = class RequestIdMiddleware {
|
||||||
|
use(req, res, next) {
|
||||||
|
req.requestId = req.headers['x-request-id'] || (0, uuid_1.v4)();
|
||||||
|
res.setHeader('X-Request-ID', req.requestId);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.RequestIdMiddleware = RequestIdMiddleware;
|
||||||
|
exports.RequestIdMiddleware = RequestIdMiddleware = __decorate([
|
||||||
|
(0, common_1.Injectable)()
|
||||||
|
], RequestIdMiddleware);
|
||||||
|
//# sourceMappingURL=request-id.middleware.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"request-id.middleware.js","sourceRoot":"","sources":["../../../src/core/middleware/request-id.middleware.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4D;AAC5D,+BAAoC;AAG7B,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,GAAG,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAgB;QACtC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,IAAA,SAAM,GAAE,CAAC;QACxD,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC;IACT,CAAC;CACF,CAAA;AANY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;GACA,mBAAmB,CAM/B"}
|
||||||
Vendored
+34
@@ -0,0 +1,34 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const core_1 = require("@nestjs/core");
|
||||||
|
const config_1 = require("@nestjs/config");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
const app_module_1 = require("./app.module");
|
||||||
|
async function bootstrap() {
|
||||||
|
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||||
|
const config = app.get(config_1.ConfigService);
|
||||||
|
app.setGlobalPrefix('api');
|
||||||
|
app.useGlobalPipes(new common_1.ValidationPipe({
|
||||||
|
whitelist: true,
|
||||||
|
transform: true,
|
||||||
|
forbidNonWhitelisted: true,
|
||||||
|
}));
|
||||||
|
app.enableCors();
|
||||||
|
const swaggerEnabled = config.get('SWAGGER_ENABLED') === 'true';
|
||||||
|
if (swaggerEnabled) {
|
||||||
|
const swaggerConfig = new swagger_1.DocumentBuilder()
|
||||||
|
.setTitle('RayLab Core API')
|
||||||
|
.setDescription('RayLab Core REST API')
|
||||||
|
.setVersion('1.0.0')
|
||||||
|
.addBearerAuth()
|
||||||
|
.build();
|
||||||
|
const document = swagger_1.SwaggerModule.createDocument(app, swaggerConfig);
|
||||||
|
swagger_1.SwaggerModule.setup('docs', app, document);
|
||||||
|
}
|
||||||
|
const port = config.get('PORT') || 3000;
|
||||||
|
await app.listen(port);
|
||||||
|
console.log(`Server running on http://localhost:${port}`);
|
||||||
|
}
|
||||||
|
bootstrap();
|
||||||
|
//# sourceMappingURL=main.js.map
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,2CAAgD;AAChD,uCAA2C;AAC3C,2CAA+C;AAC/C,6CAAiE;AAEjE,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,sBAAa,CAAC,CAAC;IAEtC,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAE3B,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;KAC3B,CAAC,CACH,CAAC;IAEF,GAAG,CAAC,UAAU,EAAE,CAAC;IAEjB,MAAM,cAAc,GAClB,MAAM,CAAC,GAAG,CAAS,iBAAiB,CAAC,KAAK,MAAM,CAAC;IAEnD,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,IAAI,yBAAe,EAAE;aACxC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,cAAc,CAAC,sBAAsB,CAAC;aACtC,UAAU,CAAC,OAAO,CAAC;aACnB,aAAa,EAAE;aACf,KAAK,EAAE,CAAC;QAEX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAElE,uBAAa,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAS,MAAM,CAAC,IAAI,IAAI,CAAC;IAEhD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,EAAE,CAAC"}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
//# sourceMappingURL=authorization.service.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"authorization.service.js","sourceRoot":"","sources":["../../../../src/modules/authorization/application/authorization.service.ts"],"names":[],"mappings":""}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Permissions = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const Permissions = (...permissions) => (0, common_1.SetMetadata)('permissions', permissions);
|
||||||
|
exports.Permissions = Permissions;
|
||||||
|
//# sourceMappingURL=permission.decorator.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"permission.decorator.js","sourceRoot":"","sources":["../../../../../src/modules/authorization/presentation/decorators/permission.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAEtC,MAAM,WAAW,GAAG,CAAC,GAAG,WAAqB,EAAE,EAAE,CACtD,IAAA,oBAAW,EAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AAD7B,QAAA,WAAW,eACkB"}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PermissionGuard = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const core_1 = require("@nestjs/core");
|
||||||
|
let PermissionGuard = class PermissionGuard {
|
||||||
|
reflector;
|
||||||
|
constructor(reflector) {
|
||||||
|
this.reflector = reflector;
|
||||||
|
}
|
||||||
|
canActivate(context) {
|
||||||
|
const permissions = this.reflector.getAllAndOverride('permissions', [
|
||||||
|
context.getHandler(),
|
||||||
|
context.getClass(),
|
||||||
|
]);
|
||||||
|
if (!permissions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const user = request.user;
|
||||||
|
return permissions.every(permission => user.permissions.includes(permission));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.PermissionGuard = PermissionGuard;
|
||||||
|
exports.PermissionGuard = PermissionGuard = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [core_1.Reflector])
|
||||||
|
], PermissionGuard);
|
||||||
|
//# sourceMappingURL=permission.guard.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"permission.guard.js","sourceRoot":"","sources":["../../../../../src/modules/authorization/presentation/guards/permission.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAIwB;AACxB,uCAAyC;AAGlC,IAAM,eAAe,GAArB,MAAM,eAAe;IAEP;IADnB,YACmB,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IACpC,CAAC;IAEJ,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GACf,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAC9B,aAAa,EACb;YACE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CACF,CAAC;QAEJ,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,OAAO,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CACpC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CACtC,CAAC;IACJ,CAAC;CACF,CAAA;AA3BY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;qCAGmB,gBAAS;GAF5B,eAAe,CA2B3B"}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
|
var ownKeys = function(o) {
|
||||||
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys(o);
|
||||||
|
};
|
||||||
|
return function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.CreateUserHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const bcrypt = __importStar(require("bcrypt"));
|
||||||
|
const user_entity_1 = require("../../domain/entities/user.entity");
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let CreateUserHandler = class CreateUserHandler {
|
||||||
|
userRepository;
|
||||||
|
constructor(userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
async execute(dto) {
|
||||||
|
const exists = await this.userRepository.existsByEmail(dto.email);
|
||||||
|
if (exists) {
|
||||||
|
throw new common_1.ConflictException('Email already exists.');
|
||||||
|
}
|
||||||
|
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '10', 10);
|
||||||
|
const hashedPassword = await bcrypt.hash(dto.password, saltRounds);
|
||||||
|
const user = user_entity_1.User.create({
|
||||||
|
name: dto.name,
|
||||||
|
email: dto.email,
|
||||||
|
password: hashedPassword,
|
||||||
|
metadata: dto.metadata,
|
||||||
|
});
|
||||||
|
await this.userRepository.create(user);
|
||||||
|
// TODO:
|
||||||
|
// this.eventDispatcher.publish(new UserCreatedEvent(user));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.CreateUserHandler = CreateUserHandler;
|
||||||
|
exports.CreateUserHandler = CreateUserHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository])
|
||||||
|
], CreateUserHandler);
|
||||||
|
//# sourceMappingURL=create-user.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"create-user.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/create-user.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAGwB;AAExB,+CAAiC;AAEjC,mEAAyD;AACzD,mGAAqF;AAG9E,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IADnB,YACmB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAElE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,0BAAiB,CAAC,uBAAuB,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAEnE,MAAM,IAAI,GAAG,kBAAI,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvC,QAAQ;QACR,4DAA4D;QAE5D,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA7BY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;GAFtC,iBAAiB,CA6B7B"}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.DeleteUserHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let DeleteUserHandler = class DeleteUserHandler {
|
||||||
|
userRepository;
|
||||||
|
constructor(userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
async execute(id) {
|
||||||
|
const user = await this.userRepository.findById(id);
|
||||||
|
if (!user) {
|
||||||
|
throw new common_1.NotFoundException('User not found.');
|
||||||
|
}
|
||||||
|
user.delete();
|
||||||
|
await this.userRepository.update(user);
|
||||||
|
// TODO:
|
||||||
|
// Publish UserDeletedEvent
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.DeleteUserHandler = DeleteUserHandler;
|
||||||
|
exports.DeleteUserHandler = DeleteUserHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository])
|
||||||
|
], DeleteUserHandler);
|
||||||
|
//# sourceMappingURL=delete-user.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"delete-user.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/delete-user.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAGwB;AAExB,mGAAqF;AAG9E,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IADnB,YACmB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,0BAAiB,CAAC,iBAAiB,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;QAEd,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvC,QAAQ;QACR,2BAA2B;IAC7B,CAAC;CACF,CAAA;AAnBY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;GAFtC,iBAAiB,CAmB7B"}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.FindUserHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let FindUserHandler = class FindUserHandler {
|
||||||
|
userRepository;
|
||||||
|
constructor(userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
async execute(id) {
|
||||||
|
const user = await this.userRepository.findById(id);
|
||||||
|
if (!user) {
|
||||||
|
throw new common_1.NotFoundException('User not found.');
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.FindUserHandler = FindUserHandler;
|
||||||
|
exports.FindUserHandler = FindUserHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository])
|
||||||
|
], FindUserHandler);
|
||||||
|
//# sourceMappingURL=find-user.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"find-user.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/find-user.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAGwB;AAExB,mGAAqF;AAI9E,IAAM,eAAe,GAArB,MAAM,eAAe;IAEP;IADnB,YACmB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,0BAAiB,CAAC,iBAAiB,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAdY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;GAFtC,eAAe,CAc3B"}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.FindUsersHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let FindUsersHandler = class FindUsersHandler {
|
||||||
|
userRepository;
|
||||||
|
constructor(userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
async execute() {
|
||||||
|
return await this.userRepository.findAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.FindUsersHandler = FindUsersHandler;
|
||||||
|
exports.FindUsersHandler = FindUsersHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository])
|
||||||
|
], FindUsersHandler);
|
||||||
|
//# sourceMappingURL=find-users.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"find-users.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/find-users.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,mGAAqF;AAI9E,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAER;IADnB,YACmB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO;QACX,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;IAC7C,CAAC;CACF,CAAA;AARY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;GAFtC,gBAAgB,CAQ5B"}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
|
var ownKeys = function(o) {
|
||||||
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys(o);
|
||||||
|
};
|
||||||
|
return function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.LoginHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const bcrypt = __importStar(require("bcrypt"));
|
||||||
|
const jwt_1 = require("@nestjs/jwt");
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let LoginHandler = class LoginHandler {
|
||||||
|
userRepository;
|
||||||
|
jwtService;
|
||||||
|
constructor(userRepository, jwtService) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
}
|
||||||
|
async execute(dto) {
|
||||||
|
const user = await this.userRepository.findByEmail(dto.email);
|
||||||
|
// Generic error message for security
|
||||||
|
const unauthorizedMsg = 'Invalid credentials.';
|
||||||
|
if (!user) {
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
const isMatch = await bcrypt.compare(dto.password, user.password);
|
||||||
|
if (!isMatch) {
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
// Build payload according to existing JwtPayload interface
|
||||||
|
const metadata = user.metadata ?? {};
|
||||||
|
const role = typeof metadata.role === 'string' ? metadata.role : 'USER';
|
||||||
|
const permissions = Array.isArray(metadata.permissions) ? metadata.permissions : [];
|
||||||
|
const payload = {
|
||||||
|
sub: user.id,
|
||||||
|
email: user.email,
|
||||||
|
role,
|
||||||
|
permissions,
|
||||||
|
};
|
||||||
|
const accessToken = await this.jwtService.signAsync(payload);
|
||||||
|
return {
|
||||||
|
access_token: accessToken,
|
||||||
|
expires_in: '1d',
|
||||||
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.LoginHandler = LoginHandler;
|
||||||
|
exports.LoginHandler = LoginHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository,
|
||||||
|
jwt_1.JwtService])
|
||||||
|
], LoginHandler);
|
||||||
|
//# sourceMappingURL=login.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"login.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/login.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAmE;AACnE,+CAAiC;AACjC,qCAAyC;AAGzC,mGAAqF;AAG9E,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IACA;IAFnB,YACmB,cAA8B,EAC9B,UAAsB;QADtB,mBAAc,GAAd,cAAc,CAAgB;QAC9B,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,GAAa;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE9D,qCAAqC;QACrC,MAAM,eAAe,GAAG,sBAAsB,CAAC;QAE/C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAElE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,2DAA2D;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;QAErC,MAAM,IAAI,GAAG,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QAExE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QAEpF,MAAM,OAAO,GAAG;YACd,GAAG,EAAE,IAAI,CAAC,EAAE;YACZ,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI;YACJ,WAAW;SACZ,CAAC;QAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE7D,OAAO;YACL,YAAY,EAAE,WAAW;YACzB,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE;gBACJ,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAhDY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;QAClB,gBAAU;GAH9B,YAAY,CAgDxB"}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
|
var ownKeys = function(o) {
|
||||||
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys(o);
|
||||||
|
};
|
||||||
|
return function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.TokenHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const bcrypt = __importStar(require("bcrypt"));
|
||||||
|
const jwt_1 = require("@nestjs/jwt");
|
||||||
|
const service_account_repository_interface_1 = require("../../domain/repositories/service-account.repository.interface");
|
||||||
|
let TokenHandler = class TokenHandler {
|
||||||
|
serviceAccountRepository;
|
||||||
|
jwtService;
|
||||||
|
constructor(serviceAccountRepository, jwtService) {
|
||||||
|
this.serviceAccountRepository = serviceAccountRepository;
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
}
|
||||||
|
async execute(body) {
|
||||||
|
const { client_id, client_secret, grant_type } = body;
|
||||||
|
if (grant_type !== 'client_credentials') {
|
||||||
|
throw new common_1.BadRequestException('Invalid grant_type.');
|
||||||
|
}
|
||||||
|
const unauthorizedMsg = 'Invalid client credentials.';
|
||||||
|
if (!client_id || !client_secret) {
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
const serviceAccount = await this.serviceAccountRepository.findByClientId(client_id);
|
||||||
|
if (!serviceAccount) {
|
||||||
|
// generic error
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
// check status
|
||||||
|
if (serviceAccount.status !== 'ACTIVE') {
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
const match = await bcrypt.compare(client_secret, serviceAccount.clientSecretHash);
|
||||||
|
if (!match) {
|
||||||
|
throw new common_1.UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
const payload = {
|
||||||
|
sub: serviceAccount.id,
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
// existing JwtPayload expects email; provide empty string to remain compatible
|
||||||
|
email: '',
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions ?? [],
|
||||||
|
};
|
||||||
|
const accessToken = await this.jwtService.signAsync(payload, {
|
||||||
|
expiresIn: '1h',
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
access_token: accessToken,
|
||||||
|
token_type: 'Bearer',
|
||||||
|
expires_in: 3600,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.TokenHandler = TokenHandler;
|
||||||
|
exports.TokenHandler = TokenHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [service_account_repository_interface_1.ServiceAccountRepository,
|
||||||
|
jwt_1.JwtService])
|
||||||
|
], TokenHandler);
|
||||||
|
//# sourceMappingURL=token.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"token.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/token.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwF;AACxF,+CAAiC;AACjC,qCAAyC;AACzC,yHAA0G;AAGnG,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IACA;IAFnB,YACmB,wBAAkD,EAClD,UAAsB;QADtB,6BAAwB,GAAxB,wBAAwB,CAA0B;QAClD,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,IAAyE;QACrF,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAEtD,IAAI,UAAU,KAAK,oBAAoB,EAAE,CAAC;YACxC,MAAM,IAAI,4BAAmB,CAAC,qBAAqB,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,eAAe,GAAG,6BAA6B,CAAC;QAEtD,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;YACjC,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAErF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,gBAAgB;YAChB,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,eAAe;QACf,IAAI,cAAc,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACvC,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC;QAEnF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,OAAO,GAAQ;YACnB,GAAG,EAAE,cAAc,CAAC,EAAE;YACtB,SAAS,EAAE,cAAc,CAAC,QAAQ;YAClC,+EAA+E;YAC/E,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,WAAW,EAAE,cAAc,CAAC,WAAW,IAAI,EAAE;SAC9C,CAAC;QAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE;YAC3D,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QAEH,OAAO;YACL,YAAY,EAAE,WAAW;YACzB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAA;AAxDY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGkC,+DAAwB;QACtC,gBAAU;GAH9B,YAAY,CAwDxB"}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
|
var ownKeys = function(o) {
|
||||||
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys(o);
|
||||||
|
};
|
||||||
|
return function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UpdateUserHandler = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const bcrypt = __importStar(require("bcrypt"));
|
||||||
|
const user_repository_interface_1 = require("../../domain/repositories/user.repository.interface");
|
||||||
|
let UpdateUserHandler = class UpdateUserHandler {
|
||||||
|
userRepository;
|
||||||
|
constructor(userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
async execute(id, dto) {
|
||||||
|
const user = await this.userRepository.findById(id);
|
||||||
|
if (!user) {
|
||||||
|
throw new common_1.NotFoundException('User not found.');
|
||||||
|
}
|
||||||
|
if (dto.email &&
|
||||||
|
dto.email !== user.email) {
|
||||||
|
const exists = await this.userRepository.existsByEmail(dto.email);
|
||||||
|
if (exists) {
|
||||||
|
throw new common_1.ConflictException('Email already exists.');
|
||||||
|
}
|
||||||
|
user.changeEmail(dto.email);
|
||||||
|
}
|
||||||
|
if (dto.name) {
|
||||||
|
user.changeName(dto.name);
|
||||||
|
}
|
||||||
|
if (dto.password) {
|
||||||
|
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '10', 10);
|
||||||
|
const hashedPassword = await bcrypt.hash(dto.password, saltRounds);
|
||||||
|
user.changePassword(hashedPassword);
|
||||||
|
}
|
||||||
|
await this.userRepository.update(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.UpdateUserHandler = UpdateUserHandler;
|
||||||
|
exports.UpdateUserHandler = UpdateUserHandler = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [user_repository_interface_1.UserRepository])
|
||||||
|
], UpdateUserHandler);
|
||||||
|
//# sourceMappingURL=update-user.handler.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"update-user.handler.js","sourceRoot":"","sources":["../../../../../src/modules/identity/application/handlers/update-user.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAIwB;AAExB,+CAAiC;AAEjC,mGAAqF;AAI9E,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IADnB,YACmB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO,CACX,EAAU,EACV,GAAkB;QAElB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,0BAAiB,CAAC,iBAAiB,CAAC,CAAC;QACjD,CAAC;QAED,IACE,GAAG,CAAC,KAAK;YACT,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EACxB,CAAC;YACD,MAAM,MAAM,GACV,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAErD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,IAAI,0BAAiB,CACzB,uBAAuB,CACxB,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YACb,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;YACxE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACnE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvC,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA7CY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGwB,0CAAc;GAFtC,iBAAiB,CA6C7B"}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ServiceAccount = void 0;
|
||||||
|
class ServiceAccount {
|
||||||
|
id;
|
||||||
|
clientId;
|
||||||
|
clientSecretHash;
|
||||||
|
name;
|
||||||
|
role;
|
||||||
|
permissions;
|
||||||
|
status;
|
||||||
|
metadata;
|
||||||
|
constructor(id, clientId, clientSecretHash, name, role, permissions, status, metadata) {
|
||||||
|
this.id = id;
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.clientSecretHash = clientSecretHash;
|
||||||
|
this.name = name;
|
||||||
|
this.role = role;
|
||||||
|
this.permissions = permissions;
|
||||||
|
this.status = status;
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
static create(data) {
|
||||||
|
return new ServiceAccount(crypto.randomUUID(), data.clientId, data.clientSecretHash, data.name, data.role, data.permissions, 'ACTIVE', data.metadata);
|
||||||
|
}
|
||||||
|
static restore(data) {
|
||||||
|
return new ServiceAccount(data.id, data.clientId, data.clientSecretHash, data.name, data.role, data.permissions, data.status, data.metadata);
|
||||||
|
}
|
||||||
|
disable() {
|
||||||
|
this.status = 'DISABLED';
|
||||||
|
}
|
||||||
|
enable() {
|
||||||
|
this.status = 'ACTIVE';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ServiceAccount = ServiceAccount;
|
||||||
|
//# sourceMappingURL=service-account.entity.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"service-account.entity.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/entities/service-account.entity.ts"],"names":[],"mappings":";;;AAAA,MAAa,cAAc;IAEP;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IART,YACkB,EAAU,EACnB,QAAgB,EAChB,gBAAwB,EACxB,IAAY,EACZ,IAAY,EACZ,WAAqB,EACrB,MAAc,EACd,QAA8B;QAPrB,OAAE,GAAF,EAAE,CAAQ;QACnB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,qBAAgB,GAAhB,gBAAgB,CAAQ;QACxB,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAQ;QACZ,gBAAW,GAAX,WAAW,CAAU;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAsB;IACpC,CAAC;IAEJ,MAAM,CAAC,MAAM,CAAC,IAOb;QACC,OAAO,IAAI,cAAc,CACvB,MAAM,CAAC,UAAU,EAAE,EACnB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,gBAAgB,EACrB,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,QAAQ,EACR,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,IASd;QACC,OAAO,IAAI,cAAc,CACvB,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,gBAAgB,EACrB,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;IACzB,CAAC;CACF;AA7DD,wCA6DC"}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.User = void 0;
|
||||||
|
class User {
|
||||||
|
id;
|
||||||
|
name;
|
||||||
|
email;
|
||||||
|
password;
|
||||||
|
metadata;
|
||||||
|
constructor(id, name, email, password, metadata) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
static create(data) {
|
||||||
|
return new User(crypto.randomUUID(), data.name, data.email, data.password, data.metadata);
|
||||||
|
}
|
||||||
|
delete() {
|
||||||
|
// Business Rule
|
||||||
|
}
|
||||||
|
changeEmail(email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
changeName(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
changePassword(newPassword) {
|
||||||
|
this.password = newPassword;
|
||||||
|
}
|
||||||
|
static restore(data) {
|
||||||
|
return new User(data.id, data.name, data.email, data.password, data.metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.User = User;
|
||||||
|
//# sourceMappingURL=user.entity.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"user.entity.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/entities/user.entity.ts"],"names":[],"mappings":";;;AAAA,MAAa,IAAI;IAEG;IACT;IACA;IACA;IACA;IALT,YACkB,EAAU,EACnB,IAAY,EACZ,KAAa,EACb,QAAgB,EAChB,QAA8B;QAJrB,OAAE,GAAF,EAAE,CAAQ;QACnB,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAQ;QACb,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAsB;IACpC,CAAC;IAEJ,MAAM,CAAC,MAAM,CAAC,IAKb;QACC,OAAO,IAAI,IAAI,CACb,MAAM,CAAC,UAAU,EAAE,EACnB,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,gBAAgB;IAClB,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,cAAc,CAAC,WAAmB;QAChC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,IAMd;QACC,OAAO,IAAI,IAAI,CACb,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;CACF;AAvDD,oBAuDC"}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UserCreatedEvent = void 0;
|
||||||
|
class UserCreatedEvent {
|
||||||
|
payload;
|
||||||
|
occurredAt;
|
||||||
|
name = 'UserCreated';
|
||||||
|
constructor(payload, occurredAt = new Date()) {
|
||||||
|
this.payload = payload;
|
||||||
|
this.occurredAt = occurredAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.UserCreatedEvent = UserCreatedEvent;
|
||||||
|
//# sourceMappingURL=user-created.event.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"user-created.event.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/events/user-created.event.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAEC;IAA8B;IADjD,IAAI,GAAG,aAAa,CAAC;IAC9B,YAA4B,OAAY,EAAkB,aAAmB,IAAI,IAAI,EAAE;QAA3D,YAAO,GAAP,OAAO,CAAK;QAAkB,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;CAC5F;AAHD,4CAGC"}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UserDeletedEvent = void 0;
|
||||||
|
class UserDeletedEvent {
|
||||||
|
payload;
|
||||||
|
occurredAt;
|
||||||
|
name = 'UserDeleted';
|
||||||
|
constructor(payload, occurredAt = new Date()) {
|
||||||
|
this.payload = payload;
|
||||||
|
this.occurredAt = occurredAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.UserDeletedEvent = UserDeletedEvent;
|
||||||
|
//# sourceMappingURL=user-deleted.event.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"user-deleted.event.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/events/user-deleted.event.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAEC;IAA8B;IADjD,IAAI,GAAG,aAAa,CAAC;IAC9B,YAA4B,OAAY,EAAkB,aAAmB,IAAI,IAAI,EAAE;QAA3D,YAAO,GAAP,OAAO,CAAK;QAAkB,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;CAC5F;AAHD,4CAGC"}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ServiceAccountRepository = void 0;
|
||||||
|
class ServiceAccountRepository {
|
||||||
|
}
|
||||||
|
exports.ServiceAccountRepository = ServiceAccountRepository;
|
||||||
|
//# sourceMappingURL=service-account.repository.interface.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"service-account.repository.interface.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/repositories/service-account.repository.interface.ts"],"names":[],"mappings":";;;AAEA,MAAsB,wBAAwB;CAQ7C;AARD,4DAQC"}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UserRepository = void 0;
|
||||||
|
class UserRepository {
|
||||||
|
}
|
||||||
|
exports.UserRepository = UserRepository;
|
||||||
|
//# sourceMappingURL=user.repository.interface.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"user.repository.interface.js","sourceRoot":"","sources":["../../../../../src/modules/identity/domain/repositories/user.repository.interface.ts"],"names":[],"mappings":";;;AAEA,MAAsB,cAAc;CAgBnC;AAhBD,wCAgBC"}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.IdentityModule = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const users_controller_1 = require("./presentation/controllers/users.controller");
|
||||||
|
const prisma_service_1 = require("../../shared/prisma.service");
|
||||||
|
const prisma_user_repository_1 = require("./infrastructure/repositories/prisma-user.repository");
|
||||||
|
const user_repository_interface_1 = require("./domain/repositories/user.repository.interface");
|
||||||
|
const event_dispatcher_1 = require("../../core/events/event-dispatcher");
|
||||||
|
const jwt_auth_guard_1 = require("../../core/auth/guards/jwt-auth.guard");
|
||||||
|
const jwt_1 = require("@nestjs/jwt");
|
||||||
|
const create_user_handler_1 = require("./application/handlers/create-user.handler");
|
||||||
|
const find_user_handler_1 = require("./application/handlers/find-user.handler");
|
||||||
|
const delete_user_handler_1 = require("./application/handlers/delete-user.handler");
|
||||||
|
const find_users_handler_1 = require("./application/handlers/find-users.handler");
|
||||||
|
const update_user_handler_1 = require("./application/handlers/update-user.handler");
|
||||||
|
const permission_guard_1 = require("../authorization/presentation/guards/permission.guard");
|
||||||
|
const core_1 = require("@nestjs/core");
|
||||||
|
const login_handler_1 = require("./application/handlers/login.handler");
|
||||||
|
const auth_controller_1 = require("./presentation/controllers/auth.controller");
|
||||||
|
const token_handler_1 = require("./application/handlers/token.handler");
|
||||||
|
const prisma_service_account_repository_1 = require("./infrastructure/repositories/prisma-service-account.repository");
|
||||||
|
const service_account_repository_interface_1 = require("./domain/repositories/service-account.repository.interface");
|
||||||
|
let IdentityModule = class IdentityModule {
|
||||||
|
};
|
||||||
|
exports.IdentityModule = IdentityModule;
|
||||||
|
exports.IdentityModule = IdentityModule = __decorate([
|
||||||
|
(0, common_1.Module)({
|
||||||
|
imports: [
|
||||||
|
jwt_1.JwtModule.register({
|
||||||
|
secret: process.env.JWT_SECRET,
|
||||||
|
signOptions: {
|
||||||
|
expiresIn: '1d',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [users_controller_1.UsersController, auth_controller_1.AuthController],
|
||||||
|
providers: [
|
||||||
|
//#region User
|
||||||
|
create_user_handler_1.CreateUserHandler,
|
||||||
|
find_user_handler_1.FindUserHandler,
|
||||||
|
find_users_handler_1.FindUsersHandler,
|
||||||
|
update_user_handler_1.UpdateUserHandler,
|
||||||
|
delete_user_handler_1.DeleteUserHandler,
|
||||||
|
login_handler_1.LoginHandler,
|
||||||
|
token_handler_1.TokenHandler,
|
||||||
|
//#endregion
|
||||||
|
jwt_auth_guard_1.JwtAuthGuard,
|
||||||
|
permission_guard_1.PermissionGuard,
|
||||||
|
core_1.Reflector,
|
||||||
|
prisma_service_1.PrismaService,
|
||||||
|
prisma_user_repository_1.PrismaUserRepository,
|
||||||
|
prisma_service_account_repository_1.PrismaServiceAccountRepository,
|
||||||
|
{
|
||||||
|
provide: user_repository_interface_1.UserRepository,
|
||||||
|
useClass: prisma_user_repository_1.PrismaUserRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: service_account_repository_interface_1.ServiceAccountRepository,
|
||||||
|
useClass: prisma_service_account_repository_1.PrismaServiceAccountRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: 'EVENT_DISPATCHER',
|
||||||
|
useValue: new event_dispatcher_1.EventDispatcher(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
], IdentityModule);
|
||||||
|
//# sourceMappingURL=identity.module.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"identity.module.js","sourceRoot":"","sources":["../../../src/modules/identity/identity.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,kFAA8E;AAC9E,gEAA4D;AAC5D,iGAA4F;AAC5F,+FAAiF;AACjF,yEAAqE;AACrE,0EAAqE;AACrE,qCAAwC;AACxC,oFAA+E;AAC/E,gFAA2E;AAC3E,oFAA+E;AAC/E,kFAA6E;AAC7E,oFAA+E;AAC/E,4FAAwF;AACxF,uCAAyC;AACzC,wEAAoE;AACpE,gFAA4E;AAC5E,wEAAoE;AACpE,uHAAiH;AACjH,qHAAsG;AA4C/F,IAAM,cAAc,GAApB,MAAM,cAAc;CAAG,CAAA;AAAjB,wCAAc;yBAAd,cAAc;IAzC1B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,eAAS,CAAC,QAAQ,CAAC;gBACjB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,WAAW,EAAE;oBACX,SAAS,EAAE,IAAI;iBAChB;aACF,CAAC;SACH;QACD,WAAW,EAAE,CAAC,kCAAe,EAAE,gCAAc,CAAC;QAC9C,SAAS,EAAE;YACT,eAAe;YACf,uCAAiB;YACjB,mCAAe;YACf,qCAAgB;YAChB,uCAAiB;YACjB,uCAAiB;YACjB,4BAAY;YACZ,4BAAY;YACZ,YAAY;YAEZ,6BAAY;YACZ,kCAAe;YACf,gBAAS;YACT,8BAAa;YACb,6CAAoB;YACpB,kEAA8B;YAC9B;gBACE,OAAO,EAAE,0CAAc;gBACvB,QAAQ,EAAE,6CAAoB;aAC/B;YACD;gBACE,OAAO,EAAE,+DAAwB;gBACjC,QAAQ,EAAE,kEAA8B;aACzC;YACD;gBACE,OAAO,EAAE,kBAAkB;gBAC3B,QAAQ,EAAE,IAAI,kCAAe,EAAE;aAChC;SACF;KACF,CAAC;GACW,cAAc,CAAG"}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaUserMapper = void 0;
|
||||||
|
const user_entity_1 = require("../../domain/entities/user.entity");
|
||||||
|
class PrismaUserMapper {
|
||||||
|
static toDomain(model) {
|
||||||
|
if (!model) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return user_entity_1.User.restore({
|
||||||
|
id: model.id,
|
||||||
|
name: model.name,
|
||||||
|
email: model.email,
|
||||||
|
password: model.password,
|
||||||
|
metadata: model.metadata,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static toPersistence(user) {
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
password: user.password,
|
||||||
|
metadata: user.metadata ?? {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.PrismaUserMapper = PrismaUserMapper;
|
||||||
|
//# sourceMappingURL=prisma-user.mapper.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"prisma-user.mapper.js","sourceRoot":"","sources":["../../../../../src/modules/identity/infrastructure/mappers/prisma-user.mapper.ts"],"names":[],"mappings":";;;AAAA,mEAAyD;AAEzD,MAAa,gBAAgB;IAC3B,MAAM,CAAC,QAAQ,CAAC,KAAU;QACxB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,kBAAI,CAAC,OAAO,CAAC;YAClB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,IAAU;QAC7B,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;SAC9B,CAAC;IACJ,CAAC;CACF;AAxBD,4CAwBC"}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaServiceAccountRepository = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const prisma_service_1 = require("../../../../shared/prisma.service");
|
||||||
|
const service_account_entity_1 = require("../../domain/entities/service-account.entity");
|
||||||
|
let PrismaServiceAccountRepository = class PrismaServiceAccountRepository {
|
||||||
|
prisma;
|
||||||
|
constructor(prisma) {
|
||||||
|
this.prisma = prisma;
|
||||||
|
}
|
||||||
|
async create(serviceAccount) {
|
||||||
|
const created = await this.prisma.serviceAccount.create({
|
||||||
|
data: {
|
||||||
|
id: serviceAccount.id,
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
client_secret_hash: serviceAccount.clientSecretHash,
|
||||||
|
name: serviceAccount.name,
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions,
|
||||||
|
status: serviceAccount.status,
|
||||||
|
metadata: serviceAccount.metadata ?? {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return service_account_entity_1.ServiceAccount.restore({
|
||||||
|
id: created.id,
|
||||||
|
clientId: created.client_id,
|
||||||
|
clientSecretHash: created.client_secret_hash,
|
||||||
|
name: created.name,
|
||||||
|
role: created.role,
|
||||||
|
permissions: created.permissions,
|
||||||
|
status: created.status,
|
||||||
|
metadata: (created.metadata ?? {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async update(serviceAccount) {
|
||||||
|
const updated = await this.prisma.serviceAccount.update({
|
||||||
|
where: { id: serviceAccount.id },
|
||||||
|
data: {
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
client_secret_hash: serviceAccount.clientSecretHash,
|
||||||
|
name: serviceAccount.name,
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions,
|
||||||
|
status: serviceAccount.status,
|
||||||
|
metadata: serviceAccount.metadata ?? {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return service_account_entity_1.ServiceAccount.restore({
|
||||||
|
id: updated.id,
|
||||||
|
clientId: updated.client_id,
|
||||||
|
clientSecretHash: updated.client_secret_hash,
|
||||||
|
name: updated.name,
|
||||||
|
role: updated.role,
|
||||||
|
permissions: updated.permissions,
|
||||||
|
status: updated.status,
|
||||||
|
metadata: (updated.metadata ?? {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async findById(id) {
|
||||||
|
const model = await this.prisma.serviceAccount.findUnique({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
if (!model)
|
||||||
|
return null;
|
||||||
|
return service_account_entity_1.ServiceAccount.restore({
|
||||||
|
id: model.id,
|
||||||
|
clientId: model.client_id,
|
||||||
|
clientSecretHash: model.client_secret_hash,
|
||||||
|
name: model.name,
|
||||||
|
role: model.role,
|
||||||
|
permissions: model.permissions,
|
||||||
|
status: model.status,
|
||||||
|
metadata: (model.metadata ?? {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async findByClientId(clientId) {
|
||||||
|
const model = await this.prisma.serviceAccount.findUnique({
|
||||||
|
where: { client_id: clientId },
|
||||||
|
});
|
||||||
|
if (!model)
|
||||||
|
return null;
|
||||||
|
return service_account_entity_1.ServiceAccount.restore({
|
||||||
|
id: model.id,
|
||||||
|
clientId: model.client_id,
|
||||||
|
clientSecretHash: model.client_secret_hash,
|
||||||
|
name: model.name,
|
||||||
|
role: model.role,
|
||||||
|
permissions: model.permissions,
|
||||||
|
status: model.status,
|
||||||
|
metadata: (model.metadata ?? {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.PrismaServiceAccountRepository = PrismaServiceAccountRepository;
|
||||||
|
exports.PrismaServiceAccountRepository = PrismaServiceAccountRepository = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||||
|
], PrismaServiceAccountRepository);
|
||||||
|
//# sourceMappingURL=prisma-service-account.repository.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"prisma-service-account.repository.js","sourceRoot":"","sources":["../../../../../src/modules/identity/infrastructure/repositories/prisma-service-account.repository.ts"],"names":[],"mappings":"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"}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaUserRepository = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const prisma_service_1 = require("../../../../shared/prisma.service");
|
||||||
|
const prisma_user_mapper_1 = require("../mappers/prisma-user.mapper");
|
||||||
|
let PrismaUserRepository = class PrismaUserRepository {
|
||||||
|
prisma;
|
||||||
|
constructor(prisma) {
|
||||||
|
this.prisma = prisma;
|
||||||
|
}
|
||||||
|
async findById(id) {
|
||||||
|
const user = await this.prisma.user.findUnique({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
return prisma_user_mapper_1.PrismaUserMapper.toDomain(user);
|
||||||
|
}
|
||||||
|
async findByEmail(email) {
|
||||||
|
const user = await this.prisma.user.findUnique({
|
||||||
|
where: { email },
|
||||||
|
});
|
||||||
|
return prisma_user_mapper_1.PrismaUserMapper.toDomain(user);
|
||||||
|
}
|
||||||
|
async findAll() {
|
||||||
|
const users = await this.prisma.user.findMany({
|
||||||
|
where: { deleted_at: null },
|
||||||
|
orderBy: { created_at: 'desc' },
|
||||||
|
});
|
||||||
|
return users.map(u => prisma_user_mapper_1.PrismaUserMapper.toDomain(u));
|
||||||
|
}
|
||||||
|
async create(user) {
|
||||||
|
const created = await this.prisma.user.create({
|
||||||
|
data: prisma_user_mapper_1.PrismaUserMapper.toPersistence(user),
|
||||||
|
});
|
||||||
|
return prisma_user_mapper_1.PrismaUserMapper.toDomain(created);
|
||||||
|
}
|
||||||
|
async update(user) {
|
||||||
|
const updated = await this.prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id: user.id,
|
||||||
|
},
|
||||||
|
data: prisma_user_mapper_1.PrismaUserMapper.toPersistence(user),
|
||||||
|
});
|
||||||
|
return prisma_user_mapper_1.PrismaUserMapper.toDomain(updated);
|
||||||
|
}
|
||||||
|
async delete(id) {
|
||||||
|
const user = await this.prisma.user.update({
|
||||||
|
where: { id },
|
||||||
|
data: { deleted_at: new Date() },
|
||||||
|
});
|
||||||
|
return prisma_user_mapper_1.PrismaUserMapper.toDomain(user);
|
||||||
|
}
|
||||||
|
async existsByEmail(email, excludeId) {
|
||||||
|
const where = { email };
|
||||||
|
if (excludeId) {
|
||||||
|
where.id = { not: excludeId };
|
||||||
|
}
|
||||||
|
const user = await this.prisma.user.findFirst({ where });
|
||||||
|
return !!user;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.PrismaUserRepository = PrismaUserRepository;
|
||||||
|
exports.PrismaUserRepository = PrismaUserRepository = __decorate([
|
||||||
|
(0, common_1.Injectable)(),
|
||||||
|
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||||
|
], PrismaUserRepository);
|
||||||
|
//# sourceMappingURL=prisma-user.repository.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"prisma-user.repository.js","sourceRoot":"","sources":["../../../../../src/modules/identity/infrastructure/repositories/prisma-user.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,sEAAkE;AAGlE,sEAAiE;AAG1D,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACF;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAC7C,KAAK,EAAE,EAAE,EAAE,EAAE;SACd,CAAC,CAAC;QAEH,OAAO,qCAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAC7C,KAAK,EAAE,EAAE,KAAK,EAAE;SACjB,CAAC,CAAC;QAEH,OAAO,qCAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC5C,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;YAC3B,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;SAChC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,qCAAgB,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAU;QACrB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5C,IAAI,EAAE,qCAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;SAC3C,CAAC,CAAC;QAEH,OAAO,qCAAgB,CAAC,QAAQ,CAAC,OAAO,CAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAU;QACrB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5C,KAAK,EAAE;gBACL,EAAE,EAAE,IAAI,CAAC,EAAE;aACZ;YACD,IAAI,EAAE,qCAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;SAC3C,CAAC,CAAC;QAEH,OAAO,qCAAgB,CAAC,QAAQ,CAAC,OAAO,CAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACzC,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE;SACjC,CAAC,CAAC;QACH,OAAO,qCAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,SAAyB;QAC1D,MAAM,KAAK,GAAQ,EAAE,KAAK,EAAE,CAAC;QAC7B,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;QAChC,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC;CACF,CAAA;AAhEY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,oBAAoB,CAgEhC"}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||||
|
return function (target, key) { decorator(target, key, paramIndex); }
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AuthController = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
const login_dto_1 = require("../dto/login.dto");
|
||||||
|
const login_handler_1 = require("../../application/handlers/login.handler");
|
||||||
|
const token_handler_1 = require("../../application/handlers/token.handler");
|
||||||
|
let AuthController = class AuthController {
|
||||||
|
loginHandler;
|
||||||
|
tokenHandler;
|
||||||
|
constructor(loginHandler, tokenHandler) {
|
||||||
|
this.loginHandler = loginHandler;
|
||||||
|
this.tokenHandler = tokenHandler;
|
||||||
|
}
|
||||||
|
async login(dto) {
|
||||||
|
const data = await this.loginHandler.execute(dto);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data,
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async token(body) {
|
||||||
|
const data = await this.tokenHandler.execute(body);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data,
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.AuthController = AuthController;
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Post)('login'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Login and obtain access token' }),
|
||||||
|
__param(0, (0, common_1.Body)()),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [login_dto_1.LoginDto]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], AuthController.prototype, "login", null);
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Post)('token'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Obtain access token using client credentials' }),
|
||||||
|
__param(0, (0, common_1.Body)()),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [Object]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], AuthController.prototype, "token", null);
|
||||||
|
exports.AuthController = AuthController = __decorate([
|
||||||
|
(0, swagger_1.ApiTags)('Auth'),
|
||||||
|
(0, common_1.Controller)('api/v1/auth'),
|
||||||
|
__metadata("design:paramtypes", [login_handler_1.LoginHandler,
|
||||||
|
token_handler_1.TokenHandler])
|
||||||
|
], AuthController);
|
||||||
|
//# sourceMappingURL=auth.controller.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../../../src/modules/identity/presentation/controllers/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwD;AACxD,6CAAwD;AAExD,gDAA4C;AAC5C,4EAAwE;AACxE,4EAAwE;AAIjE,IAAM,cAAc,GAApB,MAAM,cAAc;IAEN;IACA;IAFnB,YACmB,YAA0B,EAC1B,YAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAc;QAC1B,iBAAY,GAAZ,YAAY,CAAc;IAC1C,CAAC;IAIE,AAAN,KAAK,CAAC,KAAK,CAAS,GAAa;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAElD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI;YACJ,IAAI,EAAE,EAAE;SACT,CAAC;IACJ,CAAC;IAIK,AAAN,KAAK,CAAC,KAAK,CAAS,IAAS;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEnD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI;YACJ,IAAI,EAAE,EAAE;SACT,CAAC;IACJ,CAAC;CACF,CAAA;AA7BY,wCAAc;AAQnB;IAFL,IAAA,aAAI,EAAC,OAAO,CAAC;IACb,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;IAC9C,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAM,oBAAQ;;2CAQhC;AAIK;IAFL,IAAA,aAAI,EAAC,OAAO,CAAC;IACb,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;IAC7D,WAAA,IAAA,aAAI,GAAE,CAAA;;;;2CAQlB;yBA5BU,cAAc;IAF1B,IAAA,iBAAO,EAAC,MAAM,CAAC;IACf,IAAA,mBAAU,EAAC,aAAa,CAAC;qCAGS,4BAAY;QACZ,4BAAY;GAHlC,cAAc,CA6B1B"}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||||
|
return function (target, key) { decorator(target, key, paramIndex); }
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UsersController = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
const jwt_auth_guard_1 = require("../../../../core/auth/guards/jwt-auth.guard");
|
||||||
|
const permission_guard_1 = require("../../../authorization/presentation/guards/permission.guard");
|
||||||
|
const permission_decorator_1 = require("../../../authorization/presentation/decorators/permission.decorator");
|
||||||
|
const find_user_handler_1 = require("../../application/handlers/find-user.handler");
|
||||||
|
const find_users_handler_1 = require("../../application/handlers/find-users.handler");
|
||||||
|
const create_user_handler_1 = require("../../application/handlers/create-user.handler");
|
||||||
|
const update_user_handler_1 = require("../../application/handlers/update-user.handler");
|
||||||
|
const delete_user_handler_1 = require("../../application/handlers/delete-user.handler");
|
||||||
|
const create_user_dto_1 = require("../dto/create-user.dto");
|
||||||
|
const update_user_dto_1 = require("../dto/update-user.dto");
|
||||||
|
let UsersController = class UsersController {
|
||||||
|
createUserHandler;
|
||||||
|
findUserHandler;
|
||||||
|
findUsersHandler;
|
||||||
|
updateUserHandler;
|
||||||
|
deleteUserHandler;
|
||||||
|
constructor(createUserHandler, findUserHandler, findUsersHandler, updateUserHandler, deleteUserHandler) {
|
||||||
|
this.createUserHandler = createUserHandler;
|
||||||
|
this.findUserHandler = findUserHandler;
|
||||||
|
this.findUsersHandler = findUsersHandler;
|
||||||
|
this.updateUserHandler = updateUserHandler;
|
||||||
|
this.deleteUserHandler = deleteUserHandler;
|
||||||
|
}
|
||||||
|
sanitizeUser(user) {
|
||||||
|
if (!user)
|
||||||
|
return user;
|
||||||
|
if (Array.isArray(user)) {
|
||||||
|
return user.map(u => {
|
||||||
|
const { password, ...rest } = u;
|
||||||
|
return rest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { password, ...rest } = user;
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
async create(dto) {
|
||||||
|
const data = await this.createUserHandler.execute(dto);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async getById(id) {
|
||||||
|
const data = await this.findUserHandler.execute(id);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async getAll() {
|
||||||
|
const data = await this.findUsersHandler.execute();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async update(id, dto) {
|
||||||
|
const data = await this.updateUserHandler.execute(id, dto);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async delete(id) {
|
||||||
|
await this.deleteUserHandler.execute(id);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: null,
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.UsersController = UsersController;
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Post)(),
|
||||||
|
(0, permission_decorator_1.Permissions)('USER_CREATE'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Create user' }),
|
||||||
|
__param(0, (0, common_1.Body)()),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [create_user_dto_1.CreateUserDto]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], UsersController.prototype, "create", null);
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Get)(':id'),
|
||||||
|
(0, permission_decorator_1.Permissions)('USER_READ'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Get user by id' }),
|
||||||
|
__param(0, (0, common_1.Param)('id')),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [String]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], UsersController.prototype, "getById", null);
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Get)(),
|
||||||
|
(0, permission_decorator_1.Permissions)('USER_READ_ADMIN'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Get All User' }),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", []),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], UsersController.prototype, "getAll", null);
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Patch)(':id'),
|
||||||
|
(0, permission_decorator_1.Permissions)('USER_UPDATE'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Update User' }),
|
||||||
|
__param(0, (0, common_1.Param)('id')),
|
||||||
|
__param(1, (0, common_1.Body)()),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [String, update_user_dto_1.UpdateUserDto]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], UsersController.prototype, "update", null);
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Delete)(':id'),
|
||||||
|
(0, permission_decorator_1.Permissions)('USER_DELETE'),
|
||||||
|
(0, swagger_1.ApiOperation)({ summary: 'Delete user by id' }),
|
||||||
|
__param(0, (0, common_1.Param)('id')),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [String]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], UsersController.prototype, "delete", null);
|
||||||
|
exports.UsersController = UsersController = __decorate([
|
||||||
|
(0, swagger_1.ApiTags)('Users'),
|
||||||
|
(0, common_1.Controller)('api/v1/users'),
|
||||||
|
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, permission_guard_1.PermissionGuard),
|
||||||
|
__metadata("design:paramtypes", [create_user_handler_1.CreateUserHandler,
|
||||||
|
find_user_handler_1.FindUserHandler,
|
||||||
|
find_users_handler_1.FindUsersHandler,
|
||||||
|
update_user_handler_1.UpdateUserHandler,
|
||||||
|
delete_user_handler_1.DeleteUserHandler])
|
||||||
|
], UsersController);
|
||||||
|
//# sourceMappingURL=users.controller.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"users.controller.js","sourceRoot":"","sources":["../../../../../src/modules/identity/presentation/controllers/users.controller.ts"],"names":[],"mappings":"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"}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.CreateUserDto = void 0;
|
||||||
|
const class_validator_1 = require("class-validator");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
class CreateUserDto {
|
||||||
|
name;
|
||||||
|
email;
|
||||||
|
password;
|
||||||
|
metadata;
|
||||||
|
}
|
||||||
|
exports.CreateUserDto = CreateUserDto;
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ example: 'John Doe' }),
|
||||||
|
(0, class_validator_1.IsString)(),
|
||||||
|
(0, class_validator_1.IsNotEmpty)(),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], CreateUserDto.prototype, "name", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ example: 'user@example.com' }),
|
||||||
|
(0, class_validator_1.IsEmail)(),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], CreateUserDto.prototype, "email", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ example: 'strongpassword' }),
|
||||||
|
(0, class_validator_1.IsString)(),
|
||||||
|
(0, class_validator_1.Length)(8, 128),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], CreateUserDto.prototype, "password", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ required: false }),
|
||||||
|
__metadata("design:type", Object)
|
||||||
|
], CreateUserDto.prototype, "metadata", void 0);
|
||||||
|
//# sourceMappingURL=create-user.dto.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"create-user.dto.js","sourceRoot":"","sources":["../../../../../src/modules/identity/presentation/dto/create-user.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAwE;AACxE,6CAA8C;AAE9C,MAAa,aAAa;IAIxB,IAAI,CAAU;IAId,KAAK,CAAU;IAKf,QAAQ,CAAU;IAGlB,QAAQ,CAAuB;CAChC;AAjBD,sCAiBC;AAbC;IAHC,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACpC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;2CACC;AAId;IAFC,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC5C,IAAA,yBAAO,GAAE;;4CACK;AAKf;IAHC,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC1C,IAAA,0BAAQ,GAAE;IACV,IAAA,wBAAM,EAAC,CAAC,EAAE,GAAG,CAAC;;+CACG;AAGlB;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;+CACF"}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.LoginDto = void 0;
|
||||||
|
const class_validator_1 = require("class-validator");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
class LoginDto {
|
||||||
|
email;
|
||||||
|
password;
|
||||||
|
}
|
||||||
|
exports.LoginDto = LoginDto;
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ example: 'user@example.com' }),
|
||||||
|
(0, class_validator_1.IsEmail)(),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], LoginDto.prototype, "email", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiProperty)({ example: 'strongpassword' }),
|
||||||
|
(0, class_validator_1.IsString)(),
|
||||||
|
(0, class_validator_1.Length)(8, 128),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], LoginDto.prototype, "password", void 0);
|
||||||
|
//# sourceMappingURL=login.dto.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"login.dto.js","sourceRoot":"","sources":["../../../../../src/modules/identity/presentation/dto/login.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA4D;AAC5D,6CAA8C;AAE9C,MAAa,QAAQ;IAGnB,KAAK,CAAU;IAKf,QAAQ,CAAU;CACnB;AATD,4BASC;AANC;IAFC,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC5C,IAAA,yBAAO,GAAE;;uCACK;AAKf;IAHC,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC1C,IAAA,0BAAQ,GAAE;IACV,IAAA,wBAAM,EAAC,CAAC,EAAE,GAAG,CAAC;;0CACG"}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UpdateUserDto = void 0;
|
||||||
|
const mapped_types_1 = require("@nestjs/mapped-types");
|
||||||
|
const create_user_dto_1 = require("./create-user.dto");
|
||||||
|
const swagger_1 = require("@nestjs/swagger");
|
||||||
|
const class_validator_1 = require("class-validator");
|
||||||
|
class UpdateUserDto extends (0, mapped_types_1.PartialType)(create_user_dto_1.CreateUserDto) {
|
||||||
|
name;
|
||||||
|
email;
|
||||||
|
password;
|
||||||
|
metadata;
|
||||||
|
}
|
||||||
|
exports.UpdateUserDto = UpdateUserDto;
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiPropertyOptional)(),
|
||||||
|
(0, class_validator_1.IsOptional)(),
|
||||||
|
(0, class_validator_1.IsString)(),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], UpdateUserDto.prototype, "name", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiPropertyOptional)(),
|
||||||
|
(0, class_validator_1.IsOptional)(),
|
||||||
|
(0, class_validator_1.IsEmail)(),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], UpdateUserDto.prototype, "email", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiPropertyOptional)(),
|
||||||
|
(0, class_validator_1.IsOptional)(),
|
||||||
|
(0, class_validator_1.Length)(8, 128),
|
||||||
|
__metadata("design:type", String)
|
||||||
|
], UpdateUserDto.prototype, "password", void 0);
|
||||||
|
__decorate([
|
||||||
|
(0, swagger_1.ApiPropertyOptional)(),
|
||||||
|
(0, class_validator_1.IsOptional)(),
|
||||||
|
__metadata("design:type", Object)
|
||||||
|
], UpdateUserDto.prototype, "metadata", void 0);
|
||||||
|
//# sourceMappingURL=update-user.dto.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"update-user.dto.js","sourceRoot":"","sources":["../../../../../src/modules/identity/presentation/dto/update-user.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,uDAAmD;AACnD,uDAAkD;AAClD,6CAAsD;AACtD,qDAAwE;AAExE,MAAa,aAAc,SAAQ,IAAA,0BAAW,EAAC,+BAAa,CAAC;IAI3D,IAAI,CAAU;IAKd,KAAK,CAAU;IAKf,QAAQ,CAAU;IAIlB,QAAQ,CAAuB;CAChC;AAnBD,sCAmBC;AAfC;IAHC,IAAA,6BAAmB,GAAE;IACrB,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;2CACG;AAKd;IAHC,IAAA,6BAAmB,GAAE;IACrB,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;4CACK;AAKf;IAHC,IAAA,6BAAmB,GAAE;IACrB,IAAA,4BAAU,GAAE;IACZ,IAAA,wBAAM,EAAC,CAAC,EAAE,GAAG,CAAC;;+CACG;AAIlB;IAFC,IAAA,6BAAmB,GAAE;IACrB,IAAA,4BAAU,GAAE;;+CACkB"}
|
||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaService = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const client_1 = require("@prisma/client");
|
||||||
|
let PrismaService = class PrismaService extends client_1.PrismaClient {
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.$connect();
|
||||||
|
}
|
||||||
|
async onModuleDestroy() {
|
||||||
|
await this.$disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.PrismaService = PrismaService;
|
||||||
|
exports.PrismaService = PrismaService = __decorate([
|
||||||
|
(0, common_1.Injectable)()
|
||||||
|
], PrismaService);
|
||||||
|
//# sourceMappingURL=prisma.service.js.map
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"prisma.service.js","sourceRoot":"","sources":["../../src/shared/prisma.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA2E;AAC3E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAY;IAC7C,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AARY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAQzB"}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.noop = noop;
|
||||||
|
function noop() { }
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":";;AAAA,oBAAyB;AAAzB,SAAgB,IAAI,KAAI,CAAC"}
|
||||||
+3
-2
@@ -1,12 +1,13 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['**/tests/**/*.spec.ts', '**/?(*.)+(spec|test).ts'],
|
testMatch: ['**/tests/**/*.spec.ts', '**/?(*.)+(spec|test).[tj]s?(x)'],
|
||||||
testPathIgnorePatterns: ['/tests/api/', '/tests/integration/'],
|
testPathIgnorePatterns: ['/tests/api/', '/tests/integration/'],
|
||||||
moduleFileExtensions: ['ts', 'js', 'json'],
|
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
|
||||||
globals: {
|
globals: {
|
||||||
'ts-jest': {
|
'ts-jest': {
|
||||||
tsconfig: 'tsconfig.json',
|
tsconfig: 'tsconfig.json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+21
-255
@@ -1,5 +1,5 @@
|
|||||||
// Prisma schema for RayLab Core - Phase 1
|
// Prisma schema
|
||||||
// PostgreSQL datasource. DATABASE_URL must be set in environment.
|
// Basic User model for RayLab Core
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
@@ -11,261 +11,27 @@ datasource db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid()) @db.Uuid
|
id String @id @default(uuid())
|
||||||
authentikId String? @unique
|
name String
|
||||||
authentikUserId String? @unique
|
email String @unique
|
||||||
authentikSubject String? @unique
|
password String
|
||||||
username String? @unique @db.VarChar(255)
|
status String @default("ACTIVE")
|
||||||
email String? @unique @db.VarChar(320)
|
|
||||||
name String? @db.VarChar(255)
|
|
||||||
picture String?
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
deletedAt DateTime?
|
|
||||||
lastSeenAt DateTime?
|
|
||||||
lastSyncedAt DateTime?
|
|
||||||
syncStatus String?
|
|
||||||
storageQuota BigInt? @default(10737418240)
|
|
||||||
storageUsed BigInt? @default(0)
|
|
||||||
metadata Json?
|
metadata Json?
|
||||||
roles UserRole[]
|
created_at DateTime @default(now())
|
||||||
permissions UserPermission[]
|
updated_at DateTime @updatedAt
|
||||||
auditLogs AuditLog[]
|
deleted_at DateTime?
|
||||||
mediaObjects MediaObject[]
|
|
||||||
lastGroupHash String? @db.Text
|
|
||||||
// relations for debt module
|
|
||||||
debtGroupsOwned DebtGroup[]
|
|
||||||
debtGroupMembers DebtGroupMember[]
|
|
||||||
createdDebtTransactions DebtTransaction[]
|
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([authentikId])
|
|
||||||
@@index([username])
|
|
||||||
@@index([email])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model Role {
|
model ServiceAccount {
|
||||||
id String @id @default(uuid()) @db.Uuid
|
id String @id @default(uuid())
|
||||||
code String @unique @db.VarChar(100)
|
client_id String @unique
|
||||||
name String @db.VarChar(255)
|
client_secret_hash String
|
||||||
displayName String? @db.VarChar(255)
|
name String
|
||||||
description String?
|
role String
|
||||||
isDefault Boolean @default(false)
|
permissions Json
|
||||||
permissions RolePermission[]
|
status String @default("ACTIVE")
|
||||||
userRoles UserRole[]
|
|
||||||
mappings AuthGroupRoleMapping[]
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
model Permission {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
code String @unique @db.VarChar(150)
|
|
||||||
name String @db.VarChar(255)
|
|
||||||
displayName String? @db.VarChar(255)
|
|
||||||
description String?
|
|
||||||
rolePermissions RolePermission[]
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
UserPermission UserPermission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model RolePermission {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
||||||
roleId String @db.Uuid
|
|
||||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
|
||||||
permissionId String @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
@@unique([roleId, permissionId])
|
|
||||||
@@index([roleId])
|
|
||||||
@@index([permissionId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserPermission {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
userId String @db.Uuid
|
|
||||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
|
||||||
permissionId String @db.Uuid
|
|
||||||
assignedBy String? @db.VarChar(100)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
@@unique([userId, permissionId])
|
|
||||||
@@index([userId])
|
|
||||||
@@index([permissionId])
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UserRoleSource {
|
|
||||||
AUTHENTIK
|
|
||||||
SYSTEM
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserRole {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
userId String @db.Uuid
|
|
||||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
||||||
roleId String @db.Uuid
|
|
||||||
source UserRoleSource @default(AUTHENTIK)
|
|
||||||
syncedAt DateTime @default(now())
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
@@unique([userId, roleId])
|
|
||||||
@@index([userId])
|
|
||||||
@@index([roleId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model AuthGroupRoleMapping {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
authGroup String @db.VarChar(255)
|
|
||||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
||||||
roleId String @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([authGroup])
|
|
||||||
}
|
|
||||||
|
|
||||||
model AuditLog {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
||||||
userId String? @db.Uuid
|
|
||||||
action String @db.VarChar(200)
|
|
||||||
resource String? @db.VarChar(200)
|
|
||||||
resourceId String?
|
|
||||||
details Json?
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
@@index([userId])
|
|
||||||
@@index([action])
|
|
||||||
}
|
|
||||||
|
|
||||||
model ScheduledJob {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
name String @db.VarChar(255)
|
|
||||||
payload Json?
|
|
||||||
cron String?
|
|
||||||
runAt DateTime?
|
|
||||||
status String @default("pending") @db.VarChar(50)
|
|
||||||
attempts Int @default(0)
|
|
||||||
lastRunAt DateTime?
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([name])
|
|
||||||
@@index([status])
|
|
||||||
}
|
|
||||||
|
|
||||||
model MediaObject {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
ownerUserId String? @db.Uuid
|
|
||||||
owner User? @relation(fields: [ownerUserId], references: [id], onDelete: SetNull)
|
|
||||||
storageKey String @db.VarChar(1024)
|
|
||||||
filename String? @db.VarChar(1024)
|
|
||||||
mimeType String? @db.VarChar(255)
|
|
||||||
size BigInt?
|
|
||||||
isPublic Boolean @default(false)
|
|
||||||
metadata Json?
|
metadata Json?
|
||||||
createdAt DateTime @default(now())
|
created_at DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updated_at DateTime @updatedAt
|
||||||
|
deleted_at DateTime?
|
||||||
@@index([ownerUserId])
|
|
||||||
@@index([storageKey])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model Application {
|
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @map("id") @db.Uuid
|
|
||||||
code String @unique @map("code") @db.VarChar(100)
|
|
||||||
name String @map("name") @db.VarChar(255)
|
|
||||||
description String? @map("description") @db.Text
|
|
||||||
icon String? @map("icon") @db.Text
|
|
||||||
url String? @map("url") @db.Text
|
|
||||||
applicationsClaim String @unique @map("applicationsClaim") @db.VarChar(255)
|
|
||||||
isActive Boolean @default(true) @map("isActive")
|
|
||||||
displayOrder Int @default(0) @map("displayOrder") @db.Integer
|
|
||||||
createdAt DateTime @default(dbgenerated("now()")) @map("createdAt") @db.Timestamptz
|
|
||||||
updatedAt DateTime @default(dbgenerated("now()")) @map("updatedAt") @db.Timestamptz
|
|
||||||
|
|
||||||
@@index([code], name: "Application_code_idx")
|
|
||||||
@@index([applicationsClaim], name: "Application_applicationsClaim_idx")
|
|
||||||
@@map("Application")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debt management models for /api/bot/debt
|
|
||||||
|
|
||||||
enum DebtTransactionType {
|
|
||||||
DEBT
|
|
||||||
PAYMENT
|
|
||||||
}
|
|
||||||
|
|
||||||
model DebtGroup {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
publicId String @unique @db.VarChar(20) // e.g. RL-X7K29P
|
|
||||||
name String @db.VarChar(255)
|
|
||||||
ownerId String @db.Uuid
|
|
||||||
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
|
|
||||||
members DebtGroupMember[]
|
|
||||||
people DebtPerson[]
|
|
||||||
transactions DebtTransaction[]
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([publicId])
|
|
||||||
@@index([ownerId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model DebtGroupMember {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
group DebtGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
||||||
groupId String @db.Uuid
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
userId String @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
@@unique([groupId, userId])
|
|
||||||
@@index([groupId])
|
|
||||||
@@index([userId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model DebtPerson {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
group DebtGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
||||||
groupId String @db.Uuid
|
|
||||||
name String @db.VarChar(255)
|
|
||||||
isDeleted Boolean @default(false)
|
|
||||||
// relations back to transactions
|
|
||||||
transactionsFrom DebtTransaction[] @relation("fromPerson")
|
|
||||||
transactionsTo DebtTransaction[] @relation("toPerson")
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@unique([groupId, name])
|
|
||||||
@@index([groupId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model DebtTransaction {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
group DebtGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
||||||
groupId String @db.Uuid
|
|
||||||
fromPerson DebtPerson @relation("fromPerson", fields: [fromPersonId], references: [id], onDelete: Restrict)
|
|
||||||
fromPersonId String @db.Uuid
|
|
||||||
toPerson DebtPerson @relation("toPerson", fields: [toPersonId], references: [id], onDelete: Restrict)
|
|
||||||
toPersonId String @db.Uuid
|
|
||||||
amount BigInt @db.BigInt
|
|
||||||
type DebtTransactionType
|
|
||||||
description String?
|
|
||||||
transactionDate DateTime @db.Date
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
createdByUserId String @db.Uuid
|
|
||||||
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: SetNull)
|
|
||||||
requestId String? @db.VarChar(255)
|
|
||||||
|
|
||||||
@@index([groupId])
|
|
||||||
@@index([fromPersonId])
|
|
||||||
@@index([toPersonId])
|
|
||||||
@@unique([groupId, requestId])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+25
-152
@@ -1,171 +1,44 @@
|
|||||||
/**
|
|
||||||
* Prisma seed script for RayLab Core - Phase 1
|
|
||||||
* Run with: npx ts-node prisma/seed.ts
|
|
||||||
* Requires DATABASE_URL env var.
|
|
||||||
*/
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('Seeding default roles, permissions, and mappings...');
|
const clientId = 'raylab-telegram-bot';
|
||||||
|
const clientSecret = crypto.randomBytes(32).toString('hex');
|
||||||
|
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '10', 10);
|
||||||
|
const clientSecretHash = await bcrypt.hash(clientSecret, saltRounds);
|
||||||
|
|
||||||
// Default roles
|
// Create service account only if not exists
|
||||||
const roles = [
|
const existing = await prisma.serviceAccount.findUnique({ where: { client_id: clientId } });
|
||||||
{ name: 'Owner', displayName: 'Owner', description: 'Platform owner with full access' },
|
|
||||||
{ name: 'Employee', displayName: 'Employee', description: 'Employee role with internal permissions' },
|
|
||||||
{ name: 'Family', displayName: 'Family', description: 'Family role with limited access' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const r of roles) {
|
|
||||||
const code = r.name.toLowerCase();
|
|
||||||
await prisma.role.upsert({
|
|
||||||
where: { code },
|
|
||||||
update: { name: r.name, displayName: r.displayName, description: r.description },
|
|
||||||
create: { code, name: r.name, displayName: r.displayName, description: r.description },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default permissions (resource.action lowercase as requested)
|
|
||||||
const permissions = [
|
|
||||||
'users.create',
|
|
||||||
'users.read',
|
|
||||||
'users.update',
|
|
||||||
'users.delete',
|
|
||||||
'roles.create',
|
|
||||||
'roles.read',
|
|
||||||
'roles.update',
|
|
||||||
'roles.delete',
|
|
||||||
'permissions.create',
|
|
||||||
'permissions.read',
|
|
||||||
'permissions.update',
|
|
||||||
'permissions.delete',
|
|
||||||
'audit.read',
|
|
||||||
'storage.read',
|
|
||||||
'storage.write',
|
|
||||||
'storage.delete',
|
|
||||||
'media.read',
|
|
||||||
'media.write',
|
|
||||||
'media.delete',
|
|
||||||
'scheduler.read',
|
|
||||||
'scheduler.manage',
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const p of permissions) {
|
|
||||||
// Use code as canonical identifier (resource.action). Use name == code for now.
|
|
||||||
const code = p;
|
|
||||||
await prisma.permission.upsert({
|
|
||||||
where: { code },
|
|
||||||
update: { name: p, description: null },
|
|
||||||
create: { code, name: p, description: null },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign permissions to roles (example mapping)
|
|
||||||
const owner = await prisma.role.findUnique({ where: { code: 'owner' } });
|
|
||||||
const employee = await prisma.role.findUnique({ where: { code: 'employee' } });
|
|
||||||
const family = await prisma.role.findUnique({ where: { code: 'family' } });
|
|
||||||
|
|
||||||
if (!owner || !employee || !family) {
|
|
||||||
throw new Error('Default roles missing after upsert');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Owner -> all permissions
|
|
||||||
const allPerms = await prisma.permission.findMany();
|
|
||||||
for (const perm of allPerms) {
|
|
||||||
await prisma.rolePermission.upsert({
|
|
||||||
where: { roleId_permissionId: { roleId: owner.id, permissionId: perm.id } },
|
|
||||||
update: {},
|
|
||||||
create: { roleId: owner.id, permissionId: perm.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Employee -> a subset
|
|
||||||
const employeePerms = [
|
|
||||||
'users.read',
|
|
||||||
'permissions.read',
|
|
||||||
'scheduler.read',
|
|
||||||
'scheduler.manage',
|
|
||||||
'media.read',
|
|
||||||
'media.write',
|
|
||||||
];
|
|
||||||
for (const p of employeePerms) {
|
|
||||||
const perm = await prisma.permission.findUnique({ where: { code: p } });
|
|
||||||
if (perm) {
|
|
||||||
await prisma.rolePermission.upsert({
|
|
||||||
where: { roleId_permissionId: { roleId: employee.id, permissionId: perm.id } },
|
|
||||||
update: {},
|
|
||||||
create: { roleId: employee.id, permissionId: perm.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Family -> limited
|
|
||||||
const familyPerms = [
|
|
||||||
'media.read',
|
|
||||||
'media.write',
|
|
||||||
'media.delete',
|
|
||||||
];
|
|
||||||
for (const p of familyPerms) {
|
|
||||||
const perm = await prisma.permission.findUnique({ where: { code: p } });
|
|
||||||
if (perm) {
|
|
||||||
await prisma.rolePermission.upsert({
|
|
||||||
where: { roleId_permissionId: { roleId: family.id, permissionId: perm.id } },
|
|
||||||
update: {},
|
|
||||||
create: { roleId: family.id, permissionId: perm.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authentik group mappings
|
|
||||||
const mappings = [
|
|
||||||
{ authGroup: 'RL-Owner', roleName: 'Owner' },
|
|
||||||
{ authGroup: 'RL-Employee', roleName: 'Employee' },
|
|
||||||
{ authGroup: 'RL-Family', roleName: 'Family' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const m of mappings) {
|
|
||||||
const role = await prisma.role.findUnique({ where: { name: m.roleName } });
|
|
||||||
if (!role) continue;
|
|
||||||
// Ensure mapping exists (authGroup + roleId). AuthGroup can map to multiple roles.
|
|
||||||
const existing = await prisma.authGroupRoleMapping.findFirst({ where: { authGroup: m.authGroup, roleId: role.id } });
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
await prisma.authGroupRoleMapping.create({ data: { authGroup: m.authGroup, roleId: role.id } });
|
const sa = await prisma.serviceAccount.create({
|
||||||
}
|
data: {
|
||||||
}
|
client_id: clientId,
|
||||||
|
client_secret_hash: clientSecretHash,
|
||||||
// Seed application catalog
|
name: 'Telegram Bot',
|
||||||
const apps = [
|
role: 'BOT',
|
||||||
{ code: 'core', name: 'Core', description: 'RayLab Core Dashboard', icon: 'mdi-apps', url: '/', applicationsClaim: 'core', displayOrder: 0 },
|
permissions: ['DEBT_CREATE', 'DEBT_READ', 'DEBT_SETTLE'],
|
||||||
{ code: 'warung', name: 'Warung', description: 'Warung app', icon: 'mdi-store', url: '/warung', applicationsClaim: 'warung', displayOrder: 10 },
|
status: 'ACTIVE',
|
||||||
{ code: 'nextcloud', name: 'Nextcloud', description: 'Nextcloud', icon: 'mdi-cloud', url: 'https://nextcloud.example', applicationsClaim: 'nextcloud', displayOrder: 20 },
|
},
|
||||||
{ code: 'jellyfin', name: 'Jellyfin', description: 'Jellyfin media server', icon: 'mdi-movie', url: 'https://jellyfin.example', applicationsClaim: 'jellyfin', displayOrder: 30 },
|
|
||||||
{ code: 'forgejo', name: 'Forgejo', description: 'Forgejo git server', icon: 'mdi-source-repository', url: 'https://forgejo.example', applicationsClaim: 'forgejo', displayOrder: 40 },
|
|
||||||
{ code: 'immich', name: 'Immich', description: 'Immich photo server', icon: 'mdi-image', url: 'https://immich.example', applicationsClaim: 'immich', displayOrder: 50 },
|
|
||||||
{ code: 'grafana', name: 'Grafana', description: 'Grafana monitoring', icon: 'mdi-chart-line', url: 'https://grafana.example', applicationsClaim: 'grafana', displayOrder: 60 },
|
|
||||||
{ code: 'vaultwarden', name: 'Vaultwarden', description: 'Vaultwarden password manager', icon: 'mdi-lock', url: 'https://vaultwarden.example', applicationsClaim: 'vaultwarden', displayOrder: 70 },
|
|
||||||
{ code: 'homepage', name: 'Homepage', description: 'Homepage', icon: 'mdi-home', url: 'https://home.example', applicationsClaim: 'homepage', displayOrder: 80 },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const a of apps) {
|
|
||||||
await prisma.application.upsert({
|
|
||||||
where: { code: a.code },
|
|
||||||
update: { name: a.name, description: a.description, icon: a.icon, url: a.url, applicationsClaim: a.applicationsClaim, isActive: true, displayOrder: a.displayOrder },
|
|
||||||
create: { code: a.code, name: a.name, description: a.description, icon: a.icon, url: a.url, applicationsClaim: a.applicationsClaim, isActive: true, displayOrder: a.displayOrder },
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Seeding completed.');
|
console.log('Service account created for development/testing.');
|
||||||
|
console.log('Client ID:', clientId);
|
||||||
|
console.log('Client Secret (one-time):', clientSecret);
|
||||||
|
console.log('Please store the client secret securely.');
|
||||||
|
} else {
|
||||||
|
console.log('Service account already exists.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
.catch(async (e) => {
|
.catch(e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
await prisma.$disconnect();
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
export type TokenResponse = {
|
||||||
|
access_token: string;
|
||||||
|
token_type: string;
|
||||||
|
expires_in: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CoreApiClientError extends Error {
|
||||||
|
public status?: number;
|
||||||
|
constructor(message: string, status?: number) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'CoreApiClientError';
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CoreApiClient {
|
||||||
|
private apiUrl: string;
|
||||||
|
private clientId: string;
|
||||||
|
private clientSecret: string;
|
||||||
|
private timeoutMs: number;
|
||||||
|
|
||||||
|
private cachedToken: string | null = null;
|
||||||
|
private tokenExpiry: number = 0; // epoch ms
|
||||||
|
private tokenMarginSec = 60; // safety margin in seconds
|
||||||
|
|
||||||
|
constructor(options?: { apiUrl?: string; clientId?: string; clientSecret?: string; timeoutMs?: number }) {
|
||||||
|
this.apiUrl = options?.apiUrl ?? process.env.RAYLAB_CORE_API_URL ?? 'http://localhost:3000';
|
||||||
|
this.clientId = options?.clientId ?? process.env.RAYLAB_BOT_CLIENT_ID ?? '';
|
||||||
|
this.clientSecret = options?.clientSecret ?? process.env.RAYLAB_BOT_CLIENT_SECRET ?? '';
|
||||||
|
this.timeoutMs = options?.timeoutMs ?? 5000;
|
||||||
|
|
||||||
|
if (!this.clientId || !this.clientSecret) {
|
||||||
|
// keep construction allowed but operations will fail with clear errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchWithTimeout(url: string, init: RequestInit) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const id = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, { ...init, signal: controller.signal });
|
||||||
|
return res;
|
||||||
|
} finally {
|
||||||
|
clearTimeout(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isTokenValid() {
|
||||||
|
return !!this.cachedToken && Date.now() < this.tokenExpiry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async requestAccessToken(): Promise<TokenResponse> {
|
||||||
|
if (!this.clientId || !this.clientSecret) {
|
||||||
|
throw new CoreApiClientError('Missing client credentials');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${this.apiUrl.replace(/\/$/, '')}/api/v1/auth/token`;
|
||||||
|
|
||||||
|
const body = JSON.stringify({ client_id: this.clientId, client_secret: this.clientSecret, grant_type: 'client_credentials' });
|
||||||
|
|
||||||
|
let res: Response;
|
||||||
|
try {
|
||||||
|
res = await this.fetchWithTimeout(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
throw new CoreApiClientError('Request timeout');
|
||||||
|
}
|
||||||
|
throw new CoreApiClientError('Network error');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.status === 401) {
|
||||||
|
throw new CoreApiClientError('Invalid client credentials', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.status >= 400) {
|
||||||
|
throw new CoreApiClientError(`Token request failed with status ${res.status}`, res.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = await res.json();
|
||||||
|
// Expecting { success: true, data: { access_token, token_type, expires_in }, ... }
|
||||||
|
const data = payload?.data;
|
||||||
|
if (!data || !data.access_token) {
|
||||||
|
throw new CoreApiClientError('Invalid token response');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache token
|
||||||
|
this.cachedToken = data.access_token;
|
||||||
|
const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : parseInt(data.expires_in, 10) || 3600;
|
||||||
|
const effective = Math.max(0, expiresIn - this.tokenMarginSec);
|
||||||
|
this.tokenExpiry = Date.now() + effective * 1000;
|
||||||
|
|
||||||
|
return { access_token: data.access_token, token_type: data.token_type ?? 'Bearer', expires_in: expiresIn };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getToken(): Promise<string> {
|
||||||
|
if (this.isTokenValid()) {
|
||||||
|
return this.cachedToken as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenResp = await this.requestAccessToken();
|
||||||
|
return tokenResp.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async authenticatedRequest(input: RequestInfo, init?: RequestInit, retry = true): Promise<Response> {
|
||||||
|
const token = await this.getToken();
|
||||||
|
|
||||||
|
const headers = new Headers(init?.headers as HeadersInit);
|
||||||
|
headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
headers.set('Accept', 'application/json');
|
||||||
|
|
||||||
|
let res: Response;
|
||||||
|
try {
|
||||||
|
res = await this.fetchWithTimeout(typeof input === 'string' ? input : (input as Request).url, {
|
||||||
|
...init,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
throw new CoreApiClientError('Request timeout');
|
||||||
|
}
|
||||||
|
throw new CoreApiClientError('Network error');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.status === 401 && retry) {
|
||||||
|
// invalidate token and retry once
|
||||||
|
this.cachedToken = null;
|
||||||
|
this.tokenExpiry = 0;
|
||||||
|
try {
|
||||||
|
const newToken = await this.getToken();
|
||||||
|
const headers2 = new Headers(init?.headers as HeadersInit);
|
||||||
|
headers2.set('Authorization', `Bearer ${newToken}`);
|
||||||
|
headers2.set('Accept', 'application/json');
|
||||||
|
const res2 = await this.fetchWithTimeout(typeof input === 'string' ? input : (input as Request).url, {
|
||||||
|
...init,
|
||||||
|
headers: headers2,
|
||||||
|
});
|
||||||
|
return res2;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import {
|
||||||
|
Injectable,
|
||||||
|
ConflictException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import { CreateUserDto } from '../../presentation/dto/create-user.dto';
|
||||||
|
import { User } from '../../domain/entities/user.entity';
|
||||||
|
import { UserRepository } from '../../domain/repositories/user.repository.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CreateUserHandler {
|
||||||
|
constructor(
|
||||||
|
private readonly userRepository: UserRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(dto: CreateUserDto): Promise<User> {
|
||||||
|
const exists = await this.userRepository.existsByEmail(dto.email);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
throw new ConflictException('Email already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '10', 10);
|
||||||
|
const hashedPassword = await bcrypt.hash(dto.password, saltRounds);
|
||||||
|
|
||||||
|
const user = User.create({
|
||||||
|
name: dto.name,
|
||||||
|
email: dto.email,
|
||||||
|
password: hashedPassword,
|
||||||
|
metadata: dto.metadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.userRepository.create(user);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// this.eventDispatcher.publish(new UserCreatedEvent(user));
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
|
||||||
|
import { LoginDto } from '../../presentation/dto/login.dto';
|
||||||
|
import { UserRepository } from '../../domain/repositories/user.repository.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LoginHandler {
|
||||||
|
constructor(
|
||||||
|
private readonly userRepository: UserRepository,
|
||||||
|
private readonly jwtService: JwtService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(dto: LoginDto) {
|
||||||
|
const user = await this.userRepository.findByEmail(dto.email);
|
||||||
|
|
||||||
|
// Generic error message for security
|
||||||
|
const unauthorizedMsg = 'Invalid credentials.';
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMatch = await bcrypt.compare(dto.password, user.password);
|
||||||
|
|
||||||
|
if (!isMatch) {
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build payload according to existing JwtPayload interface
|
||||||
|
const metadata = user.metadata ?? {};
|
||||||
|
|
||||||
|
const role = typeof metadata.role === 'string' ? metadata.role : 'USER';
|
||||||
|
|
||||||
|
const permissions = Array.isArray(metadata.permissions) ? metadata.permissions : [];
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
sub: user.id,
|
||||||
|
email: user.email,
|
||||||
|
role,
|
||||||
|
permissions,
|
||||||
|
};
|
||||||
|
|
||||||
|
const accessToken = await this.jwtService.signAsync(payload);
|
||||||
|
|
||||||
|
return {
|
||||||
|
access_token: accessToken,
|
||||||
|
expires_in: '1d',
|
||||||
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { Injectable, BadRequestException, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { ServiceAccountRepository } from '../../domain/repositories/service-account.repository.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TokenHandler {
|
||||||
|
constructor(
|
||||||
|
private readonly serviceAccountRepository: ServiceAccountRepository,
|
||||||
|
private readonly jwtService: JwtService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(body: { client_id?: string; client_secret?: string; grant_type?: string }) {
|
||||||
|
const { client_id, client_secret, grant_type } = body;
|
||||||
|
|
||||||
|
if (grant_type !== 'client_credentials') {
|
||||||
|
throw new BadRequestException('Invalid grant_type.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const unauthorizedMsg = 'Invalid client credentials.';
|
||||||
|
|
||||||
|
if (!client_id || !client_secret) {
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceAccount = await this.serviceAccountRepository.findByClientId(client_id);
|
||||||
|
|
||||||
|
if (!serviceAccount) {
|
||||||
|
// generic error
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check status
|
||||||
|
if (serviceAccount.status !== 'ACTIVE') {
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = await bcrypt.compare(client_secret, serviceAccount.clientSecretHash);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
throw new UnauthorizedException(unauthorizedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload: any = {
|
||||||
|
sub: serviceAccount.id,
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
// existing JwtPayload expects email; provide empty string to remain compatible
|
||||||
|
email: '',
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions ?? [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const accessToken = await this.jwtService.signAsync(payload, {
|
||||||
|
expiresIn: '1h',
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
access_token: accessToken,
|
||||||
|
token_type: 'Bearer',
|
||||||
|
expires_in: 3600,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
Injectable,
|
||||||
|
ConflictException,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import { UpdateUserDto } from '../../presentation/dto/update-user.dto';
|
||||||
|
import { UserRepository } from '../../domain/repositories/user.repository.interface';
|
||||||
|
import { User } from '../../domain/entities/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UpdateUserHandler {
|
||||||
|
constructor(
|
||||||
|
private readonly userRepository: UserRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
id: string,
|
||||||
|
dto: UpdateUserDto,
|
||||||
|
): Promise<User> {
|
||||||
|
const user = await this.userRepository.findById(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('User not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
dto.email &&
|
||||||
|
dto.email !== user.email
|
||||||
|
) {
|
||||||
|
const exists =
|
||||||
|
await this.userRepository.existsByEmail(dto.email);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
throw new ConflictException(
|
||||||
|
'Email already exists.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
user.changeEmail(dto.email);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.name) {
|
||||||
|
user.changeName(dto.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.password) {
|
||||||
|
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '10', 10);
|
||||||
|
const hashedPassword = await bcrypt.hash(dto.password, saltRounds);
|
||||||
|
user.changePassword(hashedPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.userRepository.update(user);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
export class ServiceAccount {
|
||||||
|
private constructor(
|
||||||
|
public readonly id: string,
|
||||||
|
public clientId: string,
|
||||||
|
public clientSecretHash: string,
|
||||||
|
public name: string,
|
||||||
|
public role: string,
|
||||||
|
public permissions: string[],
|
||||||
|
public status: string,
|
||||||
|
public metadata?: Record<string, any>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
static create(data: {
|
||||||
|
clientId: string;
|
||||||
|
clientSecretHash: string;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
permissions: string[];
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}): ServiceAccount {
|
||||||
|
return new ServiceAccount(
|
||||||
|
crypto.randomUUID(),
|
||||||
|
data.clientId,
|
||||||
|
data.clientSecretHash,
|
||||||
|
data.name,
|
||||||
|
data.role,
|
||||||
|
data.permissions,
|
||||||
|
'ACTIVE',
|
||||||
|
data.metadata,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static restore(data: {
|
||||||
|
id: string;
|
||||||
|
clientId: string;
|
||||||
|
clientSecretHash: string;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
permissions: string[];
|
||||||
|
status: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}): ServiceAccount {
|
||||||
|
return new ServiceAccount(
|
||||||
|
data.id,
|
||||||
|
data.clientId,
|
||||||
|
data.clientSecretHash,
|
||||||
|
data.name,
|
||||||
|
data.role,
|
||||||
|
data.permissions,
|
||||||
|
data.status,
|
||||||
|
data.metadata,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
this.status = 'DISABLED';
|
||||||
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
this.status = 'ACTIVE';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,192 +1,56 @@
|
|||||||
import { RoleData } from "./role.entity";
|
export class User {
|
||||||
import { PermissionData } from "./permission.entity";
|
|
||||||
import crypto from 'crypto';
|
|
||||||
|
|
||||||
export class UserData {
|
|
||||||
private constructor(
|
private constructor(
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
public authentikId: string | null,
|
public name: string,
|
||||||
public username: string,
|
|
||||||
public email: string,
|
public email: string,
|
||||||
public roles: RoleData[],
|
public password: string,
|
||||||
public permissions: PermissionData[],
|
public metadata?: Record<string, any>,
|
||||||
public isActive: boolean,
|
|
||||||
public deletedAt: Date | null,
|
|
||||||
public lastSeenAt: Date | null,
|
|
||||||
public storageQuota: number,
|
|
||||||
public storageUsed: number,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
//#region Create
|
|
||||||
|
|
||||||
static create(data: {
|
static create(data: {
|
||||||
username: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
authentikId?: string | null;
|
password: string;
|
||||||
storageQuota?: number;
|
metadata?: Record<string, any>;
|
||||||
storageUsed?: number;
|
}): User {
|
||||||
}): UserData {
|
return new User(
|
||||||
const quota = data.storageQuota !== undefined ? data.storageQuota : 10737418240; // 10 GB
|
|
||||||
const used = data.storageUsed !== undefined ? data.storageUsed : 0;
|
|
||||||
return new UserData(
|
|
||||||
crypto.randomUUID(),
|
crypto.randomUUID(),
|
||||||
data.authentikId || null,
|
data.name,
|
||||||
data.username,
|
|
||||||
data.email,
|
data.email,
|
||||||
[],
|
data.password,
|
||||||
[],
|
data.metadata,
|
||||||
true,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
quota,
|
|
||||||
used,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
delete() {
|
||||||
|
// Business Rule
|
||||||
//#region Read
|
|
||||||
|
|
||||||
hasRole(roleId: string) : boolean {
|
|
||||||
return this.roles.some(x => x.id.toLowerCase() === roleId.toLowerCase())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assignRole(roleData : RoleData) : void {
|
|
||||||
if (this.hasRole(roleData.id))
|
|
||||||
throw new Error("Role Sudah dimiliki.");
|
|
||||||
|
|
||||||
this.roles.push(roleData);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPermissions(permissionId : string) : boolean {
|
|
||||||
return this.permissions.some(x => x.id.toLowerCase() === permissionId.toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPermission(permission: string) : boolean {
|
|
||||||
const byPerm = this.permissions.some(x => x.id.toLowerCase() === permission.toLowerCase() || x.name.toLowerCase() === permission.toLowerCase());
|
|
||||||
if (byPerm) return true;
|
|
||||||
|
|
||||||
// check roles
|
|
||||||
return this.roles.some(r => r.permissions.some(p => p.id.toLowerCase() === permission.toLowerCase() || p.name.toLowerCase() === permission.toLowerCase()));
|
|
||||||
}
|
|
||||||
|
|
||||||
assignPermission(permissionData : PermissionData) : void {
|
|
||||||
if (this.hasPermissions(permissionData.id))
|
|
||||||
throw new Error("Permission sudah dimiliki.")
|
|
||||||
|
|
||||||
this.permissions.push(permissionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Update
|
|
||||||
changeEmail(email: string) {
|
changeEmail(email: string) {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeUsername(username: string) {
|
changeName(name: string) {
|
||||||
this.username = username;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
touchLastSeen() {
|
changePassword(newPassword: string) {
|
||||||
this.lastSeenAt = new Date();
|
this.password = newPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
static restore(data: {
|
||||||
this.isActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
disable() {
|
|
||||||
this.isActive = false;
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Delete
|
|
||||||
softDelete() {
|
|
||||||
this.deletedAt = new Date();
|
|
||||||
this.isActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreInstance() {
|
|
||||||
this.deletedAt = null;
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
public static restore(props: {
|
|
||||||
id: string;
|
id: string;
|
||||||
authentikId?: string | null;
|
name: string;
|
||||||
username: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
roles?: RoleData[];
|
password: string;
|
||||||
permissions?: PermissionData[];
|
metadata?: Record<string, any>;
|
||||||
isActive?: boolean;
|
}): User {
|
||||||
deletedAt?: Date | null;
|
return new User(
|
||||||
lastSeenAt?: Date | null;
|
data.id,
|
||||||
storageQuota?: number | null;
|
data.name,
|
||||||
storageUsed?: number | null;
|
data.email,
|
||||||
}): UserData {
|
data.password,
|
||||||
|
data.metadata,
|
||||||
return new UserData(
|
|
||||||
props.id,
|
|
||||||
props.authentikId || null,
|
|
||||||
props.username,
|
|
||||||
props.email,
|
|
||||||
props.roles || [],
|
|
||||||
props.permissions || [],
|
|
||||||
props.isActive !== undefined ? props.isActive : true,
|
|
||||||
props.deletedAt || null,
|
|
||||||
props.lastSeenAt || null,
|
|
||||||
props.storageQuota !== undefined && props.storageQuota !== null ? props.storageQuota : 10737418240,
|
|
||||||
props.storageUsed !== undefined && props.storageUsed !== null ? props.storageUsed : 0,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRole(roleId: string) {
|
|
||||||
const idx = this.roles.findIndex(r => r.id.toLowerCase() === roleId.toLowerCase());
|
|
||||||
if (idx === -1) throw new Error('Role tidak ditemukan pada user.');
|
|
||||||
this.roles.splice(idx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
removePermission(permissionId: string) {
|
|
||||||
const idx = this.permissions.findIndex(p => p.id.toLowerCase() === permissionId.toLowerCase());
|
|
||||||
if (idx === -1) throw new Error('Permission tidak ditemukan pada user.');
|
|
||||||
this.permissions.splice(idx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage helpers
|
|
||||||
setStorageQuota(bytes: number) {
|
|
||||||
if (bytes < 0) throw new Error('storageQuota must be >= 0');
|
|
||||||
if (this.storageUsed > bytes) throw new Error('storageQuota cannot be less than storageUsed');
|
|
||||||
this.storageQuota = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStorageUsed(bytes: number) {
|
|
||||||
if (bytes < 0) throw new Error('storageUsed must be >= 0');
|
|
||||||
if (bytes > this.storageQuota) throw new Error('storageUsed cannot exceed storageQuota');
|
|
||||||
this.storageUsed = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response helper for API
|
|
||||||
toResponse() {
|
|
||||||
const remaining = this.storageQuota - this.storageUsed;
|
|
||||||
const usagePercentage = this.storageQuota > 0 ? Math.round((this.storageUsed / this.storageQuota) * 100) : 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
authentikId: this.authentikId,
|
|
||||||
username: this.username,
|
|
||||||
email: this.email,
|
|
||||||
roles: this.roles,
|
|
||||||
permissions: this.permissions,
|
|
||||||
isActive: this.isActive,
|
|
||||||
deletedAt: this.deletedAt,
|
|
||||||
lastSeenAt: this.lastSeenAt,
|
|
||||||
storage: {
|
|
||||||
quota: this.storageQuota,
|
|
||||||
used: this.storageUsed,
|
|
||||||
remaining,
|
|
||||||
usagePercentage,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { ServiceAccount } from '../entities/service-account.entity';
|
||||||
|
|
||||||
|
export abstract class ServiceAccountRepository {
|
||||||
|
abstract create(serviceAccount: ServiceAccount): Promise<ServiceAccount>;
|
||||||
|
|
||||||
|
abstract update(serviceAccount: ServiceAccount): Promise<ServiceAccount>;
|
||||||
|
|
||||||
|
abstract findById(id: string): Promise<ServiceAccount | null>;
|
||||||
|
|
||||||
|
abstract findByClientId(clientId: string): Promise<ServiceAccount | null>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { User } from '../entities/user.entity';
|
||||||
|
|
||||||
|
export abstract class UserRepository {
|
||||||
|
abstract create(user: User): Promise<User>;
|
||||||
|
|
||||||
|
abstract update(user: User): Promise<User>;
|
||||||
|
|
||||||
|
abstract findById(
|
||||||
|
id: string,
|
||||||
|
): Promise<User | null>;
|
||||||
|
|
||||||
|
abstract findByEmail(email: string): Promise<User | null>;
|
||||||
|
|
||||||
|
abstract findAll(): Promise<User[]>;
|
||||||
|
|
||||||
|
abstract existsByEmail(
|
||||||
|
email: string,
|
||||||
|
): Promise<boolean>;
|
||||||
|
}
|
||||||
@@ -1,120 +1,64 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { UsersController } from './presentation/controllers/users.controller';
|
import { UsersController } from './presentation/controllers/users.controller';
|
||||||
import { RolesController } from './presentation/controllers/roles.controller';
|
|
||||||
import { PermissionsController } from './presentation/controllers/permissions.controller';
|
|
||||||
import { PrismaService } from '../../shared/prisma.service';
|
import { PrismaService } from '../../shared/prisma.service';
|
||||||
import { UserService } from './application/services/user.service';
|
|
||||||
import { PrismaUserRepository } from './infrastructure/repositories/prisma-user.repository';
|
import { PrismaUserRepository } from './infrastructure/repositories/prisma-user.repository';
|
||||||
import { IUser } from './domain/repositories/user.interface';
|
import { UserRepository } from './domain/repositories/user.repository.interface';
|
||||||
|
import { EventDispatcher } from '../../core/events/event-dispatcher';
|
||||||
|
|
||||||
import { JwtAuthGuard } from '../../core/auth/guards/jwt-auth.guard';
|
import { JwtAuthGuard } from '../../core/auth/guards/jwt-auth.guard';
|
||||||
import { CreateUserHandler } from './application/handlers/user/create-user.handler';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { CreateUserHandler } from './application/handlers/create-user.handler';
|
||||||
|
import { FindUserHandler } from './application/handlers/find-user.handler';
|
||||||
|
import { DeleteUserHandler } from './application/handlers/delete-user.handler';
|
||||||
|
import { FindUsersHandler } from './application/handlers/find-users.handler';
|
||||||
|
import { UpdateUserHandler } from './application/handlers/update-user.handler';
|
||||||
import { PermissionGuard } from '../authorization/presentation/guards/permission.guard';
|
import { PermissionGuard } from '../authorization/presentation/guards/permission.guard';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { SyncIdentityHandler } from './application/handlers/user/sync-identity.handler';
|
import { LoginHandler } from './application/handlers/login.handler';
|
||||||
import { CurrentUserGuard } from './presentation/guards/current-user.guard';
|
import { AuthController } from './presentation/controllers/auth.controller';
|
||||||
import { PrismaRoleRepository } from './infrastructure/repositories/prisma-role.repository';
|
import { TokenHandler } from './application/handlers/token.handler';
|
||||||
import { PrismaPermissionRepository } from './infrastructure/repositories/prisma-permission.repository';
|
import { PrismaServiceAccountRepository } from './infrastructure/repositories/prisma-service-account.repository';
|
||||||
import { IRole } from './domain/repositories/role.interface';
|
import { ServiceAccountRepository } from './domain/repositories/service-account.repository.interface';
|
||||||
import { IPermission } from './domain/repositories/permission.interface';
|
|
||||||
import { IAuthConfig } from './application/config/i-auth-config';
|
|
||||||
import { EnvAuthConfig } from './application/config/env-auth-config';
|
|
||||||
import { AuthModule } from '../auth/auth.module';
|
|
||||||
import { AuthorizationModule } from '../authorization/authorization.module';
|
|
||||||
import { EventBus } from '../../core/event-bus/event-bus.service';
|
|
||||||
|
|
||||||
import { GetUsersHandler } from './application/handlers/user/get-users.handler';
|
|
||||||
import { GetUserHandler } from './application/handlers/user/get-user.handler';
|
|
||||||
import { GetCurrentUserHandler } from './application/handlers/user/get-current-user.handler';
|
|
||||||
import { EnableUserHandler } from './application/handlers/user/enable-user.handler';
|
|
||||||
import { DisableUserHandler } from './application/handlers/user/disable-user.handler';
|
|
||||||
import { DeleteUserHandler } from './application/handlers/user/delete-user.handler';
|
|
||||||
import { RestoreUserHandler } from './application/handlers/user/restore-user.handler';
|
|
||||||
import { UpdateUserHandler } from './application/handlers/user/update-user.handler';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { GetRolesHandler } from './application/handlers/role/get-roles.handler';
|
|
||||||
import { GetRoleHandler } from './application/handlers/role/get-role.handler';
|
|
||||||
import { CreateRoleHandler } from './application/handlers/role/create-role.handler';
|
|
||||||
import { UpdateRoleHandler } from './application/handlers/role/update-role.handler';
|
|
||||||
import { DeleteRoleHandler } from './application/handlers/role/delete-role.handler';
|
|
||||||
import { RoleAssignPermissionHandler } from './application/handlers/role/assign-permission.handler';
|
|
||||||
import { RoleRemovePermissionHandler } from './application/handlers/role/remove-permission.handler';
|
|
||||||
|
|
||||||
import { GetPermissionsHandler } from './application/handlers/permission/get-permissions.handler';
|
|
||||||
import { GetPermissionHandler } from './application/handlers/permission/get-permission.handler';
|
|
||||||
import { CreatePermissionHandler } from './application/handlers/permission/create-permission.handler';
|
|
||||||
import { UpdatePermissionHandler } from './application/handlers/permission/update-permission.handler';
|
|
||||||
import { DeletePermissionHandler } from './application/handlers/permission/delete-permission.handler';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [AuthModule, AuthorizationModule],
|
imports: [
|
||||||
|
JwtModule.register({
|
||||||
|
secret: process.env.JWT_SECRET,
|
||||||
|
signOptions: {
|
||||||
|
expiresIn: '1d',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [UsersController, AuthController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
||||||
//#region User
|
//#region User
|
||||||
// CreateUserHandler has been removed: provisioning disabled; users must be created in Authentik.
|
CreateUserHandler,
|
||||||
SyncIdentityHandler,
|
FindUserHandler,
|
||||||
GetUsersHandler,
|
FindUsersHandler,
|
||||||
|
|
||||||
GetUserHandler,
|
|
||||||
GetCurrentUserHandler,
|
|
||||||
EnableUserHandler,
|
|
||||||
DisableUserHandler,
|
|
||||||
DeleteUserHandler,
|
|
||||||
RestoreUserHandler,
|
|
||||||
UpdateUserHandler,
|
UpdateUserHandler,
|
||||||
|
DeleteUserHandler,
|
||||||
|
LoginHandler,
|
||||||
|
TokenHandler,
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// role & permission handlers
|
|
||||||
GetRolesHandler,
|
|
||||||
GetRoleHandler,
|
|
||||||
CreateRoleHandler,
|
|
||||||
UpdateRoleHandler,
|
|
||||||
DeleteRoleHandler,
|
|
||||||
RoleAssignPermissionHandler,
|
|
||||||
RoleRemovePermissionHandler,
|
|
||||||
|
|
||||||
GetPermissionsHandler,
|
|
||||||
GetPermissionHandler,
|
|
||||||
CreatePermissionHandler,
|
|
||||||
UpdatePermissionHandler,
|
|
||||||
DeletePermissionHandler,
|
|
||||||
|
|
||||||
JwtAuthGuard,
|
JwtAuthGuard,
|
||||||
|
|
||||||
CurrentUserGuard,
|
|
||||||
PermissionGuard,
|
PermissionGuard,
|
||||||
Reflector,
|
Reflector,
|
||||||
PrismaService,
|
PrismaService,
|
||||||
PrismaUserRepository,
|
PrismaUserRepository,
|
||||||
PrismaRoleRepository,
|
PrismaServiceAccountRepository,
|
||||||
PrismaPermissionRepository,
|
|
||||||
UserService,
|
|
||||||
UpdateUserHandler,
|
|
||||||
|
|
||||||
{
|
{
|
||||||
provide: IUser,
|
provide: UserRepository,
|
||||||
useClass: PrismaUserRepository,
|
useClass: PrismaUserRepository,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: IRole,
|
provide: ServiceAccountRepository,
|
||||||
useClass: PrismaRoleRepository,
|
useClass: PrismaServiceAccountRepository,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: IPermission,
|
provide: 'EVENT_DISPATCHER',
|
||||||
useClass: PrismaPermissionRepository,
|
useValue: new EventDispatcher(),
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: IAuthConfig,
|
|
||||||
useClass: EnvAuthConfig,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
exports: [SyncIdentityHandler, CurrentUserGuard, { provide: IUser, useClass: PrismaUserRepository }],
|
|
||||||
controllers: [UsersController, RolesController, PermissionsController],
|
|
||||||
})
|
})
|
||||||
export class IdentityModule {}
|
export class IdentityModule {}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaService } from '../../../../shared/prisma.service';
|
||||||
|
import { ServiceAccountRepository } from '../../domain/repositories/service-account.repository.interface';
|
||||||
|
import { ServiceAccount } from '../../domain/entities/service-account.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PrismaServiceAccountRepository implements ServiceAccountRepository {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
async create(serviceAccount: ServiceAccount): Promise<ServiceAccount> {
|
||||||
|
const created = await this.prisma.serviceAccount.create({
|
||||||
|
data: {
|
||||||
|
id: serviceAccount.id,
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
client_secret_hash: serviceAccount.clientSecretHash,
|
||||||
|
name: serviceAccount.name,
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions,
|
||||||
|
status: serviceAccount.status,
|
||||||
|
metadata: serviceAccount.metadata ?? {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return ServiceAccount.restore({
|
||||||
|
id: created.id,
|
||||||
|
clientId: created.client_id,
|
||||||
|
clientSecretHash: created.client_secret_hash,
|
||||||
|
name: created.name,
|
||||||
|
role: created.role,
|
||||||
|
permissions: created.permissions as string[],
|
||||||
|
status: created.status,
|
||||||
|
metadata: (created.metadata ?? {}) as any,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(serviceAccount: ServiceAccount): Promise<ServiceAccount> {
|
||||||
|
const updated = await this.prisma.serviceAccount.update({
|
||||||
|
where: { id: serviceAccount.id },
|
||||||
|
data: {
|
||||||
|
client_id: serviceAccount.clientId,
|
||||||
|
client_secret_hash: serviceAccount.clientSecretHash,
|
||||||
|
name: serviceAccount.name,
|
||||||
|
role: serviceAccount.role,
|
||||||
|
permissions: serviceAccount.permissions,
|
||||||
|
status: serviceAccount.status,
|
||||||
|
metadata: serviceAccount.metadata ?? {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return ServiceAccount.restore({
|
||||||
|
id: updated.id,
|
||||||
|
clientId: updated.client_id,
|
||||||
|
clientSecretHash: updated.client_secret_hash,
|
||||||
|
name: updated.name,
|
||||||
|
role: updated.role,
|
||||||
|
permissions: updated.permissions as string[],
|
||||||
|
status: updated.status,
|
||||||
|
metadata: (updated.metadata ?? {}) as any,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findById(id: string): Promise<ServiceAccount | null> {
|
||||||
|
const model = await this.prisma.serviceAccount.findUnique({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
return ServiceAccount.restore({
|
||||||
|
id: model.id,
|
||||||
|
clientId: model.client_id,
|
||||||
|
clientSecretHash: model.client_secret_hash,
|
||||||
|
name: model.name,
|
||||||
|
role: model.role,
|
||||||
|
permissions: model.permissions as string[],
|
||||||
|
status: model.status,
|
||||||
|
metadata: (model.metadata ?? {}) as any,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByClientId(clientId: string): Promise<ServiceAccount | null> {
|
||||||
|
const model = await this.prisma.serviceAccount.findUnique({
|
||||||
|
where: { client_id: clientId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
return ServiceAccount.restore({
|
||||||
|
id: model.id,
|
||||||
|
clientId: model.client_id,
|
||||||
|
clientSecretHash: model.client_secret_hash,
|
||||||
|
name: model.name,
|
||||||
|
role: model.role,
|
||||||
|
permissions: model.permissions as string[],
|
||||||
|
status: model.status,
|
||||||
|
metadata: (model.metadata ?? {}) as any,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,257 +1,72 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../../../../shared/prisma.service';
|
import { PrismaService } from '../../../../shared/prisma.service';
|
||||||
import { IUser } from '../../domain/repositories/user.interface';
|
import { UserRepository } from '../../domain/repositories/user.repository.interface';
|
||||||
import { UserData } from '../../domain/entities/user.entity';
|
import { User } from '../../domain/entities/user.entity';
|
||||||
import { PrismaUserMapper } from '../mappers/prisma-user.mapper';
|
import { PrismaUserMapper } from '../mappers/prisma-user.mapper';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaUserRepository implements IUser {
|
export class PrismaUserRepository implements UserRepository {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
//#region Create
|
async findById(id: string) {
|
||||||
|
const user = await this.prisma.user.findUnique({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
async create(userData: UserData): Promise<UserData> {
|
return PrismaUserMapper.toDomain(user);
|
||||||
const base = PrismaUserMapper.toPersistence(userData);
|
|
||||||
|
|
||||||
const data: any = { ...base };
|
|
||||||
|
|
||||||
if (userData.roles && userData.roles.length > 0) {
|
|
||||||
data.roles = {
|
|
||||||
create: userData.roles.map(r => ({ role: { connect: { id: r.id } }, assignedBy: 'system' })),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findByEmail(email: string): Promise<User | null> {
|
||||||
|
const user = await this.prisma.user.findUnique({
|
||||||
|
where: { email },
|
||||||
|
});
|
||||||
|
|
||||||
|
return PrismaUserMapper.toDomain(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(): Promise<User[]> {
|
||||||
|
const users = await this.prisma.user.findMany({
|
||||||
|
where: { deleted_at: null },
|
||||||
|
orderBy: { created_at: 'desc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return users.map(u => PrismaUserMapper.toDomain(u)!);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(user: User): Promise<User> {
|
||||||
const created = await this.prisma.user.create({
|
const created = await this.prisma.user.create({
|
||||||
data,
|
data: PrismaUserMapper.toPersistence(user),
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(created)!;
|
return PrismaUserMapper.toDomain(created)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
async update(user: User): Promise<User> {
|
||||||
|
|
||||||
//#region Read
|
|
||||||
|
|
||||||
async existsById(userId: string): Promise<boolean> {
|
|
||||||
return (
|
|
||||||
(await this.prisma.user.findUnique({
|
|
||||||
where: { id: userId },
|
|
||||||
select: { id: true },
|
|
||||||
})) !== null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async existByEmail(userEmail: string): Promise<boolean> {
|
|
||||||
return (
|
|
||||||
(await this.prisma.user.findUnique({
|
|
||||||
where: { email: userEmail },
|
|
||||||
select: { email: true },
|
|
||||||
})) !== null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getById(userId: string): Promise<UserData> {
|
|
||||||
const userData = await this.prisma.user.findUnique({
|
|
||||||
where: { id: userId },
|
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (userData === null) throw new Error('User tidak ditemukan.');
|
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getByEmail(userEmail: string): Promise<UserData> {
|
|
||||||
const userData = await this.prisma.user.findUnique({
|
|
||||||
where: { email: userEmail },
|
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (userData === null) throw new Error('User tidak ditemukan.');
|
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async findByAuthentikId(authentikId: string): Promise<UserData | null> {
|
|
||||||
const userData = await this.prisma.user.findUnique({
|
|
||||||
where: { authentikId },
|
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!userData) return null;
|
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async find(params: {
|
|
||||||
page?: number;
|
|
||||||
limit?: number;
|
|
||||||
search?: string | null;
|
|
||||||
isActive?: boolean | null;
|
|
||||||
deleted?: boolean | null;
|
|
||||||
roleId?: string | null;
|
|
||||||
}): Promise<{ data: UserData[]; total: number }> {
|
|
||||||
const page = params.page && params.page > 0 ? params.page : 1;
|
|
||||||
const limit = params.limit && params.limit > 0 ? params.limit : 10;
|
|
||||||
|
|
||||||
const where: any = {};
|
|
||||||
|
|
||||||
if (params.search) {
|
|
||||||
where.OR = [
|
|
||||||
{ username: { contains: params.search, mode: 'insensitive' } },
|
|
||||||
{ email: { contains: params.search, mode: 'insensitive' } },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.isActive !== undefined && params.isActive !== null) {
|
|
||||||
where.isActive = params.isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.deleted !== undefined && params.deleted !== null) {
|
|
||||||
if (params.deleted) where.deletedAt = { not: null };
|
|
||||||
else where.deletedAt = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.roleId) {
|
|
||||||
where.roles = { some: { roleId: params.roleId } };
|
|
||||||
}
|
|
||||||
|
|
||||||
const [total, items] = await Promise.all([
|
|
||||||
this.prisma.user.count({ where }),
|
|
||||||
this.prisma.user.findMany({
|
|
||||||
where,
|
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
skip: (page - 1) * limit,
|
|
||||||
take: limit,
|
|
||||||
orderBy: { createdAt: 'desc' },
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return { data: items.map(i => PrismaUserMapper.toDomain(i)!), total };
|
|
||||||
}
|
|
||||||
|
|
||||||
async softDelete(userId: string): Promise<void> {
|
|
||||||
await this.prisma.user.update({ where: { id: userId }, data: { deletedAt: new Date(), isActive: false } });
|
|
||||||
}
|
|
||||||
|
|
||||||
async restore(userId: string): Promise<UserData> {
|
|
||||||
const updated = await this.prisma.user.update({
|
const updated = await this.prisma.user.update({
|
||||||
where: { id: userId },
|
where: {
|
||||||
data: { deletedAt: null },
|
id: user.id,
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
},
|
||||||
|
data: PrismaUserMapper.toPersistence(user),
|
||||||
});
|
});
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(updated)!;
|
return PrismaUserMapper.toDomain(updated)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async enable(userId: string): Promise<UserData> {
|
async delete(id: string) {
|
||||||
const updated = await this.prisma.user.update({
|
const user = await this.prisma.user.update({
|
||||||
where: { id: userId },
|
where: { id },
|
||||||
data: { isActive: true },
|
data: { deleted_at: new Date() },
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
return PrismaUserMapper.toDomain(user);
|
||||||
return PrismaUserMapper.toDomain(updated)!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async disable(userId: string): Promise<UserData> {
|
async existsByEmail(email: string, excludeId?: string | null) {
|
||||||
const updated = await this.prisma.user.update({
|
const where: any = { email };
|
||||||
where: { id: userId },
|
if (excludeId) {
|
||||||
data: { isActive: false },
|
where.id = { not: excludeId };
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(updated)!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(userData: UserData): Promise<UserData> {
|
const user = await this.prisma.user.findFirst({ where });
|
||||||
const base = PrismaUserMapper.toPersistence(userData);
|
return !!user;
|
||||||
|
|
||||||
const data: any = { ...base };
|
|
||||||
|
|
||||||
// sync roles and permissions using transaction
|
|
||||||
const roleIds = userData.roles ? userData.roles.map(r => r.id) : [];
|
|
||||||
const permissionIds = userData.permissions ? userData.permissions.map(p => p.id) : [];
|
|
||||||
|
|
||||||
// perform transaction: delete removed relations, create missing ones, update user
|
|
||||||
await this.prisma.$transaction(async (prisma) => {
|
|
||||||
// current roles
|
|
||||||
const currentRoles = await prisma.userRole.findMany({ where: { userId: userData.id } });
|
|
||||||
const currentRoleIds = currentRoles.map(r => r.roleId);
|
|
||||||
|
|
||||||
const toAddRoles = roleIds.filter(id => !currentRoleIds.includes(id));
|
|
||||||
const toRemoveRoles = currentRoleIds.filter(id => !roleIds.includes(id));
|
|
||||||
|
|
||||||
if (toRemoveRoles.length > 0) {
|
|
||||||
await prisma.userRole.deleteMany({ where: { userId: userData.id, roleId: { in: toRemoveRoles } } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toAddRoles.length > 0) {
|
|
||||||
await prisma.userRole.createMany({
|
|
||||||
data: toAddRoles.map(rid => ({ userId: userData.id, roleId: rid, assignedBy: 'system' })) as any,
|
|
||||||
skipDuplicates: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// permissions
|
|
||||||
const currentPerms = await prisma.userPermission.findMany({ where: { userId: userData.id } });
|
|
||||||
const currentPermIds = currentPerms.map(p => p.permissionId);
|
|
||||||
|
|
||||||
const toAddPerms = permissionIds.filter(id => !currentPermIds.includes(id));
|
|
||||||
const toRemovePerms = currentPermIds.filter(id => !permissionIds.includes(id));
|
|
||||||
|
|
||||||
if (toRemovePerms.length > 0) {
|
|
||||||
await prisma.userPermission.deleteMany({ where: { userId: userData.id, permissionId: { in: toRemovePerms } } });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toAddPerms.length > 0) {
|
|
||||||
await prisma.userPermission.createMany({
|
|
||||||
data: toAddPerms.map(pid => ({ userId: userData.id, permissionId: pid, assignedBy: 'system' })) as any,
|
|
||||||
skipDuplicates: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// update base user fields
|
|
||||||
await prisma.user.update({ where: { id: userData.id }, data });
|
|
||||||
});
|
|
||||||
|
|
||||||
const updated = await this.prisma.user.findUnique({
|
|
||||||
where: { id: userData.id },
|
|
||||||
include: {
|
|
||||||
roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } },
|
|
||||||
permissions: { include: { permission: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return PrismaUserMapper.toDomain(updated)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { Controller, Post, Body } from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
import { LoginDto } from '../dto/login.dto';
|
||||||
|
import { LoginHandler } from '../../application/handlers/login.handler';
|
||||||
|
import { TokenHandler } from '../../application/handlers/token.handler';
|
||||||
|
|
||||||
|
@ApiTags('Auth')
|
||||||
|
@Controller('api/v1/auth')
|
||||||
|
export class AuthController {
|
||||||
|
constructor(
|
||||||
|
private readonly loginHandler: LoginHandler,
|
||||||
|
private readonly tokenHandler: TokenHandler,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Post('login')
|
||||||
|
@ApiOperation({ summary: 'Login and obtain access token' })
|
||||||
|
async login(@Body() dto: LoginDto) {
|
||||||
|
const data = await this.loginHandler.execute(dto);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data,
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('token')
|
||||||
|
@ApiOperation({ summary: 'Obtain access token using client credentials' })
|
||||||
|
async token(@Body() body: any) {
|
||||||
|
const data = await this.tokenHandler.execute(body);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data,
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,105 +1,113 @@
|
|||||||
import { Controller, Get, Param, UseGuards, Query, Patch, Delete, Post, Body, Req } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Delete,
|
||||||
|
Param,
|
||||||
|
UseGuards,
|
||||||
|
Body,
|
||||||
|
Patch
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { JwtAuthGuard } from '../../../../core/auth/guards/jwt-auth.guard';
|
import { JwtAuthGuard } from '../../../../core/auth/guards/jwt-auth.guard';
|
||||||
import { PermissionGuard } from '../../../authorization/presentation/guards/permission.guard';
|
import { PermissionGuard } from '../../../authorization/presentation/guards/permission.guard';
|
||||||
import { CurrentUserGuard } from '../guards/current-user.guard';
|
|
||||||
import { Permissions } from '../../../authorization/presentation/decorators/permission.decorator';
|
import { Permissions } from '../../../authorization/presentation/decorators/permission.decorator';
|
||||||
import { PermissionType } from '../../../../common/constants/permission.constants';
|
|
||||||
|
|
||||||
import { GetUsersHandler } from '../../application/handlers/user/get-users.handler';
|
|
||||||
import { GetUserHandler } from '../../application/handlers/user/get-user.handler';
|
|
||||||
import { GetCurrentUserHandler } from '../../application/handlers/user/get-current-user.handler';
|
|
||||||
import { EnableUserHandler } from '../../application/handlers/user/enable-user.handler';
|
|
||||||
import { DisableUserHandler } from '../../application/handlers/user/disable-user.handler';
|
|
||||||
import { DeleteUserHandler } from '../../application/handlers/user/delete-user.handler';
|
|
||||||
import { RestoreUserHandler } from '../../application/handlers/user/restore-user.handler';
|
|
||||||
import { UpdateUserHandler } from '../../application/handlers/user/update-user.handler';
|
|
||||||
|
|
||||||
|
import { FindUserHandler } from '../../application/handlers/find-user.handler';
|
||||||
|
import { FindUsersHandler } from '../../application/handlers/find-users.handler';
|
||||||
|
import { CreateUserHandler } from '../../application/handlers/create-user.handler';
|
||||||
|
import { UpdateUserHandler } from '../../application/handlers/update-user.handler';
|
||||||
|
import { DeleteUserHandler } from '../../application/handlers/delete-user.handler';
|
||||||
|
import { CreateUserDto } from '../dto/create-user.dto';
|
||||||
|
import { UpdateUserDto } from '../dto/update-user.dto';
|
||||||
|
|
||||||
@ApiTags('Users')
|
@ApiTags('Users')
|
||||||
@Controller('users')
|
@Controller('api/v1/users')
|
||||||
@UseGuards(JwtAuthGuard, CurrentUserGuard, PermissionGuard)
|
@UseGuards(JwtAuthGuard, PermissionGuard)
|
||||||
export class UsersController {
|
export class UsersController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly getUsersHandler: GetUsersHandler,
|
private readonly createUserHandler: CreateUserHandler,
|
||||||
private readonly getUserHandler: GetUserHandler,
|
private readonly findUserHandler: FindUserHandler,
|
||||||
private readonly getCurrentUserHandler: GetCurrentUserHandler,
|
private readonly findUsersHandler: FindUsersHandler,
|
||||||
private readonly enableUserHandler: EnableUserHandler,
|
|
||||||
private readonly disableUserHandler: DisableUserHandler,
|
|
||||||
private readonly deleteUserHandler: DeleteUserHandler,
|
|
||||||
private readonly restoreUserHandler: RestoreUserHandler,
|
|
||||||
private readonly updateUserHandler: UpdateUserHandler,
|
private readonly updateUserHandler: UpdateUserHandler,
|
||||||
|
private readonly deleteUserHandler: DeleteUserHandler,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get()
|
private sanitizeUser(user: any) {
|
||||||
@Permissions(PermissionType.USER_READ)
|
if (!user) return user;
|
||||||
@ApiOperation({ summary: 'List users' })
|
if (Array.isArray(user)) {
|
||||||
async findAll(@Query() query: any) {
|
return user.map(u => {
|
||||||
const res = await this.getUsersHandler.execute(query);
|
const { password, ...rest } = u as any;
|
||||||
|
return rest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { password, ...rest } = user as any;
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@Permissions('USER_CREATE')
|
||||||
|
@ApiOperation({ summary: 'Create user' })
|
||||||
|
async create(@Body() dto: CreateUserDto) {
|
||||||
|
const data = await this.createUserHandler.execute(dto);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: res.data.map(u => (u as any).toResponse ? (u as any).toResponse() : u),
|
data: this.sanitizeUser(data),
|
||||||
meta: { total: res.total },
|
meta: {},
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('me')
|
|
||||||
@ApiOperation({ summary: 'Get current user' })
|
|
||||||
async me(@Req() req: any) {
|
|
||||||
const user = await this.getCurrentUserHandler.execute(req.currentUser);
|
|
||||||
|
|
||||||
return { success: true, data: (user as any).toResponse ? (user as any).toResponse() : user, meta: {} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@Permissions(PermissionType.USER_READ)
|
@Permissions('USER_READ')
|
||||||
@ApiOperation({ summary: 'Get user by id' })
|
@ApiOperation({ summary: 'Get user by id' })
|
||||||
async findOne(@Param('id') id: string) {
|
async getById(@Param('id') id: string) {
|
||||||
const user = await this.getUserHandler.execute(id);
|
const data = await this.findUserHandler.execute(id);
|
||||||
return { success: true, data: (user as any).toResponse ? (user as any).toResponse() : user, meta: {} };
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id/enable')
|
@Get()
|
||||||
@Permissions(PermissionType.USER_UPDATE)
|
@Permissions('USER_READ_ADMIN')
|
||||||
@ApiOperation({ summary: 'Enable user' })
|
@ApiOperation({ summary: 'Get All User' })
|
||||||
async enable(@Param('id') id: string) {
|
async getAll() {
|
||||||
const updated = await this.enableUserHandler.execute(id);
|
const data = await this.findUsersHandler.execute();
|
||||||
return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(':id/disable')
|
return {
|
||||||
@Permissions(PermissionType.USER_UPDATE)
|
success: true,
|
||||||
@ApiOperation({ summary: 'Disable user' })
|
data: this.sanitizeUser(data),
|
||||||
async disable(@Param('id') id: string) {
|
meta: {},
|
||||||
const updated = await this.disableUserHandler.execute(id);
|
};
|
||||||
return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
@Permissions(PermissionType.USER_UPDATE)
|
@Permissions('USER_UPDATE')
|
||||||
@ApiOperation({ summary: 'Update user profile' })
|
@ApiOperation({ summary: 'Update User' })
|
||||||
async update(@Param('id') id: string, @Body() body: any) {
|
async update(@Param('id') id:string, @Body() dto:UpdateUserDto) {
|
||||||
const updated = await this.updateUserHandler.execute(id, body);
|
const data = await this.updateUserHandler.execute(id, dto);
|
||||||
return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} };
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: this.sanitizeUser(data),
|
||||||
|
meta: {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
@Permissions(PermissionType.USER_DELETE)
|
@Permissions('USER_DELETE')
|
||||||
@ApiOperation({ summary: 'Soft delete user' })
|
@ApiOperation({ summary: 'Delete user by id' })
|
||||||
async remove(@Param('id') id: string) {
|
async delete(@Param('id') id: string) {
|
||||||
await this.deleteUserHandler.execute(id);
|
await this.deleteUserHandler.execute(id);
|
||||||
return { success: true, data: null, meta: {} };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post(':id/restore')
|
return {
|
||||||
@Permissions(PermissionType.USER_UPDATE)
|
success: true,
|
||||||
@ApiOperation({ summary: 'Restore user' })
|
data: null,
|
||||||
async restore(@Param('id') id: string) {
|
meta: {},
|
||||||
const restored = await this.restoreUserHandler.execute(id);
|
};
|
||||||
return { success: true, data: (restored as any).toResponse ? (restored as any).toResponse() : restored, meta: {} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { IsEmail, IsString, Length } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class LoginDto {
|
||||||
|
@ApiProperty({ example: 'user@example.com' })
|
||||||
|
@IsEmail()
|
||||||
|
email!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'strongpassword' })
|
||||||
|
@IsString()
|
||||||
|
@Length(8, 128)
|
||||||
|
password!: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { CoreApiClient, CoreApiClientError } from '../../src/adapters/notification/core-api-client';
|
||||||
|
|
||||||
|
describe('CoreApiClient', () => {
|
||||||
|
const API_URL = 'http://core.local';
|
||||||
|
const CLIENT_ID = 'cid';
|
||||||
|
const CLIENT_SECRET = 'csec';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
(global as any).fetch = jest.fn();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requests token successfully and caches it', async () => {
|
||||||
|
// token endpoint response
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||||
|
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||||
|
|
||||||
|
const token = await client.getToken();
|
||||||
|
expect(token).toBe('t1');
|
||||||
|
|
||||||
|
// second call should not call fetch again for token
|
||||||
|
const token2 = await client.getToken();
|
||||||
|
expect(token2).toBe('t1');
|
||||||
|
expect(global.fetch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on invalid credentials (401)', async () => {
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 401, json: async () => ({}) });
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||||
|
await expect(client.getToken()).rejects.toThrow(CoreApiClientError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('retries once on 401 during authenticatedRequest', async () => {
|
||||||
|
// initial token fetch
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||||
|
|
||||||
|
// first API call returns 401
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 401, json: async () => ({}) });
|
||||||
|
|
||||||
|
// token refresh fetch returns new token
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't2', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||||
|
|
||||||
|
// retried API call returns 200
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ ok: true }) });
|
||||||
|
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||||
|
|
||||||
|
const res = await client.authenticatedRequest(`${API_URL}/api/v1/users`, { method: 'GET' });
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
expect(global.fetch).toHaveBeenCalledTimes(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not retry on 403', async () => {
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 403, json: async () => ({}) });
|
||||||
|
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||||
|
|
||||||
|
const res = await client.authenticatedRequest(`${API_URL}/api/v1/forbidden`, { method: 'GET' });
|
||||||
|
expect(res.status).toBe(403);
|
||||||
|
// only token fetch + one API call
|
||||||
|
expect(global.fetch).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles token refresh before expiry', async () => {
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 2 } }) });
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||||
|
|
||||||
|
const token1 = await client.getToken();
|
||||||
|
expect(token1).toBe('t1');
|
||||||
|
|
||||||
|
// force expiry by manipulating internal state
|
||||||
|
(client as any).tokenExpiry = Date.now() - 1000;
|
||||||
|
|
||||||
|
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't2', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||||
|
|
||||||
|
const token2 = await client.getToken();
|
||||||
|
expect(token2).toBe('t2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles network timeout', async () => {
|
||||||
|
(global.fetch as jest.Mock).mockRejectedValueOnce(Object.assign(new Error('AbortError'), { name: 'AbortError' }));
|
||||||
|
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, timeoutMs: 1 });
|
||||||
|
await expect(client.getToken()).rejects.toThrow(CoreApiClientError);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { PrismaService } from '../../src/shared/prisma.service';
|
||||||
|
import { PrismaServiceAccountRepository } from '../../src/modules/identity/infrastructure/repositories/prisma-service-account.repository';
|
||||||
|
import { ServiceAccount } from '../../src/modules/identity/domain/entities/service-account.entity';
|
||||||
|
|
||||||
|
describe('PrismaServiceAccountRepository', () => {
|
||||||
|
it('maps prisma model to domain entity for findByClientId', async () => {
|
||||||
|
const fakeModel = {
|
||||||
|
id: 'id-1',
|
||||||
|
client_id: 'cid',
|
||||||
|
client_secret_hash: 'hash',
|
||||||
|
name: 'Bot',
|
||||||
|
role: 'BOT',
|
||||||
|
permissions: ['DEBT_READ'],
|
||||||
|
status: 'ACTIVE',
|
||||||
|
metadata: { hello: 'world' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockPrisma: Partial<PrismaService> = {
|
||||||
|
serviceAccount: {
|
||||||
|
findUnique: jest.fn().mockResolvedValue(fakeModel),
|
||||||
|
} as any,
|
||||||
|
};
|
||||||
|
|
||||||
|
const repo = new PrismaServiceAccountRepository(mockPrisma as any);
|
||||||
|
|
||||||
|
const sa = await repo.findByClientId('cid');
|
||||||
|
|
||||||
|
expect(sa).not.toBeNull();
|
||||||
|
expect(sa!.clientId).toBe('cid');
|
||||||
|
expect(sa!.name).toBe('Bot');
|
||||||
|
expect(sa!.role).toBe('BOT');
|
||||||
|
expect(sa!.permissions).toEqual(fakeModel.permissions);
|
||||||
|
expect(sa!.metadata).toEqual(fakeModel.metadata);
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user