aloux-iam 0.0.140 → 0.0.142
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/lib/config/utils.js +75 -18
- package/lib/controllers/business.js +65 -0
- package/lib/controllers/company.js +35 -0
- package/lib/controllers/generatePassword.js +13 -0
- package/lib/controllers/log.js +92 -72
- package/lib/controllers/totp.js +46 -0
- package/lib/controllers/user.js +41 -50
- package/lib/models/Log.js +1 -0
- package/lib/models/User.js +10 -1
- package/lib/router.js +16 -0
- package/lib/services/auth.js +37 -49
- package/lib/services/generatePassword.js +44 -0
- package/lib/services/totp.js +169 -0
- package/lib/services/user.js +148 -68
- package/lib/swagger.yaml +209 -1
- package/package.json +4 -2
package/lib/config/utils.js
CHANGED
|
@@ -1,22 +1,79 @@
|
|
|
1
|
-
const
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const self = module.exports;
|
|
2
3
|
|
|
3
4
|
self.responseError = async (res, error) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
5
|
+
let obj = error;
|
|
6
|
+
if (!error.code) {
|
|
7
|
+
obj = {
|
|
8
|
+
code: 400,
|
|
9
|
+
title: "Error",
|
|
10
|
+
detail: error.message,
|
|
11
|
+
suggestion: "Revisar el detalle",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
res.status(obj.code).send(obj);
|
|
15
|
+
};
|
|
15
16
|
|
|
16
17
|
self.generatePaginationResponse = async (count, page, itemsPerPage, items) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
18
|
+
const totalPages = Math.ceil(count / itemsPerPage);
|
|
19
|
+
const currentPage = Math.max(1, Math.min(Number(page), totalPages));
|
|
20
|
+
const finalCurrentPage = totalPages === 0 ? 1 : currentPage;
|
|
21
|
+
const remainingPages = Math.max(0, totalPages - finalCurrentPage);
|
|
22
|
+
return { currentPage: finalCurrentPage, totalPages, perPage: Number(itemsPerPage), count, remainingPages, items };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
self.brand = {
|
|
26
|
+
_cfg: null,
|
|
27
|
+
|
|
28
|
+
init(config) {
|
|
29
|
+
this._cfg = config;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
_get(key) {
|
|
33
|
+
if (this._cfg) return this._cfg[key];
|
|
34
|
+
const APP = process.env.APP;
|
|
35
|
+
if (APP) return process.env[`${key}_${APP}`] || process.env[key];
|
|
36
|
+
return process.env[key];
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
name() {
|
|
40
|
+
return this._get("PROJECT_NAME");
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
template(key) {
|
|
44
|
+
const path = this._get(key);
|
|
45
|
+
if (!path) {
|
|
46
|
+
throw {
|
|
47
|
+
code: 500,
|
|
48
|
+
title: "Error de configuración",
|
|
49
|
+
detail: `Template no encontrado: ${key}`,
|
|
50
|
+
suggestion: "Verifica que la variable de entorno esté definida",
|
|
51
|
+
error: new Error(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
let file = fs.readFileSync(path, "utf8");
|
|
56
|
+
file = file.replace(/\+\+\+brandName\+\+\+/g, this.name() || "");
|
|
57
|
+
file = file.replace(/\+\+\+brandColor\+\+\+/g, this._get("BRAND_COLOR") || "");
|
|
58
|
+
file = file.replace(/\+\+\+brandLogo\+\+\+/g, this._get("BRAND_LOGO") || "");
|
|
59
|
+
return file;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
throw {
|
|
62
|
+
code: 500,
|
|
63
|
+
title: "Error al leer template",
|
|
64
|
+
detail: `No se pudo leer el archivo: ${path}`,
|
|
65
|
+
suggestion: "Verifica que el path del template sea correcto",
|
|
66
|
+
error: e,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Gkey
|
|
73
|
+
self.resolveGkey = (business) => {
|
|
74
|
+
const businessGkey = business.gkey || null;
|
|
75
|
+
const hasOwnKey = businessGkey?.status === true;
|
|
76
|
+
|
|
77
|
+
if (hasOwnKey) return { gkey: businessGkey, source: "business" };
|
|
78
|
+
return { gkey: null, source: null };
|
|
79
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const Business = require("../models/Business");
|
|
2
|
+
const Company = require("../models/Company");
|
|
2
3
|
const utils = require("../config/utils");
|
|
3
4
|
const AlouxAWS = require("./operationsAWS");
|
|
4
5
|
const errorController = require("../config/utils");
|
|
6
|
+
const { resolveGkey } = require("../config/utils");
|
|
5
7
|
|
|
6
8
|
const self = module.exports;
|
|
7
9
|
|
|
@@ -11,16 +13,26 @@ self.create = async (req, res) => {
|
|
|
11
13
|
req.body.lastUpdate = req.body.createdAt;
|
|
12
14
|
req.body.status = "Activo";
|
|
13
15
|
|
|
16
|
+
let inheritedGkey = null;
|
|
17
|
+
if (req.body.data?.useCompanyKey && req.body._company) {
|
|
18
|
+
const company = await Company.findOne({ _id: req.body._company }).lean();
|
|
19
|
+
const companyGkey = company?.data?.gkey;
|
|
20
|
+
if (companyGkey?.status) inheritedGkey = companyGkey;
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
if (req.body.environment && req.body.environment.length > 1) {
|
|
15
24
|
for (let i in req.body.environment) {
|
|
16
25
|
const business = new Business(req.body);
|
|
17
26
|
business.environment = req.body.environment[i];
|
|
27
|
+
if (inheritedGkey) business.gkey = inheritedGkey;
|
|
18
28
|
await business.save();
|
|
19
29
|
}
|
|
20
30
|
} else {
|
|
21
31
|
const business = new Business(req.body);
|
|
32
|
+
if (inheritedGkey) business.gkey = inheritedGkey;
|
|
22
33
|
await business.save();
|
|
23
34
|
}
|
|
35
|
+
|
|
24
36
|
await res.status(201).send({});
|
|
25
37
|
} catch (error) {
|
|
26
38
|
await errorController.responseError(res, error);
|
|
@@ -250,3 +262,56 @@ self.identity = async (req, res) => {
|
|
|
250
262
|
await errorController.responseError(res, error);
|
|
251
263
|
}
|
|
252
264
|
};
|
|
265
|
+
|
|
266
|
+
self.setUseCompanyKey = async (req, res) => {
|
|
267
|
+
try {
|
|
268
|
+
const business = await Business.findOne({ _id: req.params.BUSINESS_ID }).lean();
|
|
269
|
+
if (!business) throw { code: 404, title: "No encontrado", detail: "No existe el negocio" };
|
|
270
|
+
|
|
271
|
+
await Business.updateOne(
|
|
272
|
+
{ _id: req.params.BUSINESS_ID },
|
|
273
|
+
{
|
|
274
|
+
$unset: { gkey: "" },
|
|
275
|
+
$set: {
|
|
276
|
+
"data.useCompanyKey": false,
|
|
277
|
+
lastUpdate: new Date().getTime(),
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
res.status(202).send({ ok: true });
|
|
283
|
+
} catch (error) {
|
|
284
|
+
await errorController.responseError(res, error);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
self.inheritKey = async (req, res) => {
|
|
289
|
+
try {
|
|
290
|
+
const business = await Business.findOne({ _id: req.params.BUSINESS_ID })
|
|
291
|
+
.populate("_company")
|
|
292
|
+
.lean();
|
|
293
|
+
if (!business) throw { code: 404, title: "No encontrado", detail: "No existe el negocio" };
|
|
294
|
+
|
|
295
|
+
const companyGkey = business._company?.data?.gkey;
|
|
296
|
+
if (!companyGkey?.status) throw {
|
|
297
|
+
code: 400,
|
|
298
|
+
title: "Sin llave",
|
|
299
|
+
detail: "La organización no tiene una llave de Google Cloud configurada",
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await Business.updateOne(
|
|
303
|
+
{ _id: req.params.BUSINESS_ID },
|
|
304
|
+
{
|
|
305
|
+
$set: {
|
|
306
|
+
gkey: companyGkey,
|
|
307
|
+
"data.useCompanyKey": true,
|
|
308
|
+
lastUpdate: new Date().getTime(),
|
|
309
|
+
},
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
res.status(202).send({ ok: true });
|
|
314
|
+
} catch (error) {
|
|
315
|
+
await errorController.responseError(res, error);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
@@ -153,3 +153,38 @@ self.identity = async (req, res) => {
|
|
|
153
153
|
await errorController.responseError(res, error);
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
|
+
|
|
157
|
+
self.updateGkey = async (req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
const company = await Company.findOne({ _id: req.params.COMPANY_ID });
|
|
160
|
+
if (!company) throw { code: 404, title: "No encontrado", detail: "No existe la organización" };
|
|
161
|
+
|
|
162
|
+
company.data = { ...(company.data || {}), gkey: req.body.gkey };
|
|
163
|
+
company.lastUpdate = new Date().getTime();
|
|
164
|
+
company.markModified("data");
|
|
165
|
+
await company.save();
|
|
166
|
+
|
|
167
|
+
res.status(202).send({ ok: true });
|
|
168
|
+
} catch (error) {
|
|
169
|
+
await errorController.responseError(res, error);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
self.deleteGkey = async (req, res) => {
|
|
174
|
+
try {
|
|
175
|
+
const company = await Company.findOne({ _id: req.params.COMPANY_ID });
|
|
176
|
+
if (!company) throw { code: 404, title: "No encontrado", detail: "No existe la organización" };
|
|
177
|
+
|
|
178
|
+
const newData = { ...(company.data || {}) };
|
|
179
|
+
delete newData.gkey;
|
|
180
|
+
|
|
181
|
+
company.data = newData;
|
|
182
|
+
company.lastUpdate = new Date().getTime();
|
|
183
|
+
company.markModified("data");
|
|
184
|
+
await company.save();
|
|
185
|
+
|
|
186
|
+
res.status(200).send({ ok: true });
|
|
187
|
+
} catch (error) {
|
|
188
|
+
await errorController.responseError(res, error);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const passwordService = require("../services/generatePassword");
|
|
2
|
+
|
|
3
|
+
const self = module.exports;
|
|
4
|
+
|
|
5
|
+
self.generate = (req, res) => {
|
|
6
|
+
try {
|
|
7
|
+
const length = Number(req.query.length) || 12;
|
|
8
|
+
const password = passwordService.generatePassword(length);
|
|
9
|
+
return res.json({ password });
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return res.status(500).json({ message: "Error al generar la contraseña", error });
|
|
12
|
+
}
|
|
13
|
+
};
|
package/lib/controllers/log.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const Log = require("../models/Log");
|
|
2
2
|
const Label = require("../models/Label");
|
|
3
|
+
const mongoose = require("mongoose");
|
|
3
4
|
const self = module.exports;
|
|
4
5
|
|
|
5
6
|
self.create = async (req, res) => {
|
|
@@ -8,9 +9,11 @@ self.create = async (req, res) => {
|
|
|
8
9
|
req.header("Company") !== "undefined" ? req.header("Company") : null;
|
|
9
10
|
|
|
10
11
|
const log = new Log(req.body);
|
|
12
|
+
const businessId = req.header("business") !== "undefined" ? req.header("business") : null;
|
|
11
13
|
log.createdAt = new Date().getTime();
|
|
12
14
|
log._user = req.user._id;
|
|
13
15
|
log._company = companyId;
|
|
16
|
+
log._business = businessId;
|
|
14
17
|
|
|
15
18
|
log.label = req.body.label;
|
|
16
19
|
await log.save();
|
|
@@ -33,6 +36,7 @@ self.update = async (req, resp) => {
|
|
|
33
36
|
resp.status(400).send({ error: error.message });
|
|
34
37
|
}
|
|
35
38
|
};
|
|
39
|
+
|
|
36
40
|
self.status = async (req, resp) => {
|
|
37
41
|
try {
|
|
38
42
|
const _id = req.params.LOG_ID;
|
|
@@ -46,43 +50,44 @@ self.status = async (req, resp) => {
|
|
|
46
50
|
resp.status(400).send({ error: error.message });
|
|
47
51
|
}
|
|
48
52
|
};
|
|
53
|
+
|
|
49
54
|
self.retrieve = async (req, res) => {
|
|
50
55
|
try {
|
|
51
56
|
const companyId =
|
|
52
57
|
req.header("Company") !== "undefined" ? req.header("Company") : null;
|
|
53
|
-
let query = { _company: companyId };
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
const query = { _company: companyId };
|
|
60
|
+
|
|
61
|
+
if (req.body.users?.length) {
|
|
62
|
+
query._user = {
|
|
63
|
+
$in: req.body.users.map((id) => new mongoose.Types.ObjectId(id)),
|
|
58
64
|
};
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
console.log(new Date())
|
|
67
|
+
if (req.body.dateStart || req.body.dateEnd) {
|
|
68
|
+
query.createdAt = {};
|
|
69
|
+
if (req.body.dateStart) query.createdAt.$gte = Number(req.body.dateStart);
|
|
70
|
+
if (req.body.dateEnd) query.createdAt.$lte = Number(req.body.dateEnd);
|
|
71
|
+
}
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
if (req.body.business?.length) {
|
|
74
|
+
query._business = { $in: req.body.business };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const consulta = await Log.find(query).populate("_user", "name lastName email");
|
|
72
78
|
|
|
73
79
|
const response = {
|
|
74
80
|
dataset0: { field: "Visualizaciones totales", count: consulta.length },
|
|
75
|
-
dataset1:
|
|
81
|
+
dataset1: processDataset1(consulta),
|
|
76
82
|
dataset2: processDataset2(consulta),
|
|
77
83
|
dataset3: processDataset3(consulta),
|
|
78
84
|
dataset4: processDataset4(consulta),
|
|
79
|
-
dataset5:
|
|
85
|
+
dataset5: processDataset5(consulta),
|
|
80
86
|
dataset6: processDataset6(consulta),
|
|
81
87
|
dataset7: processDataset7(consulta),
|
|
88
|
+
dataset8: processDataset8(consulta, req.body.search, req.body.page, req.body.limit),
|
|
82
89
|
};
|
|
83
90
|
|
|
84
|
-
console.log(new Date())
|
|
85
|
-
|
|
86
91
|
res.status(200).send(response);
|
|
87
92
|
} catch (error) {
|
|
88
93
|
console.error(error);
|
|
@@ -90,35 +95,23 @@ self.retrieve = async (req, res) => {
|
|
|
90
95
|
}
|
|
91
96
|
};
|
|
92
97
|
|
|
93
|
-
function formatDate(
|
|
94
|
-
const day =
|
|
98
|
+
function formatDate(isoDate) {
|
|
99
|
+
const [year, month, day] = isoDate.split("-");
|
|
95
100
|
const monthNames = [
|
|
96
|
-
"Ene",
|
|
97
|
-
"
|
|
98
|
-
"Mar",
|
|
99
|
-
"Abr",
|
|
100
|
-
"May",
|
|
101
|
-
"Jun",
|
|
102
|
-
"Jul",
|
|
103
|
-
"Ago",
|
|
104
|
-
"Sep",
|
|
105
|
-
"Oct",
|
|
106
|
-
"Nov",
|
|
107
|
-
"Dic",
|
|
101
|
+
"Ene", "Feb", "Mar", "Abr", "May", "Jun",
|
|
102
|
+
"Jul", "Ago", "Sep", "Oct", "Nov", "Dic",
|
|
108
103
|
];
|
|
109
|
-
|
|
110
|
-
const year = date.getFullYear();
|
|
111
|
-
return `${day} ${month} ${year}`;
|
|
104
|
+
return `${day} ${monthNames[parseInt(month) - 1]} ${year}`;
|
|
112
105
|
}
|
|
106
|
+
|
|
113
107
|
function processDataset1(consulta) {
|
|
114
|
-
return consulta.map((item) => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
108
|
+
return consulta.map((item) => ({
|
|
109
|
+
_id: item._id,
|
|
110
|
+
labelDescription: item.label,
|
|
111
|
+
userName: item._user.name + " " + item._user.lastName,
|
|
112
|
+
userEmail: item._user.email,
|
|
113
|
+
createdAt: item.createdAt,
|
|
114
|
+
}));
|
|
122
115
|
}
|
|
123
116
|
|
|
124
117
|
function processDataset2(consulta) {
|
|
@@ -153,7 +146,8 @@ function processDataset3(consulta) {
|
|
|
153
146
|
|
|
154
147
|
function processDataset4(consulta) {
|
|
155
148
|
const dateCounts = consulta.reduce((acc, item) => {
|
|
156
|
-
const
|
|
149
|
+
const isoDate = new Date(item.createdAt).toISOString().split("T")[0];
|
|
150
|
+
const date = formatDate(isoDate);
|
|
157
151
|
acc[date] = (acc[date] || 0) + 1;
|
|
158
152
|
return acc;
|
|
159
153
|
}, {});
|
|
@@ -170,7 +164,8 @@ function processDataset5(consulta) {
|
|
|
170
164
|
const categories = new Set();
|
|
171
165
|
|
|
172
166
|
consulta.forEach((item) => {
|
|
173
|
-
const
|
|
167
|
+
const isoDate = new Date(item.createdAt).toISOString().split("T")[0];
|
|
168
|
+
const date = formatDate(isoDate);
|
|
174
169
|
const label = item.label;
|
|
175
170
|
categories.add(date);
|
|
176
171
|
|
|
@@ -200,55 +195,80 @@ function processDataset5(consulta) {
|
|
|
200
195
|
function processDataset6(data) {
|
|
201
196
|
const userActivity = {};
|
|
202
197
|
|
|
203
|
-
// Count activity per user. Assuming data contains _user with name and lastName
|
|
204
198
|
data.forEach((item) => {
|
|
205
199
|
const fullName = `${item._user.name} ${item._user.lastName}`;
|
|
206
200
|
userActivity[fullName] = (userActivity[fullName] || 0) + 1;
|
|
207
201
|
});
|
|
208
202
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
(
|
|
212
|
-
);
|
|
203
|
+
const topUsers = Object.entries(userActivity)
|
|
204
|
+
.sort(([, a], [, b]) => b - a)
|
|
205
|
+
.slice(0, 10);
|
|
213
206
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// Build the result object
|
|
218
|
-
const result = {
|
|
207
|
+
return {
|
|
208
|
+
field: "Usuarios con mas actividad en la plataforma",
|
|
219
209
|
counts: topUsers.map(([, count]) => count),
|
|
220
210
|
actionsName: topUsers.map(([fullName]) => fullName.split(" ")),
|
|
221
|
-
field: "Usuarios con mas actividad en la plataforma",
|
|
222
211
|
};
|
|
223
|
-
|
|
224
|
-
return result;
|
|
225
212
|
}
|
|
226
213
|
|
|
227
214
|
function processDataset7(data) {
|
|
228
215
|
const userActivity = {};
|
|
229
216
|
|
|
230
|
-
// Count activity per user. Assuming data contains _user with name and lastName
|
|
231
217
|
data.forEach((item) => {
|
|
232
218
|
const fullName = `${item._user.name} ${item._user.lastName}`;
|
|
233
219
|
userActivity[fullName] = (userActivity[fullName] || 0) + 1;
|
|
234
220
|
});
|
|
235
221
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
(
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
// Extract top 10 least active users
|
|
242
|
-
const leastActiveUsers = sortedUsers.slice(0, 10);
|
|
222
|
+
const leastUsers = Object.entries(userActivity)
|
|
223
|
+
.sort(([, a], [, b]) => a - b)
|
|
224
|
+
.slice(0, 10);
|
|
243
225
|
|
|
244
|
-
|
|
245
|
-
const result = {
|
|
246
|
-
counts: leastActiveUsers.map(([, count]) => count),
|
|
247
|
-
actionsName: leastActiveUsers.map(([fullName]) => fullName.split(" ")),
|
|
226
|
+
return {
|
|
248
227
|
field: "Usuarios con menos actividad en la plataforma",
|
|
228
|
+
counts: leastUsers.map(([, count]) => count),
|
|
229
|
+
actionsName: leastUsers.map(([fullName]) => fullName.split(" ")),
|
|
249
230
|
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function processDataset8(data, search = "", page = 1, limit = 10) {
|
|
234
|
+
const userActivity = {};
|
|
235
|
+
|
|
236
|
+
data.forEach((item) => {
|
|
237
|
+
const fullName = `${item._user.name} ${item._user.lastName}`;
|
|
238
|
+
if (!userActivity[fullName]) {
|
|
239
|
+
userActivity[fullName] = {
|
|
240
|
+
name: item._user.name,
|
|
241
|
+
lastName: item._user.lastName,
|
|
242
|
+
email: item._user.email,
|
|
243
|
+
count: 0,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
userActivity[fullName].count++;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
let users = Object.values(userActivity).sort((a, b) => b.count - a.count);
|
|
250
|
+
|
|
251
|
+
if (search) {
|
|
252
|
+
const s = search.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
253
|
+
users = users.filter((u) => {
|
|
254
|
+
const full = `${u.name} ${u.lastName} ${u.email}`.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
255
|
+
return full.includes(s);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
250
258
|
|
|
251
|
-
|
|
259
|
+
const total = users.length;
|
|
260
|
+
const totalPages = Math.ceil(total / limit);
|
|
261
|
+
const start = (page - 1) * limit;
|
|
262
|
+
const items = users.slice(start, start + limit);
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
field: "Actividad de usuarios",
|
|
266
|
+
total,
|
|
267
|
+
page,
|
|
268
|
+
limit,
|
|
269
|
+
totalPages,
|
|
270
|
+
items,
|
|
271
|
+
};
|
|
252
272
|
}
|
|
253
273
|
|
|
254
274
|
self.get = async (req, res) => {
|
|
@@ -281,4 +301,4 @@ self.count = async (req, res) => {
|
|
|
281
301
|
} catch (error) {
|
|
282
302
|
res.status(400).send({ error: error.message });
|
|
283
303
|
}
|
|
284
|
-
};
|
|
304
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const Totp = require("../services/totp");
|
|
2
|
+
const utils = require("../config/utils");
|
|
3
|
+
|
|
4
|
+
const self = module.exports;
|
|
5
|
+
|
|
6
|
+
self.setup = async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const tempToken = req.query.tempToken || req.body?.tempToken;
|
|
9
|
+
const response = await Totp.setup(tempToken);
|
|
10
|
+
res.status(200).send(response);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
await utils.responseError(res, error);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
self.activate = async (req, res) => {
|
|
17
|
+
try {
|
|
18
|
+
const tempToken = req.headers["x-temp-token"] || req.body?.tempToken;
|
|
19
|
+
const response = await Totp.activate(tempToken, req.body.token);
|
|
20
|
+
res.status(200).send(response);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
await utils.responseError(res, error);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
self.checkLogin = async (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
const { token, tempToken } = req.body;
|
|
29
|
+
if (!token || !tempToken)
|
|
30
|
+
return res.status(400).send({ message: "Faltan parámetros" });
|
|
31
|
+
|
|
32
|
+
const response = await Totp.checkLogin(token, tempToken, res);
|
|
33
|
+
res.status(200).send(response);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
await utils.responseError(res, error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
self.adminToggle = async (req, res) => {
|
|
40
|
+
try {
|
|
41
|
+
const response = await Totp.adminToggle(req.params.USER_ID, req.body.enabled);
|
|
42
|
+
res.status(200).send(response);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
await utils.responseError(res, error);
|
|
45
|
+
}
|
|
46
|
+
};
|