@runnerpro/backend 1.10.18 → 1.11.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.
@@ -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, { query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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, query, idCliente });
92
+ yield markReadMessage({ isClient, idCliente });
93
93
  });
94
- const deleteConversationMessage = (req, res, { query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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, { query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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, { query, bucket, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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, { query, bucket, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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 = ({ query, bucket, id, isClient, userid }) => __awaiter(void 0, void 0, void 0, function* () {
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, query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
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, query, idCliente });
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, query }) => __awaiter(void 0, void 0, void 0, function* () {
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, query, isClient, bucket }) => __awaiter(void 0, void 0, void 0, function* () {
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, { query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
283
+ const readMessage = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
288
284
  const { idCliente } = req.body;
289
- yield markReadMessage({ isClient, query, idCliente });
285
+ yield markReadMessage({ isClient, idCliente });
290
286
  res.send({ status: 'ok' });
291
287
  });
292
- const markReadMessage = ({ isClient, query, idCliente }) => __awaiter(void 0, void 0, void 0, function* () {
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: 'RAW',
205
+ valueInputOption: 'USER_ENTERED', // Cambiado de 'RAW' a 'USER_ENTERED' para que Google Sheets interprete fechas
152
206
  insertDataOption: 'INSERT_ROWS',
153
207
  resource: {
154
- values: [cellValues],
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;AA+SF,OAAO,EAAE,iBAAiB,EAAE,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;AAEF,QAAA,MAAM,WAAW;;;;;;mBAmBhB,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runnerpro/backend",
3
- "version": "1.10.18",
3
+ "version": "1.11.1",
4
4
  "description": "A collection of common backend functions",
5
5
  "exports": {
6
6
  ".": "./lib/cjs/index.js"