@oondemand/oon-core-back 0.3.73 → 0.3.75

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oondemand/oon-core-back",
3
- "version": "0.3.73",
3
+ "version": "0.3.75",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -0,0 +1,353 @@
1
+ "use strict";
2
+
3
+ const express = require("express");
4
+ const auth = require("../core/middlewares/auth");
5
+ const { requirePermission } = require("../core/middlewares/permissions");
6
+ const GenericError = require("../core/errors/GenericError");
7
+ const { asyncHandler } = require("../core/utils/helpers");
8
+ const {
9
+ policy,
10
+ publicPolicy,
11
+ roleByCode,
12
+ canAssignRole,
13
+ } = require("../core/rbac/policy");
14
+ const {
15
+ models,
16
+ appCode,
17
+ audit,
18
+ sanitizeSnapshot,
19
+ createInvitation,
20
+ findInvitationByToken,
21
+ recoverPendingInvitation,
22
+ assertNotLastAdmin,
23
+ } = require("../core/rbac/storage");
24
+ const { provisionInvitation } = require("../core/rbac/identityProvider");
25
+
26
+ const router = express.Router();
27
+
28
+ function requiredRbac() {
29
+ if (!policy().enabled) {
30
+ throw new GenericError("Esta Central ainda utiliza o modo de acesso legado.", {
31
+ statusCode: 409,
32
+ code: "RBAC_NOT_CONFIGURED",
33
+ });
34
+ }
35
+ }
36
+
37
+ function inviteUrl(req, token) {
38
+ const base = String(
39
+ process.env.PUBLIC_APP_URL || `${req.protocol || "http"}://${req.get("host") || req.headers.host}`,
40
+ ).replace(/\/$/, "");
41
+ return `${base}/accept-invite?token=${encodeURIComponent(token)}`;
42
+ }
43
+
44
+ function invitationView(invitation) {
45
+ return {
46
+ id: String(invitation._id),
47
+ email: invitation.email,
48
+ name: invitation.name,
49
+ roleCode: invitation.roleCode,
50
+ status: invitation.status,
51
+ expiresAt: invitation.expiresAt,
52
+ tokenFingerprint: invitation.tokenFingerprint,
53
+ createdAt: invitation.createdAt,
54
+ acceptedAt: invitation.acceptedAt,
55
+ revokedAt: invitation.revokedAt,
56
+ };
57
+ }
58
+
59
+ function accessView(access, invitation) {
60
+ return {
61
+ id: String(access._id),
62
+ identityId: access.identityId,
63
+ email: access.email,
64
+ name: access.name,
65
+ roleCode: access.roleCode,
66
+ status: access.status,
67
+ origin: access.origin,
68
+ mustChangePassword: Boolean(access.mustChangePassword),
69
+ invitedAt: access.invitedAt,
70
+ activatedAt: access.activatedAt,
71
+ disabledAt: access.disabledAt,
72
+ lastAccessAt: access.lastAccessAt,
73
+ invitation: invitation ? invitationView(invitation) : undefined,
74
+ createdAt: access.createdAt,
75
+ updatedAt: access.updatedAt,
76
+ };
77
+ }
78
+
79
+ function assertAssignable(actor, roleCode) {
80
+ const role = roleByCode(roleCode);
81
+ if (!role) {
82
+ throw new GenericError("Perfil inválido.", { statusCode: 422, code: "RBAC_ROLE_NOT_FOUND" });
83
+ }
84
+ if (!canAssignRole(actor.permissions, role)) {
85
+ throw new GenericError("Você não pode atribuir um perfil com privilégios superiores aos seus.", {
86
+ statusCode: 403,
87
+ code: "RBAC_PRIVILEGE_ESCALATION_DENIED",
88
+ });
89
+ }
90
+ return role;
91
+ }
92
+
93
+ router.get("/rbac", (_req, res) => {
94
+ res.json(publicPolicy());
95
+ });
96
+
97
+ router.get(
98
+ "/roles",
99
+ auth,
100
+ requirePermission("roles.read"),
101
+ asyncHandler(async (_req, res) => {
102
+ requiredRbac();
103
+ res.json({ results: publicPolicy().roles });
104
+ }),
105
+ );
106
+
107
+ router.get(
108
+ "/users",
109
+ auth,
110
+ requirePermission("users.read"),
111
+ asyncHandler(async (_req, res) => {
112
+ requiredRbac();
113
+ const { UserAccess, Invitation } = models();
114
+ const [accesses, pendingInvitations] = await Promise.all([
115
+ UserAccess.find({ appCode: appCode() }).sort({ name: 1, email: 1 }).lean(),
116
+ Invitation.find({ appCode: appCode(), status: "pending" }).sort({ createdAt: -1 }).lean(),
117
+ ]);
118
+ const invitationByAccess = new Map();
119
+ for (const invitation of pendingInvitations) {
120
+ const key = String(invitation.accessId);
121
+ if (!invitationByAccess.has(key)) invitationByAccess.set(key, invitation);
122
+ }
123
+ res.json({
124
+ results: accesses.map((access) => accessView(access, invitationByAccess.get(String(access._id)))),
125
+ });
126
+ }),
127
+ );
128
+
129
+ router.post(
130
+ "/users/invitations",
131
+ auth,
132
+ requirePermission("users.invite"),
133
+ asyncHandler(async (req, res) => {
134
+ requiredRbac();
135
+ const role = assertAssignable(req.usuario, req.body?.roleCode);
136
+ const result = await createInvitation({
137
+ email: req.body?.email,
138
+ name: req.body?.name,
139
+ roleCode: role.code,
140
+ actor: req.usuario,
141
+ });
142
+ res.status(201).json({
143
+ access: accessView(result.access, result.invitation),
144
+ invitation: invitationView(result.invitation),
145
+ inviteUrl: inviteUrl(req, result.token),
146
+ });
147
+ }),
148
+ );
149
+
150
+ router.get(
151
+ "/users/invitations/:id/link",
152
+ auth,
153
+ requirePermission("users.invite"),
154
+ asyncHandler(async (req, res) => {
155
+ requiredRbac();
156
+ const result = await recoverPendingInvitation(req.params.id);
157
+ if (!result?.invitation) {
158
+ throw new GenericError("Convite não encontrado.", { statusCode: 404 });
159
+ }
160
+ if (!result.token) {
161
+ throw new GenericError("O convite não está mais válido para cópia.", {
162
+ statusCode: 410,
163
+ code: "RBAC_INVITATION_INVALID",
164
+ });
165
+ }
166
+ await audit("invitation.link.copied", {
167
+ actor: req.usuario,
168
+ target: result.invitation.email,
169
+ context: { invitationId: String(result.invitation._id) },
170
+ });
171
+ res.set("Cache-Control", "no-store");
172
+ res.json({
173
+ invitation: invitationView(result.invitation),
174
+ inviteUrl: inviteUrl(req, result.token),
175
+ });
176
+ }),
177
+ );
178
+
179
+ router.post(
180
+ "/users/invitations/:id/regenerate",
181
+ auth,
182
+ requirePermission("users.invite"),
183
+ asyncHandler(async (req, res) => {
184
+ requiredRbac();
185
+ const { Invitation } = models();
186
+ const previous = await Invitation.findOne({ _id: req.params.id, appCode: appCode() });
187
+ if (!previous) throw new GenericError("Convite não encontrado.", { statusCode: 404 });
188
+ assertAssignable(req.usuario, previous.roleCode);
189
+ const result = await createInvitation({
190
+ email: previous.email,
191
+ name: previous.name,
192
+ roleCode: previous.roleCode,
193
+ actor: req.usuario,
194
+ });
195
+ await audit("invitation.regenerated", {
196
+ actor: req.usuario,
197
+ target: previous.email,
198
+ context: { previousInvitationId: String(previous._id), invitationId: String(result.invitation._id) },
199
+ });
200
+ res.json({
201
+ invitation: invitationView(result.invitation),
202
+ inviteUrl: inviteUrl(req, result.token),
203
+ });
204
+ }),
205
+ );
206
+
207
+ router.delete(
208
+ "/users/invitations/:id",
209
+ auth,
210
+ requirePermission("users.invite"),
211
+ asyncHandler(async (req, res) => {
212
+ requiredRbac();
213
+ const { Invitation, UserAccess } = models();
214
+ const invitation = await Invitation.findOne({ _id: req.params.id, appCode: appCode() });
215
+ if (!invitation) throw new GenericError("Convite não encontrado.", { statusCode: 404 });
216
+ if (invitation.status === "pending") {
217
+ invitation.status = "revoked";
218
+ invitation.revokedAt = new Date();
219
+ await invitation.save();
220
+ await UserAccess.updateOne(
221
+ { _id: invitation.accessId, appCode: appCode(), status: "invited" },
222
+ { $set: { status: "revoked", revokedAt: new Date() } },
223
+ );
224
+ await audit("invitation.revoked", { actor: req.usuario, target: invitation.email, after: invitation });
225
+ }
226
+ res.status(204).end();
227
+ }),
228
+ );
229
+
230
+ router.patch(
231
+ "/users/:id",
232
+ auth,
233
+ requirePermission(["users.update", "users.disable"]),
234
+ asyncHandler(async (req, res) => {
235
+ requiredRbac();
236
+ const { UserAccess } = models();
237
+ const access = await UserAccess.findOne({ _id: req.params.id, appCode: appCode() });
238
+ if (!access) throw new GenericError("Usuário não encontrado.", { statusCode: 404 });
239
+ const before = sanitizeSnapshot(access);
240
+
241
+ if (req.body?.roleCode && req.body.roleCode !== access.roleCode) {
242
+ if (!req.usuario.permissions?.includes("users.update") && !req.usuario.permissions?.includes("*")) {
243
+ throw new GenericError("Sem permissão para alterar o perfil.", { statusCode: 403 });
244
+ }
245
+ const role = assertAssignable(req.usuario, req.body.roleCode);
246
+ await assertNotLastAdmin(access, role.code);
247
+ access.roleCode = role.code;
248
+ }
249
+
250
+ if (req.body?.status && req.body.status !== access.status) {
251
+ if (!req.usuario.permissions?.includes("users.disable") && !req.usuario.permissions?.includes("*")) {
252
+ throw new GenericError("Sem permissão para alterar o status do acesso.", { statusCode: 403 });
253
+ }
254
+ if (!["active", "disabled", "revoked"].includes(req.body.status)) {
255
+ throw new GenericError("Status de acesso inválido.", { statusCode: 422 });
256
+ }
257
+ if (["disabled", "revoked"].includes(req.body.status)) await assertNotLastAdmin(access, null);
258
+ access.status = req.body.status;
259
+ access.disabledAt = req.body.status === "disabled" ? new Date() : undefined;
260
+ access.revokedAt = req.body.status === "revoked" ? new Date() : undefined;
261
+ if (req.body.status === "active") {
262
+ access.disabledAt = undefined;
263
+ access.revokedAt = undefined;
264
+ access.activatedAt = access.activatedAt || new Date();
265
+ }
266
+ }
267
+
268
+ await access.save();
269
+ await audit("user.access.updated", { actor: req.usuario, target: access, before, after: access });
270
+ res.json({ user: accessView(access) });
271
+ }),
272
+ );
273
+
274
+ router.get(
275
+ "/invitations/:token",
276
+ asyncHandler(async (req, res) => {
277
+ requiredRbac();
278
+ const invitation = await findInvitationByToken(req.params.token);
279
+ if (!invitation || invitation.status !== "pending") {
280
+ throw new GenericError("Convite inválido, expirado ou já utilizado.", {
281
+ statusCode: 410,
282
+ code: "RBAC_INVITATION_INVALID",
283
+ });
284
+ }
285
+ res.set("Cache-Control", "no-store");
286
+ res.json({
287
+ invitation: {
288
+ email: invitation.email,
289
+ name: invitation.name,
290
+ roleCode: invitation.roleCode,
291
+ roleName: roleByCode(invitation.roleCode)?.name,
292
+ expiresAt: invitation.expiresAt,
293
+ },
294
+ });
295
+ }),
296
+ );
297
+
298
+ router.post(
299
+ "/invitations/:token/accept",
300
+ asyncHandler(async (req, res) => {
301
+ requiredRbac();
302
+ const password = String(req.body?.password || "");
303
+ if (password.length < 8) {
304
+ throw new GenericError("A nova senha deve possuir pelo menos 8 caracteres.", { statusCode: 422 });
305
+ }
306
+
307
+ const invitation = await findInvitationByToken(req.params.token);
308
+ if (!invitation || invitation.status !== "pending") {
309
+ throw new GenericError("Convite inválido, expirado ou já utilizado.", {
310
+ statusCode: 410,
311
+ code: "RBAC_INVITATION_INVALID",
312
+ });
313
+ }
314
+
315
+ const { UserAccess } = models();
316
+ const access = await UserAccess.findOne({ _id: invitation.accessId, appCode: appCode() });
317
+ if (!access || access.status !== "invited") {
318
+ throw new GenericError("O acesso associado ao convite não está mais disponível.", { statusCode: 410 });
319
+ }
320
+
321
+ const identity = await provisionInvitation({ req, invitation, password });
322
+ const providerUser = identity?.usuario || identity?.user || identity;
323
+ access.identityId = String(providerUser?.id || providerUser?._id || access.identityId || "") || undefined;
324
+ access.name = providerUser?.nome || providerUser?.name || access.name;
325
+ access.status = "active";
326
+ access.mustChangePassword = false;
327
+ access.activatedAt = new Date();
328
+ access.disabledAt = undefined;
329
+ access.revokedAt = undefined;
330
+ await access.save();
331
+
332
+ invitation.status = "accepted";
333
+ invitation.acceptedAt = new Date();
334
+ await invitation.save();
335
+ await audit("invitation.accepted", {
336
+ actor: access.identityId || access.email,
337
+ target: access,
338
+ after: access,
339
+ context: { invitationId: String(invitation._id) },
340
+ });
341
+
342
+ res.set("Cache-Control", "no-store");
343
+ res.json({
344
+ message: "Convite aceito. A nova senha foi definida e o acesso está ativo.",
345
+ email: access.email,
346
+ });
347
+ }),
348
+ );
349
+
350
+ module.exports = router;
351
+ module.exports.inviteUrl = inviteUrl;
352
+ module.exports.accessView = accessView;
353
+ module.exports.assertAssignable = assertAssignable;
@@ -5,6 +5,8 @@ const ctx = require("../core/context");
5
5
  const GenericError = require("../core/errors/GenericError");
6
6
  const { asyncHandler, sendResponse } = require("../core/utils/helpers");
7
7
  const { ensureInstance } = require("../core/utils/instanceActivation");
8
+ const { findAccessForUser, audit } = require("../core/rbac/storage");
9
+ const { changeFirstAccessPassword } = require("../core/rbac/identityProvider");
8
10
  const {
9
11
  LOGIN_PATH,
10
12
  getBaseUrl,
@@ -13,46 +15,29 @@ const {
13
15
  } = require("../core/utils/activationProvider");
14
16
 
15
17
  const DEV_ACTIVATION_PATH = "/integracao/dev-local/ativar-central";
16
-
17
- /**
18
- * Rotas de autenticação do Core. Em aplicações member, o login é delegado para
19
- * a Central de Ativações com o código do app carregado do ambiente do backend.
20
- */
21
18
  const router = express.Router();
22
19
 
23
20
  function readBasicAuthorization(req) {
24
21
  const authorization = String(req.headers.authorization || "");
25
22
  if (!authorization.startsWith("Basic ")) {
26
- throw new GenericError("Credenciais de autenticação ausentes.", {
27
- statusCode: 401,
28
- });
23
+ throw new GenericError("Credenciais de autenticação ausentes.", { statusCode: 401 });
29
24
  }
30
25
  return authorization;
31
26
  }
32
27
 
33
28
  function readOptionalAppCode() {
34
29
  return String(
35
- process.env.APP_CODE ||
36
- process.env.APP_CODIGO ||
37
- process.env.OON_APP_CODE ||
38
- process.env.OON_APP_CODIGO ||
39
- "",
40
- )
41
- .trim()
42
- .toLowerCase();
30
+ process.env.APP_CODE || process.env.APP_CODIGO || process.env.OON_APP_CODE || process.env.OON_APP_CODIGO || "",
31
+ ).trim().toLowerCase();
43
32
  }
44
33
 
45
34
  function translateProviderError(error) {
46
35
  if (error instanceof GenericError) return error;
47
-
48
36
  const timedOut = error.code === "ECONNABORTED";
49
37
  const statusCode = timedOut ? 504 : error.response?.status || 502;
50
- const message =
51
- error.response?.data?.message ||
52
- (timedOut
53
- ? "A Central de Ativações não respondeu dentro do prazo."
54
- : "Não foi possível autenticar o usuário na Central de Ativações.");
55
-
38
+ const message = error.response?.data?.message || (timedOut
39
+ ? "A Central de Ativações não respondeu dentro do prazo."
40
+ : "Não foi possível autenticar o usuário na Central de Ativações.");
56
41
  return new GenericError(message, { statusCode });
57
42
  }
58
43
 
@@ -62,7 +47,6 @@ async function authenticateRoot(req, res, authorization, instance) {
62
47
  const result = await authenticate({ authorization, req });
63
48
  const statusCode = result?.statusCode || 200;
64
49
  const data = result?.data || result;
65
-
66
50
  res.set("Cache-Control", "no-store");
67
51
  res.status(statusCode).json(data);
68
52
  return true;
@@ -74,13 +58,10 @@ router.post(
74
58
  "/autenticar",
75
59
  asyncHandler(async (req, res) => {
76
60
  const authorization = readBasicAuthorization(req);
77
-
78
61
  const instance = await ensureInstance();
79
62
  if (await authenticateRoot(req, res, authorization, instance)) return;
80
-
81
63
  const baseUrl = getBaseUrl(req);
82
64
  const appCode = getAppCode();
83
-
84
65
  try {
85
66
  const response = await axios.post(
86
67
  `${baseUrl}${LOGIN_PATH}`,
@@ -95,7 +76,6 @@ router.post(
95
76
  },
96
77
  },
97
78
  );
98
-
99
79
  res.set("Cache-Control", "no-store");
100
80
  res.status(response.status).json(response.data);
101
81
  } catch (error) {
@@ -110,7 +90,6 @@ router.post(
110
90
  const authorization = readBasicAuthorization(req);
111
91
  const baseUrl = getBaseUrl(req);
112
92
  const appCode = readOptionalAppCode();
113
-
114
93
  try {
115
94
  const response = await axios.post(
116
95
  `${baseUrl}${DEV_ACTIVATION_PATH}`,
@@ -129,13 +108,9 @@ router.post(
129
108
  {
130
109
  timeout: getTimeout(),
131
110
  maxRedirects: 0,
132
- headers: {
133
- Authorization: authorization,
134
- "Content-Type": "application/json",
135
- },
111
+ headers: { Authorization: authorization, "Content-Type": "application/json" },
136
112
  },
137
113
  );
138
-
139
114
  res.set("Cache-Control", "no-store");
140
115
  res.status(response.status).json(response.data);
141
116
  } catch (error) {
@@ -148,8 +123,38 @@ router.get(
148
123
  "/validar-token",
149
124
  auth,
150
125
  asyncHandler(async (req, res) => {
126
+ res.set("Cache-Control", "no-store");
151
127
  sendResponse({ res, statusCode: 200, usuario: req.usuario });
152
128
  }),
153
129
  );
154
130
 
131
+ router.post(
132
+ "/first-access/password",
133
+ auth,
134
+ asyncHandler(async (req, res) => {
135
+ if (!req.usuario.mustChangePassword) {
136
+ throw new GenericError("O primeiro acesso já foi concluído.", {
137
+ statusCode: 409,
138
+ code: "FIRST_ACCESS_ALREADY_COMPLETED",
139
+ });
140
+ }
141
+ const password = String(req.body?.password || "");
142
+ if (password.length < 8) {
143
+ throw new GenericError("A nova senha deve possuir pelo menos 8 caracteres.", { statusCode: 422 });
144
+ }
145
+
146
+ await changeFirstAccessPassword({ req, user: req.usuario, password });
147
+ const access = await findAccessForUser(req.usuario);
148
+ if (access) {
149
+ access.mustChangePassword = false;
150
+ access.status = "active";
151
+ access.activatedAt = access.activatedAt || new Date();
152
+ await access.save();
153
+ }
154
+ await audit("user.first_access.completed", { actor: req.usuario, target: access || req.usuario });
155
+ res.set("Cache-Control", "no-store");
156
+ res.json({ message: "Nova senha definida. Primeiro acesso concluído." });
157
+ }),
158
+ );
159
+
155
160
  module.exports = router;
@@ -12,6 +12,7 @@ const { buildModelRouter } = require("../core/factories/modelRouter");
12
12
  const { buildIntegrationRouter, integrationsEnabled } = require("../modules/integrations");
13
13
 
14
14
  const coreRoutes = require("../api/core.routes");
15
+ const accessRoutes = require("../api/access.routes");
15
16
  const statusRoutes = require("../api/status.routes");
16
17
  const authRoutes = require("../api/auth.routes");
17
18
  const activationRoutes = require("../api/activation.routes");
@@ -31,10 +32,9 @@ function createApp() {
31
32
  app.use("/ativacao", activationRoutes);
32
33
  app.use(activationGuard);
33
34
  app.use("/auth", authRoutes);
35
+ app.use("/core", accessRoutes);
34
36
  app.use("/core", coreRoutes);
35
37
 
36
- // A engine é montada antes do log genérico: webhooks podem carregar tokens
37
- // e payloads sensíveis. A própria engine persiste diagnóstico sanitizado.
38
38
  if (integrationsEnabled(ctx.config)) {
39
39
  const integrationRouter = buildIntegrationRouter();
40
40
  app.use("/integrations", integrationRouter);
@@ -5,6 +5,7 @@ const ctx = require("./context");
5
5
  const { asyncHandler } = require("./utils/helpers");
6
6
  const auth = require("./middlewares/auth");
7
7
  const { rbac } = require("./middlewares/rbac");
8
+ const { requirePermission } = require("./middlewares/permissions");
8
9
  const { mutationAudit } = require("./middlewares/mutationAudit");
9
10
 
10
11
  function buildSchema(schemaDef, options = {}) {
@@ -123,7 +124,10 @@ function defineRoutes(basePath, builder) {
123
124
  handler = opts;
124
125
  opts = {};
125
126
  }
126
- const chain = [auth, rbac(opts.roles || [])];
127
+ const chain = [auth];
128
+ const required = opts.permission || opts.permissions;
129
+ if (required) chain.push(requirePermission(required));
130
+ else chain.push(rbac(opts.roles || []));
127
131
  if (["post", "put", "patch", "delete"].includes(method) && opts.audit) {
128
132
  chain.push(mutationAudit(opts.audit));
129
133
  }
@@ -2,16 +2,14 @@ const express = require("express");
2
2
  const { asyncHandler } = require("../utils/helpers");
3
3
  const auth = require("../middlewares/auth");
4
4
  const { rbac } = require("../middlewares/rbac");
5
+ const { requirePermission } = require("../middlewares/permissions");
5
6
  const { mutationAudit } = require("../middlewares/mutationAudit");
6
7
  const { createCrudService } = require("./crudService");
7
8
  const { createCrudController } = require("./crudController");
8
9
 
9
10
  /**
10
- * Monta o router de CRUD de uma model. Todas as rotas são privadas
11
- * (auth obrigatório). Mutações passam por RBAC + mutationAudit.
12
- *
13
- * Endpoints (Seção 2.9): GET list, GET :id, POST, PUT :id, PATCH :id,
14
- * DELETE :id, POST /import, GET /export.
11
+ * Monta o router de CRUD de uma model. `crud.permissions` é o contrato
12
+ * canônico; `crud.roles` permanece como fallback para Centrais legadas.
15
13
  */
16
14
  function buildModelRouter(entry) {
17
15
  const router = express.Router();
@@ -20,43 +18,48 @@ function buildModelRouter(entry) {
20
18
 
21
19
  const crud = entry.definition.crud || {};
22
20
  const roles = crud.roles || {};
23
- const readRoles = roles.read || [];
24
- const writeRoles = roles.write || [];
21
+ const permissions = crud.permissions || {};
22
+ const readGuard = permissions.read
23
+ ? requirePermission(permissions.read)
24
+ : rbac(roles.read || []);
25
+ const writeGuard = permissions.write
26
+ ? requirePermission(permissions.write)
27
+ : rbac(roles.write || []);
25
28
  const entidade = entry.name;
26
29
 
27
30
  router.use(auth);
28
31
 
29
- router.get("/", rbac(readRoles), asyncHandler(controller.list));
30
- router.get("/export", rbac(readRoles), asyncHandler(controller.exportAll));
31
- router.get("/:id", rbac(readRoles), asyncHandler(controller.getById));
32
+ router.get("/", readGuard, asyncHandler(controller.list));
33
+ router.get("/export", readGuard, asyncHandler(controller.exportAll));
34
+ router.get("/:id", readGuard, asyncHandler(controller.getById));
32
35
 
33
36
  router.post(
34
37
  "/import",
35
- rbac(writeRoles),
38
+ writeGuard,
36
39
  mutationAudit({ entidade, acao: "adicionado" }),
37
40
  asyncHandler(controller.importMany)
38
41
  );
39
42
  router.post(
40
43
  "/",
41
- rbac(writeRoles),
44
+ writeGuard,
42
45
  mutationAudit({ entidade, acao: "adicionado" }),
43
46
  asyncHandler(controller.create)
44
47
  );
45
48
  router.put(
46
49
  "/:id",
47
- rbac(writeRoles),
50
+ writeGuard,
48
51
  mutationAudit({ entidade, acao: "alterado" }),
49
52
  asyncHandler(controller.update)
50
53
  );
51
54
  router.patch(
52
55
  "/:id",
53
- rbac(writeRoles),
56
+ writeGuard,
54
57
  mutationAudit({ entidade, acao: "alterado" }),
55
58
  asyncHandler(controller.patch)
56
59
  );
57
60
  router.delete(
58
61
  "/:id",
59
- rbac(writeRoles),
62
+ writeGuard,
60
63
  mutationAudit({ entidade, acao: "excluido" }),
61
64
  asyncHandler(controller.remove)
62
65
  );