rl-core-api 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/query/filterField.interface.d.ts +1 -0
- package/dist/core/query/filterSort.util.js +3 -0
- package/dist/core/queue/queueAdmin.controller.d.ts +1 -1
- package/dist/core/queue/queueAdmin.controller.js +7 -3
- package/dist/core/queue/queueAdmin.service.d.ts +5 -2
- package/dist/core/queue/queueAdmin.service.js +39 -4
- package/dist/features/audit/infra/repositories/auditDataChange.repository.js +1 -1
- package/dist/features/audit/infra/repositories/requestLog.repository.js +1 -1
- package/dist/features/audit/presentation/filters/audit.filters.js +20 -0
- package/dist/features/users/domain/users.service.js +1 -1
- package/dist/features/users/presentation/commands/updateProfile.command.d.ts +1 -1
- package/dist/features/users/presentation/commands/updateProfile.command.js +13 -8
- package/dist/features/users/presentation/filters/users.filters.js +10 -0
- package/package.json +1 -1
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolveCatalogOrder = void 0;
|
|
4
4
|
const resolveCatalogOrder = (sortBy, sortDir, catalog, alias, fallback) => {
|
|
5
5
|
const chosen = catalog.find((field) => field.field === sortBy && field.sortable && !field.relation);
|
|
6
|
+
if (chosen?.sortColumn) {
|
|
7
|
+
return { column: chosen.sortColumn, direction: sortDir ?? "DESC" };
|
|
8
|
+
}
|
|
6
9
|
const column = chosen?.column ??
|
|
7
10
|
catalog.find((field) => field.field === fallback)?.column ??
|
|
8
11
|
fallback;
|
|
@@ -5,7 +5,7 @@ export declare class QueueAdminController {
|
|
|
5
5
|
private readonly queues;
|
|
6
6
|
constructor(queues: QueueAdminService);
|
|
7
7
|
counts(): Promise<QueueCounts>;
|
|
8
|
-
jobs(state: string, page?: string, limit?: string): Promise<Paginated<QueueJobSummary>>;
|
|
8
|
+
jobs(state: string, page?: string, limit?: string, sortBy?: string, sortDir?: string): Promise<Paginated<QueueJobSummary>>;
|
|
9
9
|
retry(id: string): Promise<void>;
|
|
10
10
|
remove(id: string): Promise<void>;
|
|
11
11
|
}
|
|
@@ -28,8 +28,8 @@ let QueueAdminController = class QueueAdminController {
|
|
|
28
28
|
counts() {
|
|
29
29
|
return this.queues.counts();
|
|
30
30
|
}
|
|
31
|
-
jobs(state, page, limit) {
|
|
32
|
-
return this.queues.list(toState(state), toPositive(page, 1), Math.min(toPositive(limit, DEFAULT_LIMIT), MAX_LIMIT));
|
|
31
|
+
jobs(state, page, limit, sortBy, sortDir) {
|
|
32
|
+
return this.queues.list(toState(state), toPositive(page, 1), Math.min(toPositive(limit, DEFAULT_LIMIT), MAX_LIMIT), sortBy, sortDir === "ASC" ? "ASC" : "DESC");
|
|
33
33
|
}
|
|
34
34
|
retry(id) {
|
|
35
35
|
return this.queues.retry(id);
|
|
@@ -51,12 +51,16 @@ __decorate([
|
|
|
51
51
|
(0, common_1.Get)("jobs"),
|
|
52
52
|
(0, requirePermission_decorator_1.RequirePermission)("queues:read:any"),
|
|
53
53
|
(0, swagger_1.ApiQuery)({ name: "state", enum: queueAdmin_service_1.LISTABLE_STATES }),
|
|
54
|
+
(0, swagger_1.ApiQuery)({ name: "sortBy", enum: queueAdmin_service_1.SORTABLE_JOB_FIELDS, required: false }),
|
|
55
|
+
(0, swagger_1.ApiQuery)({ name: "sortDir", enum: ["ASC", "DESC"], required: false }),
|
|
54
56
|
(0, swagger_1.ApiOkResponse)({ type: queueAdmin_response_1.PaginatedQueueJobsResponse }),
|
|
55
57
|
__param(0, (0, common_1.Query)("state")),
|
|
56
58
|
__param(1, (0, common_1.Query)("page")),
|
|
57
59
|
__param(2, (0, common_1.Query)("limit")),
|
|
60
|
+
__param(3, (0, common_1.Query)("sortBy")),
|
|
61
|
+
__param(4, (0, common_1.Query)("sortDir")),
|
|
58
62
|
__metadata("design:type", Function),
|
|
59
|
-
__metadata("design:paramtypes", [String, String, String]),
|
|
63
|
+
__metadata("design:paramtypes", [String, String, String, String, String]),
|
|
60
64
|
__metadata("design:returntype", Promise)
|
|
61
65
|
], QueueAdminController.prototype, "jobs", null);
|
|
62
66
|
__decorate([
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { QueueCounts, QueueJobSummary } from "./job.interface";
|
|
2
2
|
import { JobProducer } from "./job.producer";
|
|
3
|
-
import { Paginated } from "../utils/pagination.util";
|
|
3
|
+
import { Paginated, SortDir } from "../utils/pagination.util";
|
|
4
4
|
export declare const LISTABLE_STATES: readonly ["waiting", "active", "completed", "failed", "delayed"];
|
|
5
5
|
export type ListableState = (typeof LISTABLE_STATES)[number];
|
|
6
|
+
export declare const SORTABLE_JOB_FIELDS: readonly ["name", "attemptsMade", "percent", "createdAt", "failedReason"];
|
|
7
|
+
export type SortableJobField = (typeof SORTABLE_JOB_FIELDS)[number];
|
|
8
|
+
export declare const SORT_SCAN_LIMIT = 1000;
|
|
6
9
|
export declare class QueueAdminService {
|
|
7
10
|
private readonly producer;
|
|
8
11
|
constructor(producer: JobProducer);
|
|
9
12
|
counts(): Promise<QueueCounts>;
|
|
10
|
-
list(state: ListableState, page: number, limit: number): Promise<Paginated<QueueJobSummary>>;
|
|
13
|
+
list(state: ListableState, page: number, limit: number, sortBy?: string, sortDir?: SortDir): Promise<Paginated<QueueJobSummary>>;
|
|
11
14
|
retry(jobId: string): Promise<void>;
|
|
12
15
|
remove(jobId: string): Promise<void>;
|
|
13
16
|
private findJob;
|
|
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.QueueAdminService = exports.LISTABLE_STATES = void 0;
|
|
12
|
+
exports.QueueAdminService = exports.SORT_SCAN_LIMIT = exports.SORTABLE_JOB_FIELDS = exports.LISTABLE_STATES = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const job_producer_1 = require("./job.producer");
|
|
15
15
|
const pagination_util_1 = require("../utils/pagination.util");
|
|
@@ -20,6 +20,14 @@ exports.LISTABLE_STATES = [
|
|
|
20
20
|
"failed",
|
|
21
21
|
"delayed",
|
|
22
22
|
];
|
|
23
|
+
exports.SORTABLE_JOB_FIELDS = [
|
|
24
|
+
"name",
|
|
25
|
+
"attemptsMade",
|
|
26
|
+
"percent",
|
|
27
|
+
"createdAt",
|
|
28
|
+
"failedReason",
|
|
29
|
+
];
|
|
30
|
+
exports.SORT_SCAN_LIMIT = 1000;
|
|
23
31
|
let QueueAdminService = class QueueAdminService {
|
|
24
32
|
constructor(producer) {
|
|
25
33
|
this.producer = producer;
|
|
@@ -35,15 +43,24 @@ let QueueAdminService = class QueueAdminService {
|
|
|
35
43
|
delayed: counts.delayed ?? 0,
|
|
36
44
|
};
|
|
37
45
|
}
|
|
38
|
-
async list(state, page, limit) {
|
|
46
|
+
async list(state, page, limit, sortBy, sortDir) {
|
|
39
47
|
const queue = this.producer.requireQueue();
|
|
48
|
+
const field = exports.SORTABLE_JOB_FIELDS.find((name) => name === sortBy);
|
|
40
49
|
const start = (page - 1) * limit;
|
|
50
|
+
const range = field
|
|
51
|
+
? [0, exports.SORT_SCAN_LIMIT - 1]
|
|
52
|
+
: [start, start + limit - 1];
|
|
41
53
|
const [jobs, counts] = await Promise.all([
|
|
42
|
-
queue.getJobs([state],
|
|
54
|
+
queue.getJobs([state], range[0], range[1]),
|
|
43
55
|
queue.getJobCounts(state),
|
|
44
56
|
]);
|
|
45
57
|
const items = jobs.filter(Boolean).map((job) => this.toSummary(job, state));
|
|
46
|
-
|
|
58
|
+
const total = counts[state] ?? 0;
|
|
59
|
+
if (!field) {
|
|
60
|
+
return new pagination_util_1.Paginated(items, total, page, limit);
|
|
61
|
+
}
|
|
62
|
+
const ordered = [...items].sort(compareBy(field, sortDir ?? "DESC"));
|
|
63
|
+
return new pagination_util_1.Paginated(ordered.slice(start, start + limit), total, page, limit);
|
|
47
64
|
}
|
|
48
65
|
async retry(jobId) {
|
|
49
66
|
const job = await this.findJob(jobId);
|
|
@@ -83,3 +100,21 @@ exports.QueueAdminService = QueueAdminService = __decorate([
|
|
|
83
100
|
(0, common_1.Injectable)(),
|
|
84
101
|
__metadata("design:paramtypes", [job_producer_1.JobProducer])
|
|
85
102
|
], QueueAdminService);
|
|
103
|
+
const compareBy = (field, direction) => (a, b) => {
|
|
104
|
+
const left = a[field];
|
|
105
|
+
const right = b[field];
|
|
106
|
+
if (left === right) {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
if (left === null) {
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
if (right === null) {
|
|
113
|
+
return -1;
|
|
114
|
+
}
|
|
115
|
+
const factor = direction === "ASC" ? 1 : -1;
|
|
116
|
+
const diff = typeof left === "number" && typeof right === "number"
|
|
117
|
+
? left - right
|
|
118
|
+
: String(left).localeCompare(String(right), "pt-BR");
|
|
119
|
+
return diff * factor;
|
|
120
|
+
};
|
|
@@ -20,7 +20,7 @@ let AuditDataChangeRepository = class AuditDataChangeRepository extends typeorm_
|
|
|
20
20
|
super(auditDataChange_schema_1.AuditDataChange, dataSource.createEntityManager());
|
|
21
21
|
}
|
|
22
22
|
findPaginated(query) {
|
|
23
|
-
return (0, paginateWithFilter_util_1.paginateWithFilter)(this.createQueryBuilder("auditDataChange"), {
|
|
23
|
+
return (0, paginateWithFilter_util_1.paginateWithFilter)(this.createQueryBuilder("auditDataChange").leftJoin("users", "trailUser", "trailUser.id = auditDataChange.user_id"), {
|
|
24
24
|
query,
|
|
25
25
|
catalog: audit_filters_1.AUDIT_DATA_CHANGES_FILTER_CATALOG,
|
|
26
26
|
defaultSort: "createdAt",
|
|
@@ -20,7 +20,7 @@ let RequestLogRepository = class RequestLogRepository extends typeorm_1.Reposito
|
|
|
20
20
|
super(requestLog_schema_1.RequestLog, dataSource.createEntityManager());
|
|
21
21
|
}
|
|
22
22
|
findPaginated(query) {
|
|
23
|
-
return (0, paginateWithFilter_util_1.paginateWithFilter)(this.createQueryBuilder("requestLog"), {
|
|
23
|
+
return (0, paginateWithFilter_util_1.paginateWithFilter)(this.createQueryBuilder("requestLog").leftJoin("users", "logUser", "logUser.id = requestLog.user_id"), {
|
|
24
24
|
query,
|
|
25
25
|
catalog: audit_filters_1.REQUEST_LOGS_FILTER_CATALOG,
|
|
26
26
|
defaultSort: "createdAt",
|
|
@@ -92,6 +92,7 @@ exports.REQUEST_LOGS_FILTER_CATALOG = [
|
|
|
92
92
|
label: "Tipo do erro",
|
|
93
93
|
type: filterFieldType_enum_1.FilterFieldType.Enum,
|
|
94
94
|
options: optionsFromEnum(ERROR_TYPE_LABELS),
|
|
95
|
+
sortable: true,
|
|
95
96
|
},
|
|
96
97
|
{
|
|
97
98
|
field: "errorCode",
|
|
@@ -111,6 +112,15 @@ exports.REQUEST_LOGS_FILTER_CATALOG = [
|
|
|
111
112
|
label: "Usuário",
|
|
112
113
|
type: filterFieldType_enum_1.FilterFieldType.Uuid,
|
|
113
114
|
},
|
|
115
|
+
{
|
|
116
|
+
field: "user",
|
|
117
|
+
column: "userId",
|
|
118
|
+
label: "Usuário (nome)",
|
|
119
|
+
type: filterFieldType_enum_1.FilterFieldType.Text,
|
|
120
|
+
sortable: true,
|
|
121
|
+
filterable: false,
|
|
122
|
+
sortColumn: "logUser.name",
|
|
123
|
+
},
|
|
114
124
|
{
|
|
115
125
|
field: "requestId",
|
|
116
126
|
column: "requestId",
|
|
@@ -154,11 +164,21 @@ exports.AUDIT_DATA_CHANGES_FILTER_CATALOG = [
|
|
|
154
164
|
label: "Usuário",
|
|
155
165
|
type: filterFieldType_enum_1.FilterFieldType.Uuid,
|
|
156
166
|
},
|
|
167
|
+
{
|
|
168
|
+
field: "user",
|
|
169
|
+
column: "userId",
|
|
170
|
+
label: "Usuário (nome)",
|
|
171
|
+
type: filterFieldType_enum_1.FilterFieldType.Text,
|
|
172
|
+
sortable: true,
|
|
173
|
+
filterable: false,
|
|
174
|
+
sortColumn: "trailUser.name",
|
|
175
|
+
},
|
|
157
176
|
{
|
|
158
177
|
field: "ipAddress",
|
|
159
178
|
column: "ipAddress",
|
|
160
179
|
label: "IP",
|
|
161
180
|
type: filterFieldType_enum_1.FilterFieldType.Text,
|
|
181
|
+
sortable: true,
|
|
162
182
|
},
|
|
163
183
|
{
|
|
164
184
|
field: "createdAt",
|
|
@@ -228,7 +228,7 @@ let UsersService = class UsersService {
|
|
|
228
228
|
Object.assign(user, {
|
|
229
229
|
name: dto.name ?? user.name,
|
|
230
230
|
lastName: dto.lastName ?? user.lastName,
|
|
231
|
-
phone: dto.phone
|
|
231
|
+
phone: dto.phone !== undefined ? dto.phone : user.phone,
|
|
232
232
|
});
|
|
233
233
|
await this.userRepo.save(user);
|
|
234
234
|
return this.findById(userId);
|
|
@@ -11,28 +11,33 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.UpdateProfileCommand = void 0;
|
|
13
13
|
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
15
|
const class_validator_1 = require("class-validator");
|
|
16
|
+
const emptyToNull = ({ value }) => typeof value === "string" && value.trim() === "" ? null : value;
|
|
15
17
|
class UpdateProfileCommand {
|
|
16
18
|
}
|
|
17
19
|
exports.UpdateProfileCommand = UpdateProfileCommand;
|
|
18
20
|
__decorate([
|
|
19
21
|
(0, swagger_1.ApiProperty)({ required: false }),
|
|
20
22
|
(0, class_validator_1.IsOptional)(),
|
|
21
|
-
(0, class_validator_1.IsString)(),
|
|
22
|
-
(0, class_validator_1.Length)(2, 100),
|
|
23
|
+
(0, class_validator_1.IsString)({ message: "Nome inválido" }),
|
|
24
|
+
(0, class_validator_1.Length)(2, 100, { message: "O nome precisa ter entre 2 e 100 caracteres" }),
|
|
23
25
|
__metadata("design:type", String)
|
|
24
26
|
], UpdateProfileCommand.prototype, "name", void 0);
|
|
25
27
|
__decorate([
|
|
26
28
|
(0, swagger_1.ApiProperty)({ required: false }),
|
|
27
29
|
(0, class_validator_1.IsOptional)(),
|
|
28
|
-
(0, class_validator_1.IsString)(),
|
|
29
|
-
(0, class_validator_1.Length)(2, 100
|
|
30
|
+
(0, class_validator_1.IsString)({ message: "Sobrenome inválido" }),
|
|
31
|
+
(0, class_validator_1.Length)(2, 100, {
|
|
32
|
+
message: "O sobrenome precisa ter entre 2 e 100 caracteres",
|
|
33
|
+
}),
|
|
30
34
|
__metadata("design:type", String)
|
|
31
35
|
], UpdateProfileCommand.prototype, "lastName", void 0);
|
|
32
36
|
__decorate([
|
|
33
|
-
(0, swagger_1.ApiProperty)({ required: false }),
|
|
37
|
+
(0, swagger_1.ApiProperty)({ required: false, nullable: true }),
|
|
34
38
|
(0, class_validator_1.IsOptional)(),
|
|
35
|
-
(0,
|
|
36
|
-
(0, class_validator_1.
|
|
37
|
-
|
|
39
|
+
(0, class_transformer_1.Transform)(emptyToNull),
|
|
40
|
+
(0, class_validator_1.IsString)({ message: "Telefone inválido" }),
|
|
41
|
+
(0, class_validator_1.Length)(8, 20, { message: "O telefone precisa ter entre 8 e 20 caracteres" }),
|
|
42
|
+
__metadata("design:type", Object)
|
|
38
43
|
], UpdateProfileCommand.prototype, "phone", void 0);
|
|
@@ -37,11 +37,21 @@ exports.USERS_FILTER_CATALOG = [
|
|
|
37
37
|
type: filterFieldType_enum_1.FilterFieldType.Boolean,
|
|
38
38
|
sortable: true,
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
field: "roles",
|
|
42
|
+
column: "id",
|
|
43
|
+
label: "Papéis",
|
|
44
|
+
type: filterFieldType_enum_1.FilterFieldType.Text,
|
|
45
|
+
sortable: true,
|
|
46
|
+
filterable: false,
|
|
47
|
+
sortColumn: "(SELECT MIN(r.name) FROM user_roles ur INNER JOIN roles r ON r.id = ur.role_id WHERE ur.user_id = user.id)",
|
|
48
|
+
},
|
|
40
49
|
{
|
|
41
50
|
field: "twoFactorEnabled",
|
|
42
51
|
column: "twoFactorEnabled",
|
|
43
52
|
label: "2FA configurado",
|
|
44
53
|
type: filterFieldType_enum_1.FilterFieldType.Boolean,
|
|
54
|
+
sortable: true,
|
|
45
55
|
},
|
|
46
56
|
{
|
|
47
57
|
field: "createdAt",
|
package/package.json
CHANGED