@runnerpro/backend 1.10.18 → 1.11.2
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.
|
@@ -54,10 +54,10 @@ const conversationRoute = (_a) => {
|
|
|
54
54
|
router.post('/conversation/read', (req, res, next) => readMessage(req, res, params).catch((error) => (0, index_1.err)(req, res, error, next)));
|
|
55
55
|
};
|
|
56
56
|
exports.conversationRoute = conversationRoute;
|
|
57
|
-
const getConversation = (req, res, {
|
|
57
|
+
const getConversation = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
58
|
const idCliente = isClient ? req.session.userid : req.query.id;
|
|
59
|
-
const [header] = yield query('SELECT [NAME], [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
60
|
-
let messages = yield query(`SELECT [CHAT MESSAGE].*,
|
|
59
|
+
const [header] = yield (0, index_1.query)('SELECT [NAME], [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
60
|
+
let messages = yield (0, index_1.query)(`SELECT [CHAT MESSAGE].*,
|
|
61
61
|
[WORKOUT].[DATE] AS [WORKOUT DATE], [WORKOUT].[TYPE] AS [WORKOUT TYPE], [WORKOUT].[TITLE] AS [WORKOUT TITLE], [WORKOUT].[TITLE PREFERRED LANGUAGE] AS [WORKOUT TITLE],
|
|
62
62
|
[WORKOUT].[DURATION] AS [WORKOUT DURATION], [WORKOUT].[DISTANCE] AS [WORKOUT DISTANCE],
|
|
63
63
|
[WORKOUT].[PHOTO URL SHARE] AS [WORKOUT PHOTO URL SHARE], [WORKOUT].[PHOTO URL] AS [WORKOUT PHOTO URL], [FEELINGS], [FEELINGS DESCRIPTION]
|
|
@@ -89,36 +89,35 @@ const getConversation = (req, res, { query, isClient }) => __awaiter(void 0, voi
|
|
|
89
89
|
res.send({ header, messages });
|
|
90
90
|
// Solo se marca como leído si es el cliente | El entrenador tiene el botón o enviar mensaje para marcar como leído
|
|
91
91
|
if (isClient)
|
|
92
|
-
yield markReadMessage({ isClient,
|
|
92
|
+
yield markReadMessage({ isClient, idCliente });
|
|
93
93
|
});
|
|
94
|
-
const deleteConversationMessage = (req, res, {
|
|
94
|
+
const deleteConversationMessage = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
95
|
const { id } = req.params;
|
|
96
96
|
if (!(yield canEditOrDeleteMessage({ idMessage: id, isClient, userid: req.session.userid })))
|
|
97
97
|
return res.send({ status: 'ok' });
|
|
98
98
|
if (isClient)
|
|
99
|
-
yield query('UPDATE [CHAT MESSAGE] SET [ELIMINADO] = TRUE WHERE [ID] = ?', [id]);
|
|
99
|
+
yield (0, index_1.query)('UPDATE [CHAT MESSAGE] SET [ELIMINADO] = TRUE WHERE [ID] = ?', [id]);
|
|
100
100
|
else
|
|
101
|
-
yield query('DELETE FROM [CHAT MESSAGE] WHERE [ID] = ?', [id]);
|
|
101
|
+
yield (0, index_1.query)('DELETE FROM [CHAT MESSAGE] WHERE [ID] = ?', [id]);
|
|
102
102
|
res.send({ status: 'ok' });
|
|
103
103
|
});
|
|
104
104
|
// TODO: Si el cliente elimina o edita y ya se ha sugerido el mensaje
|
|
105
105
|
// - Se elimina la sugerencia
|
|
106
106
|
// - Se elimina el mensaje programado
|
|
107
107
|
// TODO: Comprobar que el cliente/entrenador puede editar/eliminar el mensaje (no se haya contestado ya y que no haya pasado el tiempo de cortesía)
|
|
108
|
-
const editConversationMessage = (req, res, {
|
|
108
|
+
const editConversationMessage = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
109
|
const { id } = req.params;
|
|
110
110
|
const { text } = req.body;
|
|
111
111
|
if (!(yield canEditOrDeleteMessage({ idMessage: id, isClient, userid: req.session.userid })))
|
|
112
112
|
return res.send({ status: 'ok' });
|
|
113
|
-
const [message] = yield query('SELECT [ID CLIENTE] FROM [CHAT MESSAGE] WHERE [ID] = ?', [id]);
|
|
113
|
+
const [message] = yield (0, index_1.query)('SELECT [ID CLIENTE] FROM [CHAT MESSAGE] WHERE [ID] = ?', [id]);
|
|
114
114
|
// Devuelve el texto en el otro idioma si el cliente no habla español y el idioma del cliente
|
|
115
115
|
const { textSpanish, textPreferredLanguage } = yield getPreferredLanguageForChat({
|
|
116
116
|
text,
|
|
117
117
|
idCliente: message.idCliente,
|
|
118
118
|
isClient,
|
|
119
|
-
query,
|
|
120
119
|
});
|
|
121
|
-
yield query('UPDATE [CHAT MESSAGE] SET [TEXT] = ?, [TEXT PREFERRED LANGUAGE] = ?, [EDITADO] = TRUE WHERE [ID] = ?', [
|
|
120
|
+
yield (0, index_1.query)('UPDATE [CHAT MESSAGE] SET [TEXT] = ?, [TEXT PREFERRED LANGUAGE] = ?, [EDITADO] = TRUE WHERE [ID] = ?', [
|
|
122
121
|
textSpanish,
|
|
123
122
|
textPreferredLanguage,
|
|
124
123
|
id,
|
|
@@ -146,9 +145,8 @@ const canEditOrDeleteMessage = ({ idMessage, isClient, userid }) => __awaiter(vo
|
|
|
146
145
|
return false;
|
|
147
146
|
return true;
|
|
148
147
|
});
|
|
149
|
-
const getConversationImage = (req, res, {
|
|
148
|
+
const getConversationImage = (req, res, { bucket, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
149
|
const result = yield getChatFile({
|
|
151
|
-
query,
|
|
152
150
|
bucket,
|
|
153
151
|
id: req.params.id,
|
|
154
152
|
isClient,
|
|
@@ -163,9 +161,8 @@ const getConversationImage = (req, res, { query, bucket, isClient }) => __awaite
|
|
|
163
161
|
mimetype: result.message.mimetype,
|
|
164
162
|
});
|
|
165
163
|
});
|
|
166
|
-
const getConversationFile = (req, res, {
|
|
164
|
+
const getConversationFile = (req, res, { bucket, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
167
165
|
const result = yield getChatFile({
|
|
168
|
-
query,
|
|
169
166
|
bucket,
|
|
170
167
|
id: req.params.id,
|
|
171
168
|
isClient,
|
|
@@ -180,9 +177,9 @@ const getConversationFile = (req, res, { query, bucket, isClient }) => __awaiter
|
|
|
180
177
|
});
|
|
181
178
|
res.end(result.file);
|
|
182
179
|
});
|
|
183
|
-
const getChatFile = ({
|
|
180
|
+
const getChatFile = ({ bucket, id, isClient, userid }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
184
181
|
const idBBDD = id.includes('-original') ? id.replace('-original', '') : id;
|
|
185
|
-
const [message] = yield query('SELECT [MIMETYPE], [TEXT] FROM [CHAT MESSAGE] WHERE [ID] = ? AND (? = FALSE OR [ID CLIENTE] = ?)', [
|
|
182
|
+
const [message] = yield (0, index_1.query)('SELECT [MIMETYPE], [TEXT] FROM [CHAT MESSAGE] WHERE [ID] = ? AND (? = FALSE OR [ID CLIENTE] = ?)', [
|
|
186
183
|
idBBDD,
|
|
187
184
|
isClient,
|
|
188
185
|
userid,
|
|
@@ -197,21 +194,20 @@ const getChatFile = ({ query, bucket, id, isClient, userid }) => __awaiter(void
|
|
|
197
194
|
return null;
|
|
198
195
|
}
|
|
199
196
|
});
|
|
200
|
-
const sendMessage = (req, res, { sendNotification, firebaseMessaging,
|
|
197
|
+
const sendMessage = (req, res, { sendNotification, firebaseMessaging, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
201
198
|
const { text, replyMessageId } = req.body;
|
|
202
199
|
const { userid } = req.session;
|
|
203
200
|
const idCliente = isClient ? req.session.userid : req.body.idCliente;
|
|
204
201
|
// Si es entrenador, se marca leído cuando se envía un mensaje
|
|
205
202
|
if (!isClient)
|
|
206
|
-
yield markReadMessage({ isClient,
|
|
203
|
+
yield markReadMessage({ isClient, idCliente });
|
|
207
204
|
// Devuelve el texto en el otro idioma si el cliente no habla español y el idioma del cliente
|
|
208
205
|
const { textSpanish, textPreferredLanguage, preferredLanguage } = yield getPreferredLanguageForChat({
|
|
209
206
|
text,
|
|
210
207
|
idCliente,
|
|
211
208
|
isClient,
|
|
212
|
-
query,
|
|
213
209
|
});
|
|
214
|
-
const [message] = yield query('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [TEXT PREFERRED LANGUAGE], [PREFERRED LANGUAGE], [REPLY MESSAGE ID], [TYPE]) VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, textSpanish, textPreferredLanguage, preferredLanguage, replyMessageId, 1]);
|
|
210
|
+
const [message] = yield (0, index_1.query)('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [TEXT PREFERRED LANGUAGE], [PREFERRED LANGUAGE], [REPLY MESSAGE ID], [TYPE]) VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, textSpanish, textPreferredLanguage, preferredLanguage, replyMessageId, 1]);
|
|
215
211
|
res.send({ idMessage: message.id });
|
|
216
212
|
if (!isClient) {
|
|
217
213
|
sendNotification({
|
|
@@ -221,7 +217,7 @@ const sendMessage = (req, res, { sendNotification, firebaseMessaging, query, isC
|
|
|
221
217
|
screen: common_1.NOTIFICATION_SCREEN_TYPES.CHAT,
|
|
222
218
|
});
|
|
223
219
|
// Enviar a N8N lo que ha escrito el entrenador
|
|
224
|
-
const [lastSuggestionMsg] = yield query('SELECT [ID] FROM [CHAT MESSAGE] WHERE [ID CLIENTE] = ? AND [SUGGESTION TEXT] IS NOT NULL ORDER BY [ID] DESC LIMIT 1', [idCliente]);
|
|
220
|
+
const [lastSuggestionMsg] = yield (0, index_1.query)('SELECT [ID] FROM [CHAT MESSAGE] WHERE [ID CLIENTE] = ? AND [SUGGESTION TEXT] IS NOT NULL ORDER BY [ID] DESC LIMIT 1', [idCliente]);
|
|
225
221
|
if (lastSuggestionMsg) {
|
|
226
222
|
yield axios_1.default.put(`${process.env.N8N_URL}/edc2484f-7010-44c1-8c1d-82924496a2eb`, {
|
|
227
223
|
id: lastSuggestionMsg.id,
|
|
@@ -230,8 +226,8 @@ const sendMessage = (req, res, { sendNotification, firebaseMessaging, query, isC
|
|
|
230
226
|
}
|
|
231
227
|
}
|
|
232
228
|
});
|
|
233
|
-
const getPreferredLanguageForChat = ({ text, idCliente, isClient
|
|
234
|
-
const [{ preferredLanguage }] = yield query('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
229
|
+
const getPreferredLanguageForChat = ({ text, idCliente, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
230
|
+
const [{ preferredLanguage }] = yield (0, index_1.query)('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
235
231
|
if (preferredLanguage === common_1.LANGUAGES.ES)
|
|
236
232
|
return {
|
|
237
233
|
textSpanish: text,
|
|
@@ -248,10 +244,10 @@ const getPreferredLanguageForChat = ({ text, idCliente, isClient, query }) => __
|
|
|
248
244
|
preferredLanguage: preferredLanguage,
|
|
249
245
|
};
|
|
250
246
|
});
|
|
251
|
-
const sendFile = (req, res, { sendNotification, firebaseMessaging,
|
|
247
|
+
const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, bucket }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
252
248
|
const { idCliente, type, duration } = req.body;
|
|
253
249
|
const { userid } = req.session;
|
|
254
|
-
const [{ id: idFile }] = yield query('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [MIMETYPE], [DURATION], [TYPE]) VALUES (?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, req.file.originalname, req.file.mimetype, duration || null, type || 2]);
|
|
250
|
+
const [{ id: idFile }] = yield (0, index_1.query)('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [MIMETYPE], [DURATION], [TYPE]) VALUES (?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, req.file.originalname, req.file.mimetype, duration || null, type || 2]);
|
|
255
251
|
const filePath = path_1.default.join('./uploads', req.file.filename);
|
|
256
252
|
const fileData = fs_1.default.readFileSync(filePath);
|
|
257
253
|
const files = [];
|
|
@@ -274,7 +270,7 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, query, isClie
|
|
|
274
270
|
}
|
|
275
271
|
fs_1.default.unlinkSync(filePath);
|
|
276
272
|
if (!isClient) {
|
|
277
|
-
const [cliente] = yield query('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
273
|
+
const [cliente] = yield (0, index_1.query)('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
278
274
|
sendNotification({
|
|
279
275
|
firebaseMessaging,
|
|
280
276
|
idCliente,
|
|
@@ -284,14 +280,14 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, query, isClie
|
|
|
284
280
|
}
|
|
285
281
|
res.send({ idFile });
|
|
286
282
|
});
|
|
287
|
-
const readMessage = (req, res, {
|
|
283
|
+
const readMessage = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
288
284
|
const { idCliente } = req.body;
|
|
289
|
-
yield markReadMessage({ isClient,
|
|
285
|
+
yield markReadMessage({ isClient, idCliente });
|
|
290
286
|
res.send({ status: 'ok' });
|
|
291
287
|
});
|
|
292
|
-
const markReadMessage = ({ isClient,
|
|
288
|
+
const markReadMessage = ({ isClient, idCliente }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
293
289
|
const conditionSender = isClient ? ' AND [ID SENDER] != ?' : ' AND ([ID SENDER] = ? OR [ID SENDER] IS NULL)';
|
|
294
|
-
yield query('UPDATE [CHAT MESSAGE] SET [READ] = TRUE WHERE [ID CLIENTE] = ? AND [READ] = FALSE ' + conditionSender, [idCliente, idCliente]);
|
|
290
|
+
yield (0, index_1.query)('UPDATE [CHAT MESSAGE] SET [READ] = TRUE WHERE [ID CLIENTE] = ? AND [READ] = FALSE ' + conditionSender, [idCliente, idCliente]);
|
|
295
291
|
if (!isClient)
|
|
296
292
|
yield (0, saveResponseTime_1.saveResponseTime)(idCliente);
|
|
297
293
|
});
|
|
@@ -140,18 +140,72 @@ const writeSheet = ({ sheetInstance, sheetName, sheetPage, cellValue, cellPositi
|
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
142
|
exports.writeSheet = writeSheet;
|
|
143
|
+
// Función para detectar si un valor es una fecha en formato DD/MM/YYYY o YYYY/MM/DD
|
|
144
|
+
const isDateString = (value) => {
|
|
145
|
+
if (typeof value !== 'string')
|
|
146
|
+
return false;
|
|
147
|
+
// Patrones para DD/MM/YYYY y YYYY/MM/DD
|
|
148
|
+
const datePatterns = [
|
|
149
|
+
/^\d{1,2}\/\d{1,2}\/\d{4}$/, // DD/MM/YYYY o D/M/YYYY
|
|
150
|
+
/^\d{4}\/\d{1,2}\/\d{1,2}$/, // YYYY/MM/DD o YYYY/M/D
|
|
151
|
+
];
|
|
152
|
+
return datePatterns.some((pattern) => pattern.test(value));
|
|
153
|
+
};
|
|
154
|
+
// Función para convertir fecha a formato que Google Sheets reconozca
|
|
155
|
+
const formatDateForGoogleSheets = (dateString) => {
|
|
156
|
+
if (!isDateString(dateString))
|
|
157
|
+
return dateString;
|
|
158
|
+
try {
|
|
159
|
+
let day, month, year;
|
|
160
|
+
// Detectar si es formato DD/MM/YYYY o YYYY/MM/DD
|
|
161
|
+
const parts = dateString.split('/');
|
|
162
|
+
if (parts[0].length === 4) {
|
|
163
|
+
// Formato YYYY/MM/DD
|
|
164
|
+
year = parseInt(parts[0]);
|
|
165
|
+
month = parseInt(parts[1]);
|
|
166
|
+
day = parseInt(parts[2]);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Formato DD/MM/YYYY
|
|
170
|
+
day = parseInt(parts[0]);
|
|
171
|
+
month = parseInt(parts[1]);
|
|
172
|
+
year = parseInt(parts[2]);
|
|
173
|
+
}
|
|
174
|
+
// Validar que sea una fecha válida
|
|
175
|
+
const date = new Date(year, month - 1, day);
|
|
176
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
177
|
+
return dateString; // Si no es válida, devolver el valor original
|
|
178
|
+
}
|
|
179
|
+
// Formatear para Google Sheets (MM/DD/YYYY es el formato más compatible)
|
|
180
|
+
return `${month.toString().padStart(2, '0')}/${day.toString().padStart(2, '0')}/${year}`;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return dateString; // Si hay error, devolver el valor original
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
// Función para procesar array de valores y formatear fechas
|
|
187
|
+
const processValuesForGoogleSheets = (values) => {
|
|
188
|
+
return values.map((value) => {
|
|
189
|
+
// if (typeof value === 'string' && isDateString(value)) {
|
|
190
|
+
// return formatDateForGoogleSheets(value);
|
|
191
|
+
// }
|
|
192
|
+
return value;
|
|
193
|
+
});
|
|
194
|
+
};
|
|
143
195
|
const appendSheet = ({ sheetInstance, sheetName, sheetPage, cellValues, cellPositionAppend }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
144
196
|
try {
|
|
145
197
|
if (!sheetInstance)
|
|
146
198
|
sheetInstance = yield getSheetInstance();
|
|
199
|
+
// Procesar los valores para formatear fechas automáticamente
|
|
200
|
+
const processedValues = processValuesForGoogleSheets(cellValues);
|
|
147
201
|
yield sheetInstance.spreadsheets.values.append({
|
|
148
202
|
auth: googleAuth,
|
|
149
203
|
spreadsheetId: googleSheeIds[sheetName],
|
|
150
204
|
range: `${sheetPage}!${cellPositionAppend}`,
|
|
151
|
-
valueInputOption: '
|
|
205
|
+
valueInputOption: 'USER_ENTERED',
|
|
152
206
|
insertDataOption: 'INSERT_ROWS',
|
|
153
207
|
resource: {
|
|
154
|
-
values: [
|
|
208
|
+
values: [processedValues],
|
|
155
209
|
},
|
|
156
210
|
});
|
|
157
211
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../../../src/chat/api/conversation.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,iBAAiB,0BAA2B,GAAG,SAoBpD,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../../../src/chat/api/conversation.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,iBAAiB,0BAA2B,GAAG,SAoBpD,CAAC;AA2SF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/googleSheet/index.ts"],"names":[],"mappings":"AA6BA,iBAAe,SAAS,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE;;;;;;CAAA,gBAgBnG;AAED,QAAA,MAAM,eAAe;;;;;;;;;0BAiCpB,CAAC;AAGF,iBAAS,SAAS,CAAC,MAAM,KAAA,UAaxB;AAED,iBAAS,iBAAiB,CAAC,MAAM,KAAA,UAOhC;AAED,QAAA,MAAM,UAAU;;;;;;mBAkBf,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/googleSheet/index.ts"],"names":[],"mappings":"AA6BA,iBAAe,SAAS,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE;;;;;;CAAA,gBAgBnG;AAED,QAAA,MAAM,eAAe;;;;;;;;;0BAiCpB,CAAC;AAGF,iBAAS,SAAS,CAAC,MAAM,KAAA,UAaxB;AAED,iBAAS,iBAAiB,CAAC,MAAM,KAAA,UAOhC;AAED,QAAA,MAAM,UAAU;;;;;;mBAkBf,CAAC;AA4DF,QAAA,MAAM,WAAW;;;;;;mBAsBhB,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC"}
|