@runnerpro/backend 1.6.8 → 1.6.10

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.
@@ -55,13 +55,13 @@ exports.conversationRoute = conversationRoute;
55
55
  const getConversation = (req, res, { query, isClient }) => __awaiter(void 0, void 0, void 0, function* () {
56
56
  const idCliente = isClient ? req.session.userid : req.query.id;
57
57
  const [header] = yield query('SELECT [NAME], [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
58
- let messages = yield query(`SELECT [CHAT MESSAGE].*,
59
- [WORKOUT].[DATE] AS [WORKOUT DATE], [WORKOUT].[TYPE] AS [WORKOUT TYPE], [WORKOUT].[TITLE] AS [WORKOUT TITLE],
60
- [WORKOUT].[PHOTO URL SHARE] AS [WORKOUT PHOTO URL SHARE], [FEELINGS], [FEELINGS DESCRIPTION]
61
- FROM [CHAT MESSAGE]
62
- LEFT JOIN [WORKOUT] ON [WORKOUT].[ID] = [CHAT MESSAGE].[ID WORKOUT]
63
- WHERE [CHAT MESSAGE].[ID CLIENTE] = ? AND (${isClient} = FALSE OR [CHAT MESSAGE].[SHOW CLIENT] = TRUE)
64
- ORDER BY [CHAT MESSAGE].[DATE] DESC
58
+ let messages = yield query(`SELECT [CHAT MESSAGE].*,
59
+ [WORKOUT].[DATE] AS [WORKOUT DATE], [WORKOUT].[TYPE] AS [WORKOUT TYPE], [WORKOUT].[TITLE] AS [WORKOUT TITLE],
60
+ [WORKOUT].[PHOTO URL SHARE] AS [WORKOUT PHOTO URL SHARE], [FEELINGS], [FEELINGS DESCRIPTION]
61
+ FROM [CHAT MESSAGE]
62
+ LEFT JOIN [WORKOUT] ON [WORKOUT].[ID] = [CHAT MESSAGE].[ID WORKOUT]
63
+ WHERE [CHAT MESSAGE].[ID CLIENTE] = ? AND (${isClient} = FALSE OR [CHAT MESSAGE].[SHOW CLIENT] = TRUE)
64
+ ORDER BY [CHAT MESSAGE].[DATE] DESC
65
65
  LIMIT 100`, [idCliente]);
66
66
  messages = messages.reverse();
67
67
  // Si el cliente no habla español, se muestran los mensajes en el idioma del cliente. El entrenador siempre ve los mensajes en español que están en la columna [TEXT]
@@ -300,11 +300,11 @@ const saveResponseTime = ({ query, isClient, idCliente }) => __awaiter(void 0, v
300
300
  let firstNotReadMessage;
301
301
  // eslint-disable-next-line no-constant-condition
302
302
  while (true) {
303
- const [lastMessage] = yield query(`
304
- SELECT * FROM [CHAT MESSAGE]
305
- WHERE [ID CLIENTE] = ? AND [ID] < ?
306
- ORDER BY [DATE] DESC
307
- LIMIT 1
303
+ const [lastMessage] = yield query(`
304
+ SELECT * FROM [CHAT MESSAGE]
305
+ WHERE [ID CLIENTE] = ? AND [ID] < ?
306
+ ORDER BY [DATE] DESC
307
+ LIMIT 1
308
308
  `, [idCliente, (lastNotReadMessage === null || lastNotReadMessage === void 0 ? void 0 : lastNotReadMessage.id) || 2147483646]);
309
309
  // Si no hay más mensajes || el mensaje no es del cliente || ya tiene tiempo de respuesta => salimos del bucle
310
310
  if (!lastMessage || (lastMessage.idSender && lastMessage.idCliente !== lastMessage.idSender) || lastMessage.tiempoRespuesta)
@@ -32,18 +32,18 @@ const getList = (req, res, { query, isClient }) => __awaiter(void 0, void 0, voi
32
32
  else {
33
33
  const { page } = req.query;
34
34
  const limit = 20;
35
- const list = yield query(`
36
- SELECT [C].[ID], [C].[NAME],
37
- [CM].[DATE], [CM].[TEXT],
38
- CASE WHEN [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE] THEN 0
39
- ELSE 1 END AS [READ]
40
- FROM [CLIENTE] AS [C]
41
- LEFT JOIN (
42
- SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
43
- FROM [CHAT MESSAGE]
44
- ) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
45
- ORDER BY CASE WHEN [CM].[DATE] IS NULL THEN 1 ELSE 0 END, [CM].[DATE] DESC
46
- LIMIT ? OFFSET ?
35
+ const list = yield query(`
36
+ SELECT [C].[ID], [C].[NAME],
37
+ [CM].[DATE], [CM].[TEXT],
38
+ CASE WHEN [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE] THEN 0
39
+ ELSE 1 END AS [READ]
40
+ FROM [CLIENTE] AS [C]
41
+ LEFT JOIN (
42
+ SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
43
+ FROM [CHAT MESSAGE]
44
+ ) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
45
+ ORDER BY CASE WHEN [CM].[DATE] IS NULL THEN 1 ELSE 0 END, [CM].[DATE] DESC
46
+ LIMIT ? OFFSET ?
47
47
  `, [limit, limit * page]);
48
48
  res.send(list);
49
49
  }
@@ -12,22 +12,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getCountNotificaciones = void 0;
13
13
  const getCountNotificaciones = ({ query, isClient, idClient }) => __awaiter(void 0, void 0, void 0, function* () {
14
14
  if (isClient) {
15
- const [{ chat }] = yield query(`
16
- SELECT COUNT([ID]) AS [CHAT]
17
- FROM [CHAT MESSAGE]
18
- WHERE [ID CLIENTE] = ? AND [READ] = FALSE AND [ID SENDER] != [ID CLIENTE]
15
+ const [{ chat }] = yield query(`
16
+ SELECT COUNT([ID]) AS [CHAT]
17
+ FROM [CHAT MESSAGE]
18
+ WHERE [ID CLIENTE] = ? AND [READ] = FALSE AND [ID SENDER] != [ID CLIENTE]
19
19
  `, [idClient]);
20
20
  return chat;
21
21
  }
22
22
  else {
23
- const [{ chat }] = yield query(`
24
- SELECT COUNT([C].[ID]) AS [CHAT]
25
- FROM [CLIENTE] AS [C]
26
- LEFT JOIN (
27
- SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
28
- FROM [CHAT MESSAGE]
29
- ) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
30
- WHERE [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE]
23
+ const [{ chat }] = yield query(`
24
+ SELECT COUNT([C].[ID]) AS [CHAT]
25
+ FROM [CLIENTE] AS [C]
26
+ LEFT JOIN (
27
+ SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
28
+ FROM [CHAT MESSAGE]
29
+ ) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
30
+ WHERE [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE]
31
31
  `);
32
32
  return chat;
33
33
  }
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.toPgArray = exports.batchQuery = exports.query = void 0;
15
+ exports.pool = exports.toPgArray = exports.batchQuery = exports.query = void 0;
16
16
  const pg_1 = __importDefault(require("pg"));
17
17
  const { Pool } = pg_1.default;
18
18
  const pool = new Pool({
@@ -22,6 +22,7 @@ const pool = new Pool({
22
22
  host: process.env.DB_HOST,
23
23
  port: 5432,
24
24
  });
25
+ exports.pool = pool;
25
26
  const query = (queryText, values = []) => __awaiter(void 0, void 0, void 0, function* () {
26
27
  const client = yield pool.connect();
27
28
  const text = getParseQuery(queryText, values);
package/lib/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDefaultWorkoutImage = exports.generateShareMap = exports.reduceSizeImage = exports.getLetter = exports.getNumberByLetter = exports.appendSheet = exports.writeSheet = exports.findCellByValue = exports.readSheet = exports.NOTION_DATABASES_ID = exports.notionEditPage = exports.notionAddPage = exports.notionGetDatabase = exports.notionGetUsers = exports.getCountNotificaciones = exports.chatExposed = exports.chatApi = exports.chat = exports.getExerciseTranslatedDescription = exports.useTranslation = exports.LANGUAGES = exports.translate = exports.CHANNEL_SLACK = exports.notifySlack = exports.fetchIA = exports.err = exports.sendMail = exports.toPgArray = exports.batchQuery = exports.query = exports.sleep = exports.sendNotification = void 0;
3
+ exports.sendWorkoutToWatch = exports.getDefaultWorkoutImage = exports.generateShareMap = exports.reduceSizeImage = exports.getLetter = exports.getNumberByLetter = exports.appendSheet = exports.writeSheet = exports.findCellByValue = exports.readSheet = exports.NOTION_DATABASES_ID = exports.notionEditPage = exports.notionAddPage = exports.notionGetDatabase = exports.notionGetUsers = exports.getCountNotificaciones = exports.chatExposed = exports.chatApi = exports.chat = exports.getExerciseTranslatedDescription = exports.useTranslation = exports.LANGUAGES = exports.translate = exports.CHANNEL_SLACK = exports.notifySlack = exports.fetchIA = exports.err = exports.sendMail = exports.pool = exports.toPgArray = exports.batchQuery = exports.query = exports.sleep = exports.sendNotification = void 0;
4
4
  const sendNotification_1 = require("./sendNotification");
5
5
  Object.defineProperty(exports, "sendNotification", { enumerable: true, get: function () { return sendNotification_1.sendNotification; } });
6
6
  const sleep_1 = require("./sleep");
@@ -9,6 +9,7 @@ const db_1 = require("./db");
9
9
  Object.defineProperty(exports, "query", { enumerable: true, get: function () { return db_1.query; } });
10
10
  Object.defineProperty(exports, "batchQuery", { enumerable: true, get: function () { return db_1.batchQuery; } });
11
11
  Object.defineProperty(exports, "toPgArray", { enumerable: true, get: function () { return db_1.toPgArray; } });
12
+ Object.defineProperty(exports, "pool", { enumerable: true, get: function () { return db_1.pool; } });
12
13
  const sendMail_1 = require("./sendMail");
13
14
  Object.defineProperty(exports, "sendMail", { enumerable: true, get: function () { return sendMail_1.sendMail; } });
14
15
  const err_1 = require("./err");
@@ -47,3 +48,5 @@ const generateShareMap_1 = require("./image/generateShareMap");
47
48
  Object.defineProperty(exports, "generateShareMap", { enumerable: true, get: function () { return generateShareMap_1.generateShareMap; } });
48
49
  const getDefaultWorkoutImage_1 = require("./image/getDefaultWorkoutImage");
49
50
  Object.defineProperty(exports, "getDefaultWorkoutImage", { enumerable: true, get: function () { return getDefaultWorkoutImage_1.getDefaultWorkoutImage; } });
51
+ const sendToWatch_1 = require("./workout/sendToWatch");
52
+ Object.defineProperty(exports, "sendWorkoutToWatch", { enumerable: true, get: function () { return sendToWatch_1.sendWorkoutToWatch; } });
@@ -45,72 +45,72 @@ const sendMail = ({ subject, title, body, to, link, attachments, bcc }) => __awa
45
45
  });
46
46
  exports.sendMail = sendMail;
47
47
  function getBodyHTML(title, body, link) {
48
- return `
49
- <html lang="es">
50
- <head>
51
- <meta charset="UTF-8">
52
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
53
- <title>Correo con estilo</title>
54
- <style>
55
- /* Estilos generales */
56
- body {
57
- margin: 0;
58
- padding: 0;
59
- }
60
-
61
- /* Estilos específicos del botón */
62
- .button {
63
- display: inline-block;
64
- padding: 12px 26px;
65
- font-size: 17px;
66
- text-align: center;
67
- text-decoration: none;
68
- background-color: #ea5b1b;
69
- color: #ffffff !important;
70
- margin: 40px 0 20px 0;
71
- font-family: 'Sofia Sans', 'Roboto', sans-serif;
72
- font-weight: bold;
73
- border-radius: 4px;
74
- border: 2px solid #ea5b1b;
75
- }
76
- </style>
77
- </head>
78
- <body style="background: #f0f0f0; padding: 0 0 40px 0">
79
- <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0">
80
- <tr>
81
- <td align="center" style="padding:0;">
82
- <table role="presentation" style="width:100%;border-collapse:collapse;border-spacing:0;text-align:left;">
83
- <tr>
84
- <td align="center" style="padding:5px 0 0 0;background:#ea5b1b;">
85
- <img src="cid:logo" alt="" width="220" style="height:auto;display:block;">
86
- </td>
87
- </tr>
88
- <tr>
89
- <td style="padding:20px 24px 0px 24px; max-width: 600px" align="center">
90
- <h1 style="font-size:22px;text-align:center;margin:16px 0 6px 0;font-family:'Sofia Sans', 'Roboto', sans-serif;font-style: italic">
91
- ${title || ''}
92
- </h1>
93
- <p style="text-align:left;margin:0 0 12px 0;font-size:15px;line-height:24px;font-family:'Sofia Sans', 'Roboto', sans-serif;">
94
- ${body.split('\n').join('<br>')}
95
- </p>
48
+ return `
49
+ <html lang="es">
50
+ <head>
51
+ <meta charset="UTF-8">
52
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
53
+ <title>Correo con estilo</title>
54
+ <style>
55
+ /* Estilos generales */
56
+ body {
57
+ margin: 0;
58
+ padding: 0;
59
+ }
60
+
61
+ /* Estilos específicos del botón */
62
+ .button {
63
+ display: inline-block;
64
+ padding: 12px 26px;
65
+ font-size: 17px;
66
+ text-align: center;
67
+ text-decoration: none;
68
+ background-color: #ea5b1b;
69
+ color: #ffffff !important;
70
+ margin: 40px 0 20px 0;
71
+ font-family: 'Sofia Sans', 'Roboto', sans-serif;
72
+ font-weight: bold;
73
+ border-radius: 4px;
74
+ border: 2px solid #ea5b1b;
75
+ }
76
+ </style>
77
+ </head>
78
+ <body style="background: #f0f0f0; padding: 0 0 40px 0">
79
+ <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0">
80
+ <tr>
81
+ <td align="center" style="padding:0;">
82
+ <table role="presentation" style="width:100%;border-collapse:collapse;border-spacing:0;text-align:left;">
83
+ <tr>
84
+ <td align="center" style="padding:5px 0 0 0;background:#ea5b1b;">
85
+ <img src="cid:logo" alt="" width="220" style="height:auto;display:block;">
86
+ </td>
87
+ </tr>
88
+ <tr>
89
+ <td style="padding:20px 24px 0px 24px; max-width: 600px" align="center">
90
+ <h1 style="font-size:22px;text-align:center;margin:16px 0 6px 0;font-family:'Sofia Sans', 'Roboto', sans-serif;font-style: italic">
91
+ ${title || ''}
92
+ </h1>
93
+ <p style="text-align:left;margin:0 0 12px 0;font-size:15px;line-height:24px;font-family:'Sofia Sans', 'Roboto', sans-serif;">
94
+ ${body.split('\n').join('<br>')}
95
+ </p>
96
96
  ${link
97
- ? `
98
- <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0;">
99
- <tr>
100
- <td align="center" style="padding:0;">
101
- <a href="${link.external ? '' : process.env.FRONTEND_URL}${link.url}" class="button" style="color:white">${link.text}</a>
102
- </td>
103
- </tr>
104
- </table>
97
+ ? `
98
+ <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0;">
99
+ <tr>
100
+ <td align="center" style="padding:0;">
101
+ <a href="${link.external ? '' : process.env.FRONTEND_URL}${link.url}" class="button" style="color:white">${link.text}</a>
102
+ </td>
103
+ </tr>
104
+ </table>
105
105
  `
106
- : ''}
107
- </td>
108
- </tr>
109
- </table>
110
- </td>
111
- </tr>
112
- </table>
113
- </body>
114
- </html>
106
+ : ''}
107
+ </td>
108
+ </tr>
109
+ </table>
110
+ </td>
111
+ </tr>
112
+ </table>
113
+ </body>
114
+ </html>
115
115
  `;
116
116
  }
@@ -1,5 +1,7 @@
1
+ import postgresql from 'pg';
2
+ declare const pool: postgresql.Pool;
1
3
  declare const query: (queryText: string, values?: (string | number | boolean)[]) => Promise<any>;
2
4
  declare const toPgArray: (arr: string[]) => string;
3
5
  declare const batchQuery: (queries: any, length?: number) => Promise<void>;
4
- export { query, batchQuery, toPgArray };
6
+ export { query, batchQuery, toPgArray, pool };
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/db/index.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,KAAK,cAAqB,MAAM,WAAU,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,iBAsB5E,CAAC;AAEF,QAAA,MAAM,SAAS,QAAS,MAAM,EAAE,WAM/B,CAAC;AA+BF,QAAA,MAAM,UAAU,YAAmB,GAAG,mCAUrC,CAAC;AAEF,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,IAAI,CAAC;AAI5B,QAAA,MAAM,IAAI,iBAMR,CAAC;AAEH,QAAA,MAAM,KAAK,cAAqB,MAAM,WAAU,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,iBAsB5E,CAAC;AAEF,QAAA,MAAM,SAAS,QAAS,MAAM,EAAE,WAM/B,CAAC;AA+BF,QAAA,MAAM,UAAU,YAAmB,GAAG,mCAUrC,CAAC;AAEF,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC"}
@@ -1,3 +1,4 @@
1
- declare const generateShareMap: (image: any, idWorkout: any, options: any) => Promise<any>;
1
+ /// <reference types="node" />
2
+ declare const generateShareMap: (image: any, idWorkout: any, options: any) => Promise<Buffer>;
2
3
  export { generateShareMap, };
3
4
  //# sourceMappingURL=generateShareMap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateShareMap.d.ts","sourceRoot":"","sources":["../../../../src/image/generateShareMap.ts"],"names":[],"mappings":"AAcA,QAAA,MAAM,gBAAgB,4DAkBrB,CAAC;AA0HF,OAAO,EACL,gBAAgB,GACjB,CAAC"}
1
+ {"version":3,"file":"generateShareMap.d.ts","sourceRoot":"","sources":["../../../../src/image/generateShareMap.ts"],"names":[],"mappings":";AAcA,QAAA,MAAM,gBAAgB,+DAkBrB,CAAC;AA0HF,OAAO,EACL,gBAAgB,GACjB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { sendNotification } from './sendNotification';
2
2
  import { sleep } from './sleep';
3
- import { query, batchQuery, toPgArray } from './db';
3
+ import { query, batchQuery, toPgArray, pool } from './db';
4
4
  import { sendMail } from './sendMail';
5
5
  import { err } from './err';
6
6
  import { fetchIA } from './fetch/fetchIA';
@@ -12,5 +12,6 @@ import { readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter,
12
12
  import { reduceSizeImage } from './image/reduceSizeImage';
13
13
  import { generateShareMap } from './image/generateShareMap';
14
14
  import { getDefaultWorkoutImage } from './image/getDefaultWorkoutImage';
15
- export { sendNotification, sleep, query, batchQuery, toPgArray, sendMail, err, fetchIA, notifySlack, CHANNEL_SLACK, translate, LANGUAGES, useTranslation, getExerciseTranslatedDescription, chat, chatApi, chatExposed, getCountNotificaciones, notionGetUsers, notionGetDatabase, notionAddPage, notionEditPage, NOTION_DATABASES_ID, readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter, getLetter, reduceSizeImage, generateShareMap, getDefaultWorkoutImage, };
15
+ import { sendWorkoutToWatch } from './workout/sendToWatch';
16
+ export { sendNotification, sleep, query, batchQuery, toPgArray, pool, sendMail, err, fetchIA, notifySlack, CHANNEL_SLACK, translate, LANGUAGES, useTranslation, getExerciseTranslatedDescription, chat, chatApi, chatExposed, getCountNotificaciones, notionGetUsers, notionGetDatabase, notionAddPage, notionEditPage, NOTION_DATABASES_ID, readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter, getLetter, reduceSizeImage, generateShareMap, getDefaultWorkoutImage, sendWorkoutToWatch, };
16
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,OAAO,EACL,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,EACT,QAAQ,EACR,GAAG,EACH,OAAO,EACP,WAAW,EACX,aAAa,EACb,SAAS,EACT,SAAS,EACT,cAAc,EACd,gCAAgC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,sBAAsB,GACvB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EACL,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,OAAO,EACP,WAAW,EACX,aAAa,EACb,SAAS,EACT,SAAS,EACT,cAAc,EACd,gCAAgC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,CAAC"}
@@ -0,0 +1,5 @@
1
+ declare const getStructuraWorkout: (workout: any, estructura: any) => any;
2
+ declare const saveWorkoutEstructuraNotDone: (idWorkout: any, data: any) => Promise<void>;
3
+ declare const savePlantillaEstructuraNotDone: (idPlantilla: any, data: any) => Promise<void>;
4
+ export { getStructuraWorkout, saveWorkoutEstructuraNotDone, savePlantillaEstructuraNotDone };
5
+ //# sourceMappingURL=estructuraWorkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estructuraWorkout.d.ts","sourceRoot":"","sources":["../../../../src/workout/estructuraWorkout.ts"],"names":[],"mappings":"AA2DA,QAAA,MAAM,mBAAmB,wCAiCxB,CAAC;AAmCF,QAAA,MAAM,4BAA4B,8CAkBjC,CAAC;AAEF,QAAA,MAAM,8BAA8B,gDAkBnC,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,8BAA8B,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ declare const createWorkoutGarmin: (userid: any, workout: any) => Promise<{
2
+ workoutGarminId: any;
3
+ workoutGarminOwnerId: any;
4
+ }>;
5
+ declare const updateWorkoutGarmin: (userid: any, workout: any) => Promise<any>;
6
+ declare const deleteWorkoutGarmin: (userid: any, workout: any) => Promise<any>;
7
+ declare const scheduleWorkoutGarmin: (userid: any, workout: any) => Promise<any>;
8
+ declare const updateScheduleWorkoutGarmin: (userid: any, schedule: any, workout: any) => Promise<any>;
9
+ export { createWorkoutGarmin, updateWorkoutGarmin, deleteWorkoutGarmin, scheduleWorkoutGarmin, updateScheduleWorkoutGarmin };
10
+ //# sourceMappingURL=garmin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"garmin.d.ts","sourceRoot":"","sources":["../../../../src/workout/garmin.ts"],"names":[],"mappings":"AAkOA,QAAA,MAAM,mBAAmB;;;EAYxB,CAAC;AAEF,QAAA,MAAM,mBAAmB,6CASxB,CAAC;AAEF,QAAA,MAAM,mBAAmB,6CAMxB,CAAC;AAEF,QAAA,MAAM,qBAAqB,6CAU1B,CAAC;AAEF,QAAA,MAAM,2BAA2B,4DAWhC,CAAC;AAIF,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ declare const sendWorkoutToWatch: (clientId: any, workoutId: any) => Promise<{
2
+ error: string;
3
+ success?: undefined;
4
+ } | {
5
+ success: boolean;
6
+ error?: undefined;
7
+ }>;
8
+ export { sendWorkoutToWatch };
9
+ //# sourceMappingURL=sendToWatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sendToWatch.d.ts","sourceRoot":"","sources":["../../../../src/workout/sendToWatch.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,kBAAkB;;;;;;EAmBvB,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.savePlantillaEstructuraNotDone = exports.saveWorkoutEstructuraNotDone = exports.getStructuraWorkout = void 0;
13
+ const db_1 = require("../db");
14
+ const calculateZone = (values) => {
15
+ const percentage = Number(values.pacePercentage);
16
+ if (percentage <= 70)
17
+ values.zone = 1;
18
+ else if (percentage <= 77.5)
19
+ values.zone = 2;
20
+ else if (percentage <= 87.5)
21
+ values.zone = 3;
22
+ else if (percentage <= 95)
23
+ values.zone = 4;
24
+ else if (percentage <= 100)
25
+ values.zone = 5;
26
+ };
27
+ const parseWorkoutEstructuraNotDone = ({ estructura }) => {
28
+ let idSerie = 0;
29
+ const rows = [];
30
+ estructura.forEach((row) => {
31
+ if (row.number) {
32
+ for (let iNumber = 0; iNumber < Number(row.number); iNumber++) {
33
+ row.steps.forEach((step) => {
34
+ rows.push(Object.assign(Object.assign({}, step), { idSerie, indexSerie: iNumber }));
35
+ });
36
+ }
37
+ idSerie++;
38
+ }
39
+ else {
40
+ rows.push(row);
41
+ }
42
+ });
43
+ return rows;
44
+ };
45
+ const getStructuraWorkout = (workout, estructura) => {
46
+ if (workout.done)
47
+ return estructura;
48
+ else {
49
+ const rows = [];
50
+ for (const s of estructura) {
51
+ if (s.pacePercentage)
52
+ calculateZone(s);
53
+ if (!s.idSerie) {
54
+ rows.push(s);
55
+ }
56
+ else {
57
+ const index = rows.findIndex((r) => r.idSerie && Number(r.idSerie) === Number(s.idSerie));
58
+ if (index !== -1) {
59
+ if (!rows[index].steps)
60
+ rows[index].steps = [];
61
+ rows[index].steps.push(s);
62
+ }
63
+ else {
64
+ rows.push({
65
+ idSerie: s.idSerie,
66
+ steps: [s],
67
+ });
68
+ }
69
+ }
70
+ }
71
+ return rows.map((r) => {
72
+ if (!r.idSerie)
73
+ return r;
74
+ else {
75
+ if (!r.steps)
76
+ return r;
77
+ const filteredSteps = r.steps.filter((s) => Number(s.indexSerie) === 0);
78
+ return {
79
+ steps: filteredSteps,
80
+ number: r.steps.length / filteredSteps.length,
81
+ };
82
+ }
83
+ });
84
+ }
85
+ };
86
+ exports.getStructuraWorkout = getStructuraWorkout;
87
+ const insertWorkoutEstructura = (idWorkout, row, index) => __awaiter(void 0, void 0, void 0, function* () {
88
+ yield (0, db_1.query)(`
89
+ INSERT INTO [WORKOUT STRUCTURE] ([ID WORKOUT], [INDEX], [ID SERIE], [INDEX SERIE], [TYPE], [TYPE METRIC 1],
90
+ [VALUE METRIC 1], [TYPE METRIC 2], [VALUE METRIC 2], [DESNIVEL PLANNED])
91
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
92
+ `, [
93
+ idWorkout,
94
+ index,
95
+ row.idSerie,
96
+ row.indexSerie,
97
+ row.type,
98
+ row.typeMetric1,
99
+ row.valueMetric1,
100
+ row.typeMetric2,
101
+ row.valueMetric2,
102
+ row.desnivelPlanned || null,
103
+ ]);
104
+ });
105
+ const insertPlantillaEstructura = (idPlantilla, row, index) => __awaiter(void 0, void 0, void 0, function* () {
106
+ yield (0, db_1.query)(`
107
+ INSERT INTO [PLANTILLAS WORKOUT STRUCTURE] ([ID WORKOUT], [INDEX], [ID SERIE], [INDEX SERIE], [TYPE], [TYPE METRIC 1],
108
+ [VALUE METRIC 1], [PACE PERCENTAGE], [DESNIVEL PLANNED])
109
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
110
+ `, [idPlantilla, index, row.idSerie, row.indexSerie, row.type, row.typeMetric1, row.valueMetric1, row.pacePercentage, row.desnivelPlanned || null]);
111
+ });
112
+ const saveWorkoutEstructuraNotDone = (idWorkout, data) => __awaiter(void 0, void 0, void 0, function* () {
113
+ const rows = parseWorkoutEstructuraNotDone(data);
114
+ yield (0, db_1.query)('DELETE FROM [WORKOUT STRUCTURE] WHERE [ID WORKOUT] = ?;', [idWorkout]);
115
+ let index = 0;
116
+ for (const row of rows) {
117
+ if (row.number && row.steps) {
118
+ for (let iNumber = 0; iNumber < row.number; iNumber++) {
119
+ for (const step of row.steps) {
120
+ yield insertWorkoutEstructura(idWorkout, step, index);
121
+ index++;
122
+ }
123
+ }
124
+ }
125
+ else {
126
+ yield insertWorkoutEstructura(idWorkout, row, index);
127
+ index++;
128
+ }
129
+ }
130
+ });
131
+ exports.saveWorkoutEstructuraNotDone = saveWorkoutEstructuraNotDone;
132
+ const savePlantillaEstructuraNotDone = (idPlantilla, data) => __awaiter(void 0, void 0, void 0, function* () {
133
+ const rows = parseWorkoutEstructuraNotDone(data);
134
+ yield (0, db_1.query)('DELETE FROM [PLANTILLAS WORKOUT STRUCTURE] WHERE [ID WORKOUT] = ?;', [idPlantilla]);
135
+ let index = 0;
136
+ for (const row of rows) {
137
+ if (row.number && row.steps) {
138
+ for (let iNumber = 0; iNumber < row.number; iNumber++) {
139
+ for (const step of row.steps) {
140
+ yield insertPlantillaEstructura(idPlantilla, step, index);
141
+ index++;
142
+ }
143
+ }
144
+ }
145
+ else {
146
+ yield insertPlantillaEstructura(idPlantilla, row, index);
147
+ index++;
148
+ }
149
+ }
150
+ });
151
+ exports.savePlantillaEstructuraNotDone = savePlantillaEstructuraNotDone;
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.updateScheduleWorkoutGarmin = exports.scheduleWorkoutGarmin = exports.deleteWorkoutGarmin = exports.updateWorkoutGarmin = exports.createWorkoutGarmin = void 0;
16
+ const db_1 = require("../db");
17
+ const common_1 = require("@runnerpro/common");
18
+ const estructuraWorkout_1 = require("./estructuraWorkout");
19
+ const axios_1 = __importDefault(require("axios"));
20
+ const oauth_signature_1 = __importDefault(require("oauth-signature"));
21
+ const garminOauthActivity = ({ url, httpMethod, userid, params = {} }) => __awaiter(void 0, void 0, void 0, function* () {
22
+ const [tokens] = yield (0, db_1.query)(`SELECT * FROM [CLIENTE APLICACIONES GARMIN] WHERE [ID] =
23
+ (SELECT [ID APLICATION] FROM [CLIENTE APLICACIONES] WHERE [ID CLIENTE] = ? AND [TIPO APLICATION] = ?)`, [userid, common_1.TIPO_APLICACION.GARMIN]);
24
+ const nonce = 15456;
25
+ const timestamp = Date.now();
26
+ const method = 'HMAC-SHA1';
27
+ const version = '1.0';
28
+ const parameters = {
29
+ oauth_consumer_key: process.env.GARMIN_CONSUMER_KEY,
30
+ oauth_nonce: nonce,
31
+ oauth_signature_method: method,
32
+ oauth_timestamp: timestamp,
33
+ oauth_token: tokens.accessToken,
34
+ oauth_version: version,
35
+ };
36
+ const encodedSignature = oauth_signature_1.default.generate(httpMethod, url, parameters, process.env.GARMIN_CONSUMER_SECRET, tokens.accessTokenSecret);
37
+ const oauth = [['oauth_signature', encodedSignature], ...Object.entries(parameters)].map(([k, v]) => `${k}="${v}"`).join(', ');
38
+ let data;
39
+ if (httpMethod === 'POST') {
40
+ data = yield axios_1.default.post(url, params, {
41
+ headers: {
42
+ Authorization: `OAuth ${oauth}`,
43
+ Accept: '*/*',
44
+ },
45
+ });
46
+ }
47
+ else if (httpMethod === 'PUT') {
48
+ data = yield axios_1.default.put(url, params, {
49
+ headers: {
50
+ Authorization: `OAuth ${oauth}`,
51
+ Accept: '*/*',
52
+ },
53
+ });
54
+ }
55
+ else if (httpMethod === 'DELETE') {
56
+ data = yield axios_1.default.delete(url, {
57
+ headers: {
58
+ Authorization: `OAuth ${oauth}`,
59
+ Accept: '*/*',
60
+ },
61
+ });
62
+ }
63
+ return data.data;
64
+ });
65
+ const secondsPerKmToMetersPerSecond = (secondsPerKm) => {
66
+ return Math.round((1000 / secondsPerKm) * 100) / 100;
67
+ };
68
+ const typeTranslateWorkoutGarmin = (type) => {
69
+ if (type === common_1.WORKOUT_TYPE.FUERZA)
70
+ return 'STRENGTH_TRAINING';
71
+ if (type === common_1.WORKOUT_TYPE.SWIM)
72
+ return 'LAP_SWIMMING';
73
+ if (type === common_1.WORKOUT_TYPE.BIKE)
74
+ return 'CYCLING';
75
+ if (type === common_1.WORKOUT_TYPE.WALK)
76
+ return 'WALKING';
77
+ else
78
+ return 'RUNNING';
79
+ };
80
+ const intensityTranslateWorkoutGarmin = (intensity) => {
81
+ if (Number(intensity) === Number(common_1.STEP_TYPE.CALENTAMIENTO))
82
+ return 'WARMUP';
83
+ if ([Number(common_1.STEP_TYPE.CORRER), Number(common_1.STEP_TYPE.BICICLETA), Number(common_1.STEP_TYPE.NADAR)].includes(Number(intensity)))
84
+ return 'INTERVAL';
85
+ if (Number(intensity) === Number(common_1.STEP_TYPE.DESCANSO))
86
+ return 'REST';
87
+ if (Number(intensity) === Number(common_1.STEP_TYPE.ENFRIAMIENTO))
88
+ return 'COOLDOWN';
89
+ if (Number(intensity) === Number(common_1.STEP_TYPE.CAMINAR))
90
+ return 'RECOVERY';
91
+ };
92
+ const translateWorkoutGarmin = (workout) => {
93
+ const workoutGarmin = {
94
+ workoutName: workout.titlePreferredLanguage || workout.title,
95
+ description: workout.descriptionPreferredLanguage || workout.description,
96
+ sport: typeTranslateWorkoutGarmin(workout.type),
97
+ workoutProvider: 'RUNNERPRO',
98
+ workoutSourceId: 'RUNNERPRO',
99
+ steps: [],
100
+ };
101
+ if (workout.type === common_1.WORKOUT_TYPE.FUERZA) {
102
+ workoutGarmin.steps.push({
103
+ type: 'WorkoutStep',
104
+ stepOrder: 1,
105
+ intensity: 'ACTIVE',
106
+ durationType: 'OPEN',
107
+ });
108
+ }
109
+ else if (!workout.estructura) {
110
+ if (!workout.distancePlanned || !workout.durationPlanned)
111
+ return null;
112
+ const targetType = getWorkoutGarminTargetType(workout, null);
113
+ const targetValue = getWorkoutGarminTargetValue(workout, null);
114
+ workoutGarmin.steps.push({
115
+ type: 'WorkoutStep',
116
+ stepOrder: 1,
117
+ intensity: 'ACTIVE',
118
+ durationType: 'DISTANCE',
119
+ durationValue: workout.distancePlanned,
120
+ durationValueType: 'METER',
121
+ targetType,
122
+ targetValue: targetValue.value,
123
+ targetValueLow: targetValue.low,
124
+ targetValueHigh: targetValue.high,
125
+ });
126
+ }
127
+ else {
128
+ const estructura = (0, estructuraWorkout_1.getStructuraWorkout)(Object.assign(Object.assign({}, workout), { done: false }), workout.estructura);
129
+ let stepOrder = 0;
130
+ estructura.forEach((row) => {
131
+ stepOrder++;
132
+ if (row.number) {
133
+ workoutGarmin.steps.push({
134
+ type: 'WorkoutRepeatStep',
135
+ stepOrder,
136
+ repeatType: 'REPEAT_UNTIL_STEPS_CMPLT',
137
+ repeatValue: row.number,
138
+ steps: row.steps.map((s) => {
139
+ stepOrder++;
140
+ return getWorkoutGarminStep(workout, s, stepOrder);
141
+ }),
142
+ });
143
+ }
144
+ else {
145
+ workoutGarmin.steps.push(getWorkoutGarminStep(workout, row, stepOrder));
146
+ }
147
+ });
148
+ }
149
+ return workoutGarmin;
150
+ };
151
+ const getWorkoutGarminStep = (workout, row, stepOrder) => {
152
+ const targetType = getWorkoutGarminTargetType(workout, row);
153
+ const targetValue = getWorkoutGarminTargetValue(workout, row);
154
+ return {
155
+ type: 'WorkoutStep',
156
+ stepOrder,
157
+ intensity: intensityTranslateWorkoutGarmin(row.type),
158
+ durationType: Number(row.typeMetric1) === 1 ? 'DISTANCE' : 'TIME',
159
+ durationValue: row.valueMetric1,
160
+ targetType,
161
+ targetValue: targetValue.value,
162
+ targetValueLow: targetValue.low,
163
+ targetValueHigh: targetValue.high,
164
+ };
165
+ };
166
+ const getWorkoutGarminTargetType = (workout, row) => {
167
+ // Si es natación o descanso no tiene tipo
168
+ if (workout.type === common_1.WORKOUT_TYPE.SWIM || (row && Number(row.type) === 3))
169
+ return null;
170
+ // Si es entrenamiento de bicicleta y no tiene estructura o si tiene estructura y el tipo es potencia
171
+ // No se puede añadir potencia ya que el valor que hay que dar es una zona, no absoluto
172
+ // if ((workout.type === WORKOUT_TYPE.BIKE && !row) || (row && Number(row.typeMetric2) === 3)) return 'POWER';
173
+ return 'PACE';
174
+ };
175
+ const getWorkoutGarminTargetValue = (workout, row) => {
176
+ let value;
177
+ if (!row) {
178
+ // Si es entrenamiento de bicicleta y tiene potencia -> value = potencia
179
+ // if (workout.type === WORKOUT_TYPE.BIKE && workout.powerPlanned) {
180
+ // value = Number(workout.powerPlanned);
181
+ // } else {
182
+ // El resto calcular el ritmo
183
+ // No se puede añadir potencia ya que el valor que hay que dar es una zona, no absoluto
184
+ value = Number(workout.distancePlanned) / Number(workout.durationPlanned);
185
+ // }
186
+ }
187
+ else {
188
+ // Si es descanso -> value = null
189
+ if (Number(row.type) === 3)
190
+ value = null;
191
+ // Si es de tipo potencia -> value = valor potencia
192
+ else if (Number(row.typeMetric2) === 3)
193
+ value = Number(row.valueMetric2);
194
+ // El resto de casos se calcula el ritmo
195
+ else
196
+ value = secondsPerKmToMetersPerSecond(row.valueMetric2);
197
+ }
198
+ if (!value) {
199
+ return {
200
+ value: null,
201
+ low: null,
202
+ high: null,
203
+ };
204
+ }
205
+ else {
206
+ return {
207
+ value,
208
+ low: value - value * 0.02,
209
+ high: value + value * 0.02,
210
+ };
211
+ }
212
+ };
213
+ const createWorkoutGarmin = (userid, workout) => __awaiter(void 0, void 0, void 0, function* () {
214
+ const workoutGarmin = translateWorkoutGarmin(workout);
215
+ const data = yield garminOauthActivity({
216
+ url: 'https://apis.garmin.com/training-api/workout',
217
+ userid,
218
+ params: workoutGarmin,
219
+ httpMethod: 'POST',
220
+ });
221
+ yield (0, db_1.query)('UPDATE [WORKOUT] SET [WORKOUT ID GARMIN] = ?, [WORKOUT OWNER GARMIN] = ? WHERE [ID] = ?', [data.workoutId, data.ownerId, workout.id]);
222
+ return { workoutGarminId: data.workoutId, workoutGarminOwnerId: data.ownerId };
223
+ });
224
+ exports.createWorkoutGarmin = createWorkoutGarmin;
225
+ const updateWorkoutGarmin = (userid, workout) => {
226
+ const workoutGarmin = translateWorkoutGarmin(workout);
227
+ return garminOauthActivity({
228
+ url: 'https://apis.garmin.com/training-api/workout/' + workout.workoutIdGarmin,
229
+ userid,
230
+ params: workoutGarmin,
231
+ httpMethod: 'PUT',
232
+ });
233
+ };
234
+ exports.updateWorkoutGarmin = updateWorkoutGarmin;
235
+ const deleteWorkoutGarmin = (userid, workout) => {
236
+ return garminOauthActivity({
237
+ url: 'https://apis.garmin.com/training-api/workout/' + workout.workoutIdGarmin,
238
+ userid,
239
+ httpMethod: 'DELETE',
240
+ });
241
+ };
242
+ exports.deleteWorkoutGarmin = deleteWorkoutGarmin;
243
+ const scheduleWorkoutGarmin = (userid, workout) => {
244
+ return garminOauthActivity({
245
+ url: 'https://apis.garmin.com/training-api/schedule',
246
+ userid,
247
+ httpMethod: 'POST',
248
+ params: {
249
+ workoutId: workout.workoutIdGarmin,
250
+ date: workout.date,
251
+ },
252
+ });
253
+ };
254
+ exports.scheduleWorkoutGarmin = scheduleWorkoutGarmin;
255
+ const updateScheduleWorkoutGarmin = (userid, schedule, workout) => {
256
+ return garminOauthActivity({
257
+ url: 'https://apis.garmin.com/training-api/schedule/' + schedule.scheduleId,
258
+ userid,
259
+ httpMethod: 'PUT',
260
+ params: {
261
+ scheduleId: schedule.scheduleId,
262
+ workoutId: schedule.workoutId,
263
+ date: workout.date,
264
+ },
265
+ });
266
+ };
267
+ exports.updateScheduleWorkoutGarmin = updateScheduleWorkoutGarmin;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.sendWorkoutToWatch = void 0;
16
+ const db_1 = require("../db");
17
+ const garmin_1 = require("./garmin");
18
+ const common_1 = require("@runnerpro/common");
19
+ const moment_1 = __importDefault(require("moment"));
20
+ const sendWorkoutToWatch = (clientId, workoutId) => __awaiter(void 0, void 0, void 0, function* () {
21
+ const [aplicacion] = yield (0, db_1.query)('SELECT [TIPO APLICATION] FROM [CLIENTE APLICACIONES] WHERE [ID CLIENTE] = ? AND [TIPO APLICATION] = ?', [clientId, common_1.TIPO_APLICACION.GARMIN]);
22
+ if (!aplicacion)
23
+ return { error: 'No tiene Garmin vinculado' };
24
+ // Obtener el workout
25
+ const [workout] = yield (0, db_1.query)('SELECT * FROM [WORKOUT] WHERE [ID] = ? AND [ID CLIENTE] = ?', [workoutId, clientId]);
26
+ if (!workout)
27
+ throw new Error('Workout no encontrado');
28
+ const estructura = yield (0, db_1.query)('SELECT * FROM [WORKOUT STRUCTURE] WHERE [ID WORKOUT] = ? ORDER BY [INDEX]', [workoutId]);
29
+ if (estructura.length > 0)
30
+ workout.estructura = estructura;
31
+ // Llamar a la función que envía el workout al Garmin
32
+ const { workoutGarminId } = yield (0, garmin_1.createWorkoutGarmin)(clientId, workout);
33
+ yield (0, garmin_1.scheduleWorkoutGarmin)(clientId, { date: (0, moment_1.default)(workout.date).format('YYYY-MM-DD'), workoutId: workoutGarminId });
34
+ return { success: true };
35
+ });
36
+ exports.sendWorkoutToWatch = sendWorkoutToWatch;
package/package.json CHANGED
@@ -1,72 +1,73 @@
1
- {
2
- "name": "@runnerpro/backend",
3
- "version": "1.6.8",
4
- "description": "A collection of common backend functions",
5
- "exports": {
6
- ".": "./lib/cjs/index.js"
7
- },
8
- "types": "./lib/cjs/types/index.d.ts",
9
- "main": "./lib/cjs/index.js",
10
- "files": [
11
- "lib/**/*"
12
- ],
13
- "scripts": {
14
- "clean": "del-cli ./lib",
15
- "build": "npm run clean && tsc -p ./configs/tsconfig.cjs.json",
16
- "deploy": "npm run build && npm publish",
17
- "semantic-release": "semantic-release",
18
- "lint": "eslint --ext .ts --ignore-path .gitignore .",
19
- "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
20
- "prepare": "husky",
21
- "test": "jest"
22
- },
23
- "release": {
24
- "branches": [
25
- "main"
26
- ]
27
- },
28
- "publishConfig": {
29
- "access": "public"
30
- },
31
- "repository": {
32
- "type": "git",
33
- "url": "https://gitlab.com/runner-pro/runnerpro-backend.git"
34
- },
35
- "author": "Runner Pro",
36
- "license": "MIT",
37
- "devDependencies": {
38
- "@eslint/js": "^9.6.0",
39
- "@types/eslint__js": "^8.42.3",
40
- "@types/nodemailer": "^6.4.15",
41
- "@types/pg": "^8.11.3",
42
- "del-cli": "5.1.0",
43
- "eslint": "^8.57.0",
44
- "eslint-config-prettier": "^9.1.0",
45
- "eslint-plugin-exception-handling": "^1.0.2",
46
- "eslint-plugin-sonarjs": "^1.0.3",
47
- "husky": "^9.0.11",
48
- "jest": "^29.7.0",
49
- "semantic-release": "23.0.2",
50
- "ts-node": "10.9.2",
51
- "typescript": "5.3.3",
52
- "typescript-eslint": "^7.15.0"
53
- },
54
- "peerDependencies": {
55
- "@napi-rs/canvas": "^0.1.53",
56
- "@runnerpro/common": "^1.5.1",
57
- "axios": "^1.6.7",
58
- "image-size": "^1.0.2",
59
- "jimp": "^0.22.10",
60
- "nodemailer": "6.9.9",
61
- "pg": "8.11.3",
62
- "uuidv4": "^6.2.13"
63
- },
64
- "dependencies": {
65
- "@google-cloud/translate": "^8.3.0",
66
- "@notionhq/client": "^2.2.15",
67
- "exifr": "^7.1.3",
68
- "googleapis": "^144.0.0",
69
- "multer": "^1.4.5-lts.1",
70
- "socket.io": "^4.7.2"
71
- }
72
- }
1
+ {
2
+ "name": "@runnerpro/backend",
3
+ "version": "1.6.10",
4
+ "description": "A collection of common backend functions",
5
+ "exports": {
6
+ ".": "./lib/cjs/index.js"
7
+ },
8
+ "types": "./lib/cjs/types/index.d.ts",
9
+ "main": "./lib/cjs/index.js",
10
+ "files": [
11
+ "lib/**/*"
12
+ ],
13
+ "scripts": {
14
+ "clean": "del-cli ./lib",
15
+ "build": "npm run clean && tsc -p ./configs/tsconfig.cjs.json",
16
+ "deploy": "npm run build && npm publish",
17
+ "semantic-release": "semantic-release",
18
+ "lint": "eslint --ext .ts --ignore-path .gitignore .",
19
+ "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
20
+ "prepare": "husky",
21
+ "test": "jest"
22
+ },
23
+ "release": {
24
+ "branches": [
25
+ "main"
26
+ ]
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://gitlab.com/runner-pro/runnerpro-backend.git"
34
+ },
35
+ "author": "Runner Pro",
36
+ "license": "MIT",
37
+ "devDependencies": {
38
+ "@eslint/js": "^9.6.0",
39
+ "@types/eslint__js": "^8.42.3",
40
+ "@types/nodemailer": "^6.4.15",
41
+ "@types/pg": "^8.11.3",
42
+ "del-cli": "5.1.0",
43
+ "eslint": "^8.57.0",
44
+ "eslint-config-prettier": "^9.1.0",
45
+ "eslint-plugin-exception-handling": "^1.0.2",
46
+ "eslint-plugin-sonarjs": "^1.0.3",
47
+ "husky": "^9.0.11",
48
+ "jest": "^29.7.0",
49
+ "semantic-release": "23.0.2",
50
+ "ts-node": "10.9.2",
51
+ "typescript": "5.3.3",
52
+ "typescript-eslint": "^7.15.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@napi-rs/canvas": "^0.1.53",
56
+ "@runnerpro/common": "^1.5.1",
57
+ "axios": "^1.6.7",
58
+ "image-size": "^1.0.2",
59
+ "jimp": "^0.22.10",
60
+ "nodemailer": "6.9.9",
61
+ "pg": "8.11.3",
62
+ "uuidv4": "^6.2.13"
63
+ },
64
+ "dependencies": {
65
+ "@google-cloud/translate": "^8.3.0",
66
+ "@notionhq/client": "^2.2.15",
67
+ "exifr": "^7.1.3",
68
+ "googleapis": "^144.0.0",
69
+ "multer": "^1.4.5-lts.1",
70
+ "socket.io": "^4.7.2",
71
+ "oauth-signature": "1.5.0"
72
+ }
73
+ }