rl-core-api 0.15.6 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/bootstrap/bootstrapCore.util.js +1 -1
- package/dist/core/config/env.schema.d.ts +7 -0
- package/dist/core/config/env.schema.js +4 -0
- package/dist/core/database/migrations/1789171200000-NotificationDismissal.d.ts +6 -0
- package/dist/core/database/migrations/1789171200000-NotificationDismissal.js +16 -0
- package/dist/core/database/migrations/index.js +2 -0
- package/dist/core/images/imageCleanup.service.d.ts +9 -0
- package/dist/core/images/imageCleanup.service.js +50 -0
- package/dist/core/images/imageFetch.service.d.ts +11 -0
- package/dist/core/images/imageFetch.service.js +190 -0
- package/dist/core/images/imageProcessing.service.d.ts +9 -0
- package/dist/core/images/imageProcessing.service.js +74 -0
- package/dist/core/images/imageProfile.interface.d.ts +40 -0
- package/dist/core/images/imageProfile.interface.js +29 -0
- package/dist/core/images/imageProfile.registry.d.ts +14 -0
- package/dist/core/images/imageProfile.registry.js +61 -0
- package/dist/core/images/imageStorage.service.d.ts +28 -0
- package/dist/core/images/imageStorage.service.js +151 -0
- package/dist/core/images/images.controller.d.ts +16 -0
- package/dist/core/images/images.controller.js +142 -0
- package/dist/core/images/images.module.d.ts +2 -0
- package/dist/core/images/images.module.js +35 -0
- package/dist/core/images/images.processor.d.ts +18 -0
- package/dist/core/images/images.processor.js +75 -0
- package/dist/core/images/images.service.d.ts +34 -0
- package/dist/core/images/images.service.js +137 -0
- package/dist/core/images/imagesApi.module.d.ts +2 -0
- package/dist/core/images/imagesApi.module.js +25 -0
- package/dist/core/images/imagesWorker.module.d.ts +2 -0
- package/dist/core/images/imagesWorker.module.js +22 -0
- package/dist/core/images/responses/imageAccepted.response.d.ts +4 -0
- package/dist/core/images/responses/imageAccepted.response.js +28 -0
- package/dist/core/images/responses/imageProfile.response.d.ts +10 -0
- package/dist/core/images/responses/imageProfile.response.js +55 -0
- package/dist/core/images/responses/imageStatus.response.d.ts +7 -0
- package/dist/core/images/responses/imageStatus.response.js +36 -0
- package/dist/core/images/uploadImageFromUrl.command.d.ts +3 -0
- package/dist/core/images/uploadImageFromUrl.command.js +23 -0
- package/dist/core/queue/job.producer.d.ts +1 -1
- package/dist/core/queue/job.producer.js +7 -1
- package/dist/core/queue/queue.constants.d.ts +4 -1
- package/dist/core/queue/queue.constants.js +5 -2
- package/dist/features/notifications/domain/notifications.service.d.ts +2 -0
- package/dist/features/notifications/domain/notifications.service.js +12 -0
- package/dist/features/notifications/infra/repositories/notification.repository.d.ts +1 -0
- package/dist/features/notifications/infra/repositories/notification.repository.js +8 -0
- package/dist/features/notifications/infra/repositories/notificationRead.repository.d.ts +1 -0
- package/dist/features/notifications/infra/repositories/notificationRead.repository.js +17 -0
- package/dist/features/notifications/infra/schema/notificationRead.schema.d.ts +1 -0
- package/dist/features/notifications/infra/schema/notificationRead.schema.js +4 -0
- package/dist/features/notifications/presentation/notifications.controller.d.ts +2 -0
- package/dist/features/notifications/presentation/notifications.controller.js +23 -0
- package/dist/features/users/domain/avatarImage.profile.d.ts +13 -0
- package/dist/features/users/domain/avatarImage.profile.js +30 -0
- package/dist/features/users/domain/index.d.ts +1 -1
- package/dist/features/users/domain/index.js +1 -1
- package/dist/features/users/presentation/users.controller.d.ts +6 -5
- package/dist/features/users/presentation/users.controller.js +28 -15
- package/dist/features/users/users.module.js +3 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +43 -2
- package/dist/rlCore.module.js +5 -1
- package/package.json +1 -1
- package/dist/features/users/domain/avatar.service.d.ts +0 -5
- package/dist/features/users/domain/avatar.service.js +0 -61
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ImagesWorkerModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const images_module_1 = require("./images.module");
|
|
12
|
+
const images_processor_1 = require("./images.processor");
|
|
13
|
+
const queue_constants_1 = require("../queue/queue.constants");
|
|
14
|
+
let ImagesWorkerModule = class ImagesWorkerModule {
|
|
15
|
+
};
|
|
16
|
+
exports.ImagesWorkerModule = ImagesWorkerModule;
|
|
17
|
+
exports.ImagesWorkerModule = ImagesWorkerModule = __decorate([
|
|
18
|
+
(0, common_1.Module)({
|
|
19
|
+
imports: [images_module_1.ImagesModule],
|
|
20
|
+
providers: (0, queue_constants_1.isRedisConfigured)() ? [images_processor_1.ImagesProcessor] : [],
|
|
21
|
+
})
|
|
22
|
+
], ImagesWorkerModule);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ImageAcceptedResponse = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
class ImageAcceptedResponse {
|
|
15
|
+
}
|
|
16
|
+
exports.ImageAcceptedResponse = ImageAcceptedResponse;
|
|
17
|
+
__decorate([
|
|
18
|
+
(0, swagger_1.ApiProperty)({ type: String, nullable: true, example: "312" }),
|
|
19
|
+
__metadata("design:type", Object)
|
|
20
|
+
], ImageAcceptedResponse.prototype, "jobId", void 0);
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, swagger_1.ApiProperty)({
|
|
23
|
+
type: String,
|
|
24
|
+
nullable: true,
|
|
25
|
+
example: "/uploads/funkos/pending/6f1b2c34-9d55-4a1e-8f0a-2b7c1d9e4f10.webp",
|
|
26
|
+
}),
|
|
27
|
+
__metadata("design:type", Object)
|
|
28
|
+
], ImageAcceptedResponse.prototype, "path", void 0);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ImageProfileResponse = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const imageProfile_interface_1 = require("../imageProfile.interface");
|
|
15
|
+
class ImageProfileResponse {
|
|
16
|
+
}
|
|
17
|
+
exports.ImageProfileResponse = ImageProfileResponse;
|
|
18
|
+
__decorate([
|
|
19
|
+
(0, swagger_1.ApiProperty)({ example: "funkos" }),
|
|
20
|
+
__metadata("design:type", String)
|
|
21
|
+
], ImageProfileResponse.prototype, "name", void 0);
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, swagger_1.ApiProperty)({ example: 400, description: "Lado máximo em pixels — é teto, não obrigação" }),
|
|
24
|
+
__metadata("design:type", Number)
|
|
25
|
+
], ImageProfileResponse.prototype, "width", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
28
|
+
type: Number,
|
|
29
|
+
nullable: true,
|
|
30
|
+
example: 400,
|
|
31
|
+
description: "Lado da caixa em que a imagem cabe. Com `inside`, a altura final segue a proporção da foto — este número é o teto, e é o que a tela usa para desenhar a área de envio",
|
|
32
|
+
}),
|
|
33
|
+
__metadata("design:type", Object)
|
|
34
|
+
], ImageProfileResponse.prototype, "height", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
(0, swagger_1.ApiProperty)({ enum: imageProfile_interface_1.ImageFit, example: imageProfile_interface_1.ImageFit.CONTAIN }),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], ImageProfileResponse.prototype, "fit", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, swagger_1.ApiProperty)({ enum: imageProfile_interface_1.ImageFormat, example: imageProfile_interface_1.ImageFormat.WEBP }),
|
|
41
|
+
__metadata("design:type", String)
|
|
42
|
+
], ImageProfileResponse.prototype, "format", void 0);
|
|
43
|
+
__decorate([
|
|
44
|
+
(0, swagger_1.ApiProperty)({ example: 8388608 }),
|
|
45
|
+
__metadata("design:type", Number)
|
|
46
|
+
], ImageProfileResponse.prototype, "maxBytes", void 0);
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, swagger_1.ApiProperty)({
|
|
49
|
+
type: String,
|
|
50
|
+
isArray: true,
|
|
51
|
+
example: ["image/jpeg", "image/png", "image/webp"],
|
|
52
|
+
description: "Vira o `accept` do seletor de arquivo",
|
|
53
|
+
}),
|
|
54
|
+
__metadata("design:type", Array)
|
|
55
|
+
], ImageProfileResponse.prototype, "accept", void 0);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ImageStatusResponse = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
class ImageStatusResponse {
|
|
15
|
+
}
|
|
16
|
+
exports.ImageStatusResponse = ImageStatusResponse;
|
|
17
|
+
__decorate([
|
|
18
|
+
(0, swagger_1.ApiProperty)({ example: "completed" }),
|
|
19
|
+
__metadata("design:type", String)
|
|
20
|
+
], ImageStatusResponse.prototype, "state", void 0);
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, swagger_1.ApiProperty)({ example: 100 }),
|
|
23
|
+
__metadata("design:type", Number)
|
|
24
|
+
], ImageStatusResponse.prototype, "percent", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, swagger_1.ApiProperty)({
|
|
27
|
+
type: String,
|
|
28
|
+
nullable: true,
|
|
29
|
+
example: "/uploads/funkos/pending/6f1b2c34-9d55-4a1e-8f0a-2b7c1d9e4f10.webp",
|
|
30
|
+
}),
|
|
31
|
+
__metadata("design:type", Object)
|
|
32
|
+
], ImageStatusResponse.prototype, "path", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, swagger_1.ApiProperty)({ type: String, nullable: true }),
|
|
35
|
+
__metadata("design:type", Object)
|
|
36
|
+
], ImageStatusResponse.prototype, "errorMessage", void 0);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.UploadImageFromUrlCommand = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
class UploadImageFromUrlCommand {
|
|
16
|
+
}
|
|
17
|
+
exports.UploadImageFromUrlCommand = UploadImageFromUrlCommand;
|
|
18
|
+
__decorate([
|
|
19
|
+
(0, swagger_1.ApiProperty)({ example: "https://exemplo.com/ron.png" }),
|
|
20
|
+
(0, class_validator_1.IsUrl)({ protocols: ["http", "https"], require_protocol: true }),
|
|
21
|
+
(0, class_validator_1.MaxLength)(2048),
|
|
22
|
+
__metadata("design:type", String)
|
|
23
|
+
], UploadImageFromUrlCommand.prototype, "url", void 0);
|
|
@@ -5,7 +5,7 @@ import { QueueName } from "./queue.constants";
|
|
|
5
5
|
export declare class JobProducer implements OnApplicationBootstrap {
|
|
6
6
|
private readonly logger;
|
|
7
7
|
private readonly queues;
|
|
8
|
-
constructor(jobs?: Queue<JobEnvelope>, exports?: Queue<JobEnvelope>);
|
|
8
|
+
constructor(jobs?: Queue<JobEnvelope>, exports?: Queue<JobEnvelope>, images?: Queue<JobEnvelope>);
|
|
9
9
|
onApplicationBootstrap(): Promise<void>;
|
|
10
10
|
isAvailable(queue?: QueueName): boolean;
|
|
11
11
|
enqueue<TPayload>(name: string, payload: TPayload, options: EnqueueOptions): Promise<JobRef>;
|
|
@@ -28,7 +28,7 @@ const ENQUEUE_TIMEOUT_MS = 5000;
|
|
|
28
28
|
const HEALTH_TIMEOUT_MS = 1500;
|
|
29
29
|
const isStoredProgress = (value) => typeof value === "object" && value !== null && "percent" in value;
|
|
30
30
|
let JobProducer = JobProducer_1 = class JobProducer {
|
|
31
|
-
constructor(jobs, exports) {
|
|
31
|
+
constructor(jobs, exports, images) {
|
|
32
32
|
this.logger = new common_1.Logger(JobProducer_1.name);
|
|
33
33
|
this.queues = new Map();
|
|
34
34
|
if (jobs) {
|
|
@@ -37,6 +37,9 @@ let JobProducer = JobProducer_1 = class JobProducer {
|
|
|
37
37
|
if (exports) {
|
|
38
38
|
this.queues.set(queue_constants_1.EXPORTS_QUEUE, exports);
|
|
39
39
|
}
|
|
40
|
+
if (images) {
|
|
41
|
+
this.queues.set(queue_constants_1.IMAGES_QUEUE, images);
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
async onApplicationBootstrap() {
|
|
42
45
|
if (!(0, queue_constants_1.isRedisConfigured)()) {
|
|
@@ -144,6 +147,9 @@ exports.JobProducer = JobProducer = JobProducer_1 = __decorate([
|
|
|
144
147
|
__param(0, (0, bullmq_1.InjectQueue)(queue_constants_1.JOBS_QUEUE)),
|
|
145
148
|
__param(1, (0, common_1.Optional)()),
|
|
146
149
|
__param(1, (0, bullmq_1.InjectQueue)(queue_constants_1.EXPORTS_QUEUE)),
|
|
150
|
+
__param(2, (0, common_1.Optional)()),
|
|
151
|
+
__param(2, (0, bullmq_1.InjectQueue)(queue_constants_1.IMAGES_QUEUE)),
|
|
147
152
|
__metadata("design:paramtypes", [bullmq_2.Queue,
|
|
153
|
+
bullmq_2.Queue,
|
|
148
154
|
bullmq_2.Queue])
|
|
149
155
|
], JobProducer);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const JOBS_QUEUE = "jobs";
|
|
2
2
|
export declare const EXPORTS_QUEUE = "exports";
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const IMAGES_QUEUE = "images";
|
|
4
|
+
export declare const QUEUE_NAMES: readonly ["jobs", "exports", "images"];
|
|
4
5
|
export type QueueName = (typeof QUEUE_NAMES)[number];
|
|
5
6
|
export declare const isQueueName: (value: unknown) => value is QueueName;
|
|
6
7
|
export declare const JOB_PROGRESS_EVENT = "job:progress";
|
|
@@ -10,6 +11,8 @@ export declare const JOB_CONCURRENCY = 5;
|
|
|
10
11
|
export declare const JOB_ATTEMPTS = 3;
|
|
11
12
|
export declare const EXPORT_CONCURRENCY = 2;
|
|
12
13
|
export declare const EXPORT_LOCK_DURATION_MS = 300000;
|
|
14
|
+
export declare const IMAGE_CONCURRENCY = 4;
|
|
15
|
+
export declare const IMAGE_LOCK_DURATION_MS = 60000;
|
|
13
16
|
export declare const JOB_BACKOFF_DELAY_MS = 30000;
|
|
14
17
|
export declare const COMPLETED_RETENTION_SECONDS = 86400;
|
|
15
18
|
export declare const FAILED_RETENTION_SECONDS = 14400;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.queuePrefix = exports.isRedisConfigured = exports.FAILED_RETENTION_SECONDS = exports.COMPLETED_RETENTION_SECONDS = exports.JOB_BACKOFF_DELAY_MS = exports.EXPORT_LOCK_DURATION_MS = exports.EXPORT_CONCURRENCY = exports.JOB_ATTEMPTS = exports.JOB_CONCURRENCY = exports.JOB_FAILED_EVENT = exports.JOB_COMPLETED_EVENT = exports.JOB_PROGRESS_EVENT = exports.isQueueName = exports.QUEUE_NAMES = exports.EXPORTS_QUEUE = exports.JOBS_QUEUE = void 0;
|
|
3
|
+
exports.queuePrefix = exports.isRedisConfigured = exports.FAILED_RETENTION_SECONDS = exports.COMPLETED_RETENTION_SECONDS = exports.JOB_BACKOFF_DELAY_MS = exports.IMAGE_LOCK_DURATION_MS = exports.IMAGE_CONCURRENCY = exports.EXPORT_LOCK_DURATION_MS = exports.EXPORT_CONCURRENCY = exports.JOB_ATTEMPTS = exports.JOB_CONCURRENCY = exports.JOB_FAILED_EVENT = exports.JOB_COMPLETED_EVENT = exports.JOB_PROGRESS_EVENT = exports.isQueueName = exports.QUEUE_NAMES = exports.IMAGES_QUEUE = exports.EXPORTS_QUEUE = exports.JOBS_QUEUE = void 0;
|
|
4
4
|
const dotenv_1 = require("dotenv");
|
|
5
5
|
(0, dotenv_1.config)();
|
|
6
6
|
exports.JOBS_QUEUE = "jobs";
|
|
7
7
|
exports.EXPORTS_QUEUE = "exports";
|
|
8
|
-
exports.
|
|
8
|
+
exports.IMAGES_QUEUE = "images";
|
|
9
|
+
exports.QUEUE_NAMES = [exports.JOBS_QUEUE, exports.EXPORTS_QUEUE, exports.IMAGES_QUEUE];
|
|
9
10
|
const isQueueName = (value) => exports.QUEUE_NAMES.includes(value);
|
|
10
11
|
exports.isQueueName = isQueueName;
|
|
11
12
|
exports.JOB_PROGRESS_EVENT = "job:progress";
|
|
@@ -15,6 +16,8 @@ exports.JOB_CONCURRENCY = 5;
|
|
|
15
16
|
exports.JOB_ATTEMPTS = 3;
|
|
16
17
|
exports.EXPORT_CONCURRENCY = 2;
|
|
17
18
|
exports.EXPORT_LOCK_DURATION_MS = 300_000;
|
|
19
|
+
exports.IMAGE_CONCURRENCY = 4;
|
|
20
|
+
exports.IMAGE_LOCK_DURATION_MS = 60_000;
|
|
18
21
|
exports.JOB_BACKOFF_DELAY_MS = 30_000;
|
|
19
22
|
exports.COMPLETED_RETENTION_SECONDS = 86_400;
|
|
20
23
|
exports.FAILED_RETENTION_SECONDS = 14_400;
|
|
@@ -38,6 +38,8 @@ export declare class NotificationsService {
|
|
|
38
38
|
findByUser(user: AuthenticatedUser, query: PaginationQuery): Promise<Paginated<UserNotification>>;
|
|
39
39
|
countUnread(user: AuthenticatedUser): Promise<number>;
|
|
40
40
|
markAsRead(id: string, user: AuthenticatedUser): Promise<void>;
|
|
41
|
+
dismiss(id: string, user: AuthenticatedUser): Promise<void>;
|
|
42
|
+
dismissRead(user: AuthenticatedUser): Promise<number>;
|
|
41
43
|
markAllAsRead(user: AuthenticatedUser): Promise<void>;
|
|
42
44
|
cleanupOldRead(retentionDays: number): Promise<number>;
|
|
43
45
|
private visibilityOf;
|
|
@@ -60,6 +60,18 @@ let NotificationsService = class NotificationsService {
|
|
|
60
60
|
}
|
|
61
61
|
await this.reads.markAsRead([id], user.id);
|
|
62
62
|
}
|
|
63
|
+
async dismiss(id, user) {
|
|
64
|
+
const visible = await this.notifications.isVisibleToUser(id, this.visibilityOf(user));
|
|
65
|
+
if (!visible) {
|
|
66
|
+
throw new common_1.NotFoundException("Notificação não encontrada");
|
|
67
|
+
}
|
|
68
|
+
await this.reads.dismiss([id], user.id);
|
|
69
|
+
}
|
|
70
|
+
async dismissRead(user) {
|
|
71
|
+
const ids = await this.notifications.findReadIds(this.visibilityOf(user));
|
|
72
|
+
await this.reads.dismiss(ids, user.id);
|
|
73
|
+
return ids.length;
|
|
74
|
+
}
|
|
63
75
|
async markAllAsRead(user) {
|
|
64
76
|
const ids = await this.notifications.findUnreadIds(this.visibilityOf(user));
|
|
65
77
|
await this.reads.markAsRead(ids, user.id);
|
|
@@ -9,6 +9,7 @@ export declare class NotificationRepository extends Repository<Notification> {
|
|
|
9
9
|
findVisibleToUser(params: VisibilityParams, page: number, limit: number): Promise<[Notification[], number]>;
|
|
10
10
|
countUnread(params: VisibilityParams): Promise<number>;
|
|
11
11
|
isVisibleToUser(notificationId: string, params: VisibilityParams): Promise<boolean>;
|
|
12
|
+
findReadIds(params: VisibilityParams): Promise<string[]>;
|
|
12
13
|
findUnreadIds(params: VisibilityParams): Promise<string[]>;
|
|
13
14
|
softDeleteReadByAllBefore(limit: Date): Promise<number>;
|
|
14
15
|
private baseVisibleQuery;
|
|
@@ -69,6 +69,13 @@ let NotificationRepository = class NotificationRepository extends typeorm_1.Repo
|
|
|
69
69
|
.getCount();
|
|
70
70
|
return count > 0;
|
|
71
71
|
}
|
|
72
|
+
async findReadIds(params) {
|
|
73
|
+
const rows = await this.baseVisibleQuery(params)
|
|
74
|
+
.andWhere("read.notification_id IS NOT NULL")
|
|
75
|
+
.select("notification.id", "id")
|
|
76
|
+
.getRawMany();
|
|
77
|
+
return rows.map((row) => row.id);
|
|
78
|
+
}
|
|
72
79
|
async findUnreadIds(params) {
|
|
73
80
|
const rows = await this.baseVisibleQuery(params)
|
|
74
81
|
.andWhere("read.notification_id IS NULL")
|
|
@@ -92,6 +99,7 @@ let NotificationRepository = class NotificationRepository extends typeorm_1.Repo
|
|
|
92
99
|
return this.createQueryBuilder("notification")
|
|
93
100
|
.leftJoinAndSelect("notification.reads", "read", "read.user_id = :userId", { userId: params.userId })
|
|
94
101
|
.where("notification.deletedAt IS NULL")
|
|
102
|
+
.andWhere("read.dismissed_at IS NULL")
|
|
95
103
|
.andWhere(VISIBLE_TO_USER, {
|
|
96
104
|
userScope: scopeType_enum_1.ScopeType.USER,
|
|
97
105
|
roleScope: scopeType_enum_1.ScopeType.ROLE,
|
|
@@ -3,4 +3,5 @@ import { NotificationRead } from "../schema/notificationRead.schema";
|
|
|
3
3
|
export declare class NotificationReadRepository extends Repository<NotificationRead> {
|
|
4
4
|
constructor(dataSource: DataSource);
|
|
5
5
|
markAsRead(notificationIds: string[], userId: string): Promise<void>;
|
|
6
|
+
dismiss(notificationIds: string[], userId: string): Promise<void>;
|
|
6
7
|
}
|
|
@@ -32,6 +32,23 @@ let NotificationReadRepository = class NotificationReadRepository extends typeor
|
|
|
32
32
|
.orIgnore()
|
|
33
33
|
.execute();
|
|
34
34
|
}
|
|
35
|
+
async dismiss(notificationIds, userId) {
|
|
36
|
+
if (notificationIds.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const agora = new Date();
|
|
40
|
+
await this.createQueryBuilder()
|
|
41
|
+
.insert()
|
|
42
|
+
.into(notificationRead_schema_1.NotificationRead)
|
|
43
|
+
.values(notificationIds.map((notificationId) => ({
|
|
44
|
+
notificationId,
|
|
45
|
+
userId,
|
|
46
|
+
readAt: agora,
|
|
47
|
+
dismissedAt: agora,
|
|
48
|
+
})))
|
|
49
|
+
.orUpdate(["dismissed_at"], ["notification_id", "user_id"])
|
|
50
|
+
.execute();
|
|
51
|
+
}
|
|
35
52
|
};
|
|
36
53
|
exports.NotificationReadRepository = NotificationReadRepository;
|
|
37
54
|
exports.NotificationReadRepository = NotificationReadRepository = __decorate([
|
|
@@ -27,6 +27,10 @@ __decorate([
|
|
|
27
27
|
(0, typeorm_1.Column)({ name: "read_at", type: "datetime" }),
|
|
28
28
|
__metadata("design:type", Date)
|
|
29
29
|
], NotificationRead.prototype, "readAt", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, typeorm_1.Column)({ name: "dismissed_at", type: "datetime", nullable: true }),
|
|
32
|
+
__metadata("design:type", Object)
|
|
33
|
+
], NotificationRead.prototype, "dismissedAt", void 0);
|
|
30
34
|
__decorate([
|
|
31
35
|
(0, typeorm_1.ManyToOne)(() => notification_schema_1.Notification, { onDelete: "CASCADE" }),
|
|
32
36
|
(0, typeorm_1.JoinColumn)({ name: "notification_id" }),
|
|
@@ -12,5 +12,7 @@ export declare class NotificationsController {
|
|
|
12
12
|
unreadCount(user: AuthenticatedUser): Promise<UnreadCountResponse>;
|
|
13
13
|
markAllAsRead(user: AuthenticatedUser): Promise<void>;
|
|
14
14
|
markAsRead(id: string, user: AuthenticatedUser): Promise<void>;
|
|
15
|
+
dismissRead(user: AuthenticatedUser): Promise<void>;
|
|
16
|
+
dismiss(id: string, user: AuthenticatedUser): Promise<void>;
|
|
15
17
|
create(command: CreateNotificationCommand, user: AuthenticatedUser): Promise<UserNotificationResponse>;
|
|
16
18
|
}
|
|
@@ -40,6 +40,12 @@ let NotificationsController = class NotificationsController {
|
|
|
40
40
|
async markAsRead(id, user) {
|
|
41
41
|
await this.notifications.markAsRead(id, user);
|
|
42
42
|
}
|
|
43
|
+
async dismissRead(user) {
|
|
44
|
+
await this.notifications.dismissRead(user);
|
|
45
|
+
}
|
|
46
|
+
async dismiss(id, user) {
|
|
47
|
+
await this.notifications.dismiss(id, user);
|
|
48
|
+
}
|
|
43
49
|
create(command, user) {
|
|
44
50
|
return this.publisher.publishAndPush({
|
|
45
51
|
title: command.title,
|
|
@@ -88,6 +94,23 @@ __decorate([
|
|
|
88
94
|
__metadata("design:paramtypes", [String, Object]),
|
|
89
95
|
__metadata("design:returntype", Promise)
|
|
90
96
|
], NotificationsController.prototype, "markAsRead", null);
|
|
97
|
+
__decorate([
|
|
98
|
+
(0, common_1.Delete)("read"),
|
|
99
|
+
(0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
|
|
100
|
+
__param(0, (0, currentUser_decorator_1.CurrentUser)()),
|
|
101
|
+
__metadata("design:type", Function),
|
|
102
|
+
__metadata("design:paramtypes", [Object]),
|
|
103
|
+
__metadata("design:returntype", Promise)
|
|
104
|
+
], NotificationsController.prototype, "dismissRead", null);
|
|
105
|
+
__decorate([
|
|
106
|
+
(0, common_1.Delete)(":id"),
|
|
107
|
+
(0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
|
|
108
|
+
__param(0, (0, common_1.Param)("id", common_1.ParseUUIDPipe)),
|
|
109
|
+
__param(1, (0, currentUser_decorator_1.CurrentUser)()),
|
|
110
|
+
__metadata("design:type", Function),
|
|
111
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
112
|
+
__metadata("design:returntype", Promise)
|
|
113
|
+
], NotificationsController.prototype, "dismiss", null);
|
|
91
114
|
__decorate([
|
|
92
115
|
(0, common_1.Post)(),
|
|
93
116
|
(0, requirePermission_decorator_1.RequirePermission)("notifications:create:any"),
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ImageFit, ImageFormat, ImageProfile } from "../../../core/images/imageProfile.interface";
|
|
2
|
+
export declare const AVATAR_MAX_BYTES: number;
|
|
3
|
+
export declare const AVATAR_PROFILE = "avatars";
|
|
4
|
+
export declare class AvatarImageProfile implements ImageProfile {
|
|
5
|
+
readonly name = "avatars";
|
|
6
|
+
readonly folder = "avatars";
|
|
7
|
+
readonly width = 256;
|
|
8
|
+
readonly height = 256;
|
|
9
|
+
readonly fit = ImageFit.COVER;
|
|
10
|
+
readonly format = ImageFormat.WEBP;
|
|
11
|
+
readonly quality = 85;
|
|
12
|
+
readonly maxBytes: number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.AvatarImageProfile = exports.AVATAR_PROFILE = exports.AVATAR_MAX_BYTES = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const imageProfile_interface_1 = require("../../../core/images/imageProfile.interface");
|
|
12
|
+
exports.AVATAR_MAX_BYTES = 5 * 1024 * 1024;
|
|
13
|
+
exports.AVATAR_PROFILE = "avatars";
|
|
14
|
+
let AvatarImageProfile = class AvatarImageProfile {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.name = exports.AVATAR_PROFILE;
|
|
17
|
+
this.folder = "avatars";
|
|
18
|
+
this.width = 256;
|
|
19
|
+
this.height = 256;
|
|
20
|
+
this.fit = imageProfile_interface_1.ImageFit.COVER;
|
|
21
|
+
this.format = imageProfile_interface_1.ImageFormat.WEBP;
|
|
22
|
+
this.quality = 85;
|
|
23
|
+
this.maxBytes = exports.AVATAR_MAX_BYTES;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
exports.AvatarImageProfile = AvatarImageProfile;
|
|
27
|
+
exports.AvatarImageProfile = AvatarImageProfile = __decorate([
|
|
28
|
+
(0, imageProfile_interface_1.ImageUploadProfile)(),
|
|
29
|
+
(0, common_1.Injectable)()
|
|
30
|
+
], AvatarImageProfile);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./avatarImage.profile";
|
|
2
2
|
export * from "./users.service";
|
|
@@ -14,5 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./avatarImage.profile"), exports);
|
|
18
18
|
__exportStar(require("./users.service"), exports);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AuthenticatedUser } from "../../../core/auth/authenticatedUser.interface";
|
|
2
|
+
import { ImagesService } from "../../../core/images/images.service";
|
|
2
3
|
import { FilterFieldResponse } from "../../../core/query/filterSchema.response";
|
|
3
4
|
import { Paginated, PaginationQuery } from "../../../core/utils/pagination.util";
|
|
4
|
-
import { AvatarService } from "../domain/avatar.service";
|
|
5
5
|
import { UsersService } from "../domain/users.service";
|
|
6
6
|
import { User } from "../infra/schema/user.schema";
|
|
7
7
|
import { ChangePasswordCommand } from "./commands/changePassword.command";
|
|
@@ -10,13 +10,14 @@ import { UpdateProfileCommand } from "./commands/updateProfile.command";
|
|
|
10
10
|
import { UpdateUserCommand } from "./commands/updateUser.command";
|
|
11
11
|
export declare class UsersController {
|
|
12
12
|
private readonly users;
|
|
13
|
-
private readonly
|
|
14
|
-
constructor(users: UsersService,
|
|
13
|
+
private readonly images;
|
|
14
|
+
constructor(users: UsersService, images: ImagesService);
|
|
15
15
|
me(userId: string): Promise<User>;
|
|
16
16
|
updateMe(userId: string, dto: UpdateProfileCommand): Promise<User>;
|
|
17
17
|
changeMyPassword(userId: string, dto: ChangePasswordCommand): Promise<void>;
|
|
18
|
-
uploadAvatar(
|
|
19
|
-
deleteAvatar(
|
|
18
|
+
uploadAvatar(user: AuthenticatedUser, file: Express.Multer.File): Promise<User>;
|
|
19
|
+
deleteAvatar(user: AuthenticatedUser): Promise<void>;
|
|
20
|
+
private discardAvatar;
|
|
20
21
|
list(query: PaginationQuery, actor: AuthenticatedUser): Promise<Paginated<User>>;
|
|
21
22
|
filterSchema(actor: AuthenticatedUser): FilterFieldResponse[];
|
|
22
23
|
findOne(id: string, actor: AuthenticatedUser): Promise<User>;
|
|
@@ -21,10 +21,11 @@ const currentUser_decorator_1 = require("../../../core/auth/decorators/currentUs
|
|
|
21
21
|
const requirePermission_decorator_1 = require("../../../core/auth/decorators/requirePermission.decorator");
|
|
22
22
|
const permissions_guard_1 = require("../../../core/auth/guards/permissions.guard");
|
|
23
23
|
const permissionScope_util_1 = require("../../../core/auth/permissionScope.util");
|
|
24
|
+
const images_service_1 = require("../../../core/images/images.service");
|
|
24
25
|
const filterSchema_response_1 = require("../../../core/query/filterSchema.response");
|
|
25
26
|
const pagination_util_1 = require("../../../core/utils/pagination.util");
|
|
26
27
|
const auditable_decorator_1 = require("../../audit/presentation/decorators/auditable.decorator");
|
|
27
|
-
const
|
|
28
|
+
const avatarImage_profile_1 = require("../domain/avatarImage.profile");
|
|
28
29
|
const users_service_1 = require("../domain/users.service");
|
|
29
30
|
const changePassword_command_1 = require("./commands/changePassword.command");
|
|
30
31
|
const createUser_command_1 = require("./commands/createUser.command");
|
|
@@ -33,9 +34,9 @@ const updateUser_command_1 = require("./commands/updateUser.command");
|
|
|
33
34
|
const users_filters_1 = require("./filters/users.filters");
|
|
34
35
|
const user_response_1 = require("./responses/user.response");
|
|
35
36
|
let UsersController = class UsersController {
|
|
36
|
-
constructor(users,
|
|
37
|
+
constructor(users, images) {
|
|
37
38
|
this.users = users;
|
|
38
|
-
this.
|
|
39
|
+
this.images = images;
|
|
39
40
|
}
|
|
40
41
|
me(userId) {
|
|
41
42
|
return this.users.findById(userId);
|
|
@@ -46,13 +47,25 @@ let UsersController = class UsersController {
|
|
|
46
47
|
async changeMyPassword(userId, dto) {
|
|
47
48
|
await this.users.changePassword(userId, dto.currentPassword, dto.newPassword);
|
|
48
49
|
}
|
|
49
|
-
async uploadAvatar(
|
|
50
|
-
const
|
|
51
|
-
|
|
50
|
+
async uploadAvatar(user, file) {
|
|
51
|
+
const previous = (await this.users.findById(user.id)).avatar;
|
|
52
|
+
const path = await this.images.fromFileNow(user, avatarImage_profile_1.AVATAR_PROFILE, file);
|
|
53
|
+
const updated = await this.users.setAvatar(user.id, path);
|
|
54
|
+
await this.discardAvatar(user, previous);
|
|
55
|
+
return updated;
|
|
52
56
|
}
|
|
53
|
-
async deleteAvatar(
|
|
54
|
-
await this.
|
|
55
|
-
await this.users.removeAvatar(
|
|
57
|
+
async deleteAvatar(user) {
|
|
58
|
+
const previous = (await this.users.findById(user.id)).avatar;
|
|
59
|
+
await this.users.removeAvatar(user.id);
|
|
60
|
+
await this.discardAvatar(user, previous);
|
|
61
|
+
}
|
|
62
|
+
async discardAvatar(user, path) {
|
|
63
|
+
if (!path) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
await this.images
|
|
67
|
+
.remove(user, avatarImage_profile_1.AVATAR_PROFILE, path)
|
|
68
|
+
.catch(() => undefined);
|
|
56
69
|
}
|
|
57
70
|
list(query, actor) {
|
|
58
71
|
return this.users.list(query, actor);
|
|
@@ -122,20 +135,20 @@ __decorate([
|
|
|
122
135
|
(0, swagger_1.ApiOkResponse)({ type: user_response_1.UserResponse }),
|
|
123
136
|
(0, common_1.UseInterceptors)((0, platform_express_1.FileInterceptor)("file", {
|
|
124
137
|
storage: (0, multer_1.memoryStorage)(),
|
|
125
|
-
limits: { fileSize:
|
|
138
|
+
limits: { fileSize: avatarImage_profile_1.AVATAR_MAX_BYTES, files: 1 },
|
|
126
139
|
})),
|
|
127
|
-
__param(0, (0, currentUser_decorator_1.CurrentUser)(
|
|
140
|
+
__param(0, (0, currentUser_decorator_1.CurrentUser)()),
|
|
128
141
|
__param(1, (0, common_1.UploadedFile)()),
|
|
129
142
|
__metadata("design:type", Function),
|
|
130
|
-
__metadata("design:paramtypes", [
|
|
143
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
131
144
|
__metadata("design:returntype", Promise)
|
|
132
145
|
], UsersController.prototype, "uploadAvatar", null);
|
|
133
146
|
__decorate([
|
|
134
147
|
(0, common_1.Delete)("me/avatar"),
|
|
135
148
|
(0, common_1.HttpCode)(204),
|
|
136
|
-
__param(0, (0, currentUser_decorator_1.CurrentUser)(
|
|
149
|
+
__param(0, (0, currentUser_decorator_1.CurrentUser)()),
|
|
137
150
|
__metadata("design:type", Function),
|
|
138
|
-
__metadata("design:paramtypes", [
|
|
151
|
+
__metadata("design:paramtypes", [Object]),
|
|
139
152
|
__metadata("design:returntype", Promise)
|
|
140
153
|
], UsersController.prototype, "deleteAvatar", null);
|
|
141
154
|
__decorate([
|
|
@@ -257,5 +270,5 @@ exports.UsersController = UsersController = __decorate([
|
|
|
257
270
|
(0, swagger_1.ApiBearerAuth)(),
|
|
258
271
|
(0, common_1.Controller)({ path: "users", version: "1" }),
|
|
259
272
|
__metadata("design:paramtypes", [users_service_1.UsersService,
|
|
260
|
-
|
|
273
|
+
images_service_1.ImagesService])
|
|
261
274
|
], UsersController);
|