nitor 1.0.0 → 1.2.0

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.
@@ -0,0 +1,301 @@
1
+ const axios = require('axios');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const readline = require('readline');
5
+ const fs = require('fs');
6
+ const { zohoConfig } = require('../utils');
7
+
8
+ const userHomeDir = `${os.homedir()}/.time-entry`;
9
+ const filePath = path.join(userHomeDir, '.zoho-config');
10
+ const keyMap = {
11
+ p: 'project',
12
+ project: 'project',
13
+ s: 'sprint',
14
+ sprint: 'sprint',
15
+ t: 'task',
16
+ task: 'task',
17
+ dt: 'date',
18
+ date: 'date',
19
+ w: 'work',
20
+ work: 'work',
21
+ du: 'duration',
22
+ duration: 'duration',
23
+ r: 'remarks',
24
+ remarks: 'remarks',
25
+ id: 'id',
26
+ i: 'id',
27
+ };
28
+ const contentTableHeading =
29
+ '| id | project | sprint | date | task | work | duration | remarks | synced |';
30
+ const contentTableSeparator = '| -- | -- | -- | -- | -- | -- | -- | -- | -- |';
31
+
32
+ const accessFileSync = (path) => {
33
+ try {
34
+ fs.accessSync(path, fs.constants.R_OK | fs.constants.W_OK);
35
+
36
+ return true;
37
+ } catch {
38
+ return false;
39
+ }
40
+ };
41
+ const appendFileSync = (path, data) => {
42
+ try {
43
+ fs.appendFileSync(path, data);
44
+ } catch (error) {
45
+ console.log(error);
46
+ }
47
+ };
48
+ const convertToTaskData = async (values) => {
49
+ const sprints = await getSprints({ params: { type: '2' } });
50
+ const data = values.reduce((acc, item) => {
51
+ let [key, ...itemValues] = item.split(' ');
52
+ let itemValue = itemValues.join(' ');
53
+
54
+ if (key.charAt(0) === '-') {
55
+ key = key.substring(1);
56
+ }
57
+
58
+ switch (key) {
59
+ case 's':
60
+ case 'sprint': {
61
+ if (!itemValue.includes('sprint')) {
62
+ itemValue = `sprint ${itemValue}`;
63
+ }
64
+
65
+ acc[keyMap[key]] = itemValue;
66
+
67
+ break;
68
+ }
69
+
70
+ case 'dt':
71
+ case 'date': {
72
+ acc[keyMap[key]] = new Date(itemValue).toISOString().split('T')[0];
73
+
74
+ break;
75
+ }
76
+
77
+ case 'du':
78
+ case 'duration': {
79
+ acc[keyMap[key]] = +itemValue;
80
+
81
+ break;
82
+ }
83
+
84
+ default: {
85
+ acc[keyMap[key]] = itemValue;
86
+
87
+ break;
88
+ }
89
+ }
90
+
91
+ return acc;
92
+ }, {});
93
+
94
+ if (!data.project) {
95
+ data.project = Object.values(zohoConfig.projects).find(
96
+ (p) => p.value === zohoConfig.defaultProjectId,
97
+ )?.label;
98
+ }
99
+
100
+ if (!data.sprint) {
101
+ if (sprints.length > 1) {
102
+ await new Promise((resolve) => {
103
+ console.log('Multiple active sprints are available, select your task sprint.');
104
+ for (const [index, project] of Object.entries(sprints)) {
105
+ console.log(`${+index + 1}. ${project.label}`);
106
+ }
107
+
108
+ rl.question('Enter the sprint index: ', (userInput) => {
109
+ data.sprint = sprints[+userInput - 1].label;
110
+
111
+ rl.close();
112
+ resolve(data.sprint);
113
+ });
114
+ });
115
+ } else {
116
+ data.sprint = sprints[0].label;
117
+ }
118
+ }
119
+
120
+ return data;
121
+ };
122
+ const existsSync = (path) => {
123
+ return fs.existsSync(path);
124
+ };
125
+ const getHeaders = async () => {
126
+ return {
127
+ authority: 'externalusers.zohosprints.com',
128
+ accept: '*/*',
129
+ 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8,ml;q=0.7',
130
+ 'cache-control': 'no-cache',
131
+ cookie: zohoConfig.cookie,
132
+ pragma: 'no-cache',
133
+ referer: `${zohoConfig.url}/workspace/4medica/client/wmoku`,
134
+ 'sec-ch-ua': '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
135
+ 'sec-ch-ua-mobile': '?0',
136
+ 'sec-ch-ua-platform': '"macOS"',
137
+ 'sec-fetch-dest': 'empty',
138
+ 'sec-fetch-mode': 'cors',
139
+ 'sec-fetch-site': 'same-origin',
140
+ 'user-agent':
141
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
142
+ 'x-requested-with': 'XMLHttpRequest',
143
+ 'x-za-clientportalid': zohoConfig.portalId,
144
+ 'x-za-reqsize': 'large',
145
+ 'x-za-sessionid': zohoConfig.sessionId,
146
+ 'x-za-source': zohoConfig.source,
147
+ 'x-za-ui-version': 'v2',
148
+ 'x-zcsrf-token': zohoConfig.token,
149
+ };
150
+ };
151
+ const getProjects = async () => {
152
+ const headers = await getHeaders();
153
+ const p = {
154
+ action: 'recentprojects',
155
+ team: '803166918',
156
+ };
157
+ const parentUrl = `${zohoConfig.url}/zsapi/team/${p.team}/projects/?action=${p.action}`;
158
+
159
+ try {
160
+ const response = await axios.get(parentUrl, { headers });
161
+
162
+ return Object.entries(response.data.projectJObj)
163
+ .map(([key, value]) => ({ value: key, label: value[0] }))
164
+ .sort((a, b) => (a.label < b.label ? 1 : a.label > b.label ? -1 : 0));
165
+ } catch (error) {
166
+ console.error(error.message);
167
+ }
168
+ };
169
+ const getSprints = async ({ params }) => {
170
+ const headers = await getHeaders();
171
+ const p = {
172
+ index: params.index || 1,
173
+ range: params.range || 150,
174
+ project: params.project || zohoConfig.defaultProjectId,
175
+ action: 'data',
176
+ team: zohoConfig.team,
177
+ };
178
+
179
+ if (params?.type) {
180
+ if (typeof params.type === 'string') {
181
+ p.type = params.type.split(',');
182
+ } else {
183
+ p.type = params.type;
184
+ }
185
+ } else {
186
+ p.type = ['2', '3'];
187
+ }
188
+ const parentUrl = `${zohoConfig.url}/zsapi/team/${p.team}/projects/${
189
+ p.project
190
+ }/sprints/?action=${p.action}&range=${p.range}&type=${encodeURIComponent(
191
+ JSON.stringify(p.type),
192
+ )}&index=${p.index}`;
193
+
194
+ try {
195
+ const response = await axios.get(parentUrl, { headers });
196
+
197
+ return Object.entries(response.data.sprintJObj)
198
+ .map(([key, value]) => ({ value: key, label: value[0] }))
199
+ .sort((a, b) => (a.label < b.label ? 1 : a.label > b.label ? -1 : 0));
200
+ } catch (error) {
201
+ console.error(error.message);
202
+ }
203
+ };
204
+ const groupBy = (arr, key) => {
205
+ return arr.reduce((acc, obj) => {
206
+ const group = obj[key];
207
+
208
+ if (!acc[group]) {
209
+ acc[group] = [];
210
+ }
211
+
212
+ acc[group].push(obj);
213
+
214
+ return acc;
215
+ }, {});
216
+ };
217
+ const mkdirSync = () => {
218
+ try {
219
+ return fs.mkdirSync(userHomeDir);
220
+ } catch (error) {
221
+ console.log(error);
222
+ }
223
+ };
224
+ const readFileSync = (path) => {
225
+ try {
226
+ return fs.readFileSync(path, 'utf8');
227
+ } catch (error) {
228
+ // console.log(error);
229
+ }
230
+ };
231
+ const removeEmpty = (obj) => {
232
+ for (let [key, val] of Object.entries(obj)) {
233
+ if (val && typeof val === 'object') {
234
+ this.removeEmpty(val);
235
+
236
+ if (!(Object.keys(val).length || val instanceof Date)) {
237
+ delete obj[key];
238
+ }
239
+ } else {
240
+ if (typeof val === 'string') {
241
+ val = val.trim();
242
+ }
243
+
244
+ if (val === null || val === undefined || val === '') {
245
+ delete obj[key];
246
+ } else {
247
+ obj[key] = val;
248
+ }
249
+ }
250
+ }
251
+
252
+ return obj;
253
+ };
254
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
255
+ const userConfig = async (jsonData) => {
256
+ return new Promise((resolve, reject) => {
257
+ try {
258
+ if (!jsonData) {
259
+ const data = readFileSync(filePath);
260
+ jsonData = JSON.parse(data);
261
+ }
262
+
263
+ if (!Object.values(jsonData).length) {
264
+ throw new Error('No configurations found, try `zoho init` as first step.');
265
+ }
266
+
267
+ resolve(jsonData);
268
+ } catch (parseError) {
269
+ reject(parseError);
270
+ }
271
+ });
272
+ };
273
+ const writeFileSync = (path, data) => {
274
+ try {
275
+ fs.writeFileSync(path, data);
276
+ } catch (error) {
277
+ console.log(error);
278
+ }
279
+ };
280
+
281
+ module.exports = {
282
+ accessFileSync,
283
+ appendFileSync,
284
+ contentTableHeading,
285
+ contentTableSeparator,
286
+ convertToTaskData,
287
+ existsSync,
288
+ filePath,
289
+ getHeaders,
290
+ getProjects,
291
+ getSprints,
292
+ groupBy,
293
+ mkdirSync,
294
+ path,
295
+ readFileSync,
296
+ removeEmpty,
297
+ rl,
298
+ userConfig,
299
+ userHomeDir,
300
+ writeFileSync,
301
+ };
package/services/utils.js CHANGED
@@ -4,10 +4,6 @@ const { ACTIONS } = require('./enums/actions.enum');
4
4
 
5
5
  require('dotenv').config({ path: path.resolve(require('os').homedir(), 'Desktop/.env.nu') });
6
6
 
7
- const csrfToken = process.env.CSRF_TOKEN;
8
- const Cookie = process.env.COOKIE;
9
- const Origin = process.env.ORIGIN;
10
- const gitlabToken = process.env.GITLAB_TOKEN;
11
7
  const mrPrompt = process.env.MR_PROMPT;
12
8
  const mrLang = process.env.MR_LANG;
13
9
  const mrApiUri = process.env.MR_API_URI;
@@ -15,6 +11,26 @@ const openAIKey = process.env.AI_API_KEY;
15
11
  const openAIModel = process.env.AI_MODEL;
16
12
  const backupConfig = process.env.BACKUP_CONFIG && JSON.parse(process.env.BACKUP_CONFIG);
17
13
  const restoreConfig = process.env.RESTORE_CONFIG && JSON.parse(process.env.RESTORE_CONFIG);
14
+ const gitlabConfig = {
15
+ url: process.env.GITLAB_URL,
16
+ cookie: process.env.GITLAB_COOKIE,
17
+ xCsrfToken: process.env.GITLAB_XCSRF_TOKEN,
18
+ userId: process.env.GITLAB_USERID,
19
+ token: process.env.GITLAB_TOKEN,
20
+ };
21
+ const zohoConfig = {
22
+ cookie: process.env.ZOHO_COOKIE,
23
+ customViewId: process.env.ZOHO_CUSTOMVIEW_ID,
24
+ defaultProjectId: process.env.ZOHO_DEFAULt_PROJECT_ID,
25
+ portalId: process.env.ZOHO_PORTAL_ID,
26
+ projects: process.env.ZOHO_PROJECTS,
27
+ sessionId: process.env.ZOHO_SESSION_ID,
28
+ source: process.env.ZOHO_SOURCE,
29
+ team: process.env.ZOHO_TEAM,
30
+ token: process.env.ZOHO_TOKEN,
31
+ url: process.env.ZOHO_URI,
32
+ userId: process.env.ZOHO_USERID,
33
+ };
18
34
  const keyMap = {
19
35
  components: 'components',
20
36
  c: 'components',
@@ -94,12 +110,12 @@ const buildHeaders = (url) => ({
94
110
  'Accept-Language': 'en-US,en;q=0.5',
95
111
  'Accept-Encoding': 'gzip, deflate, br',
96
112
  Referer: `${url}/new`,
97
- 'X-CSRF-Token': csrfToken,
113
+ 'X-CSRF-Token': gitlabConfig.xCsrfToken,
98
114
  'X-Requested-With': 'XMLHttpRequest',
99
115
  'Content-Type': 'application/json',
100
- Origin,
116
+ Origin: gitlabConfig.url,
101
117
  Connection: 'keep-alive',
102
- Cookie,
118
+ Cookie: gitlabConfig.cookie,
103
119
  'Sec-Fetch-Dest': 'empty',
104
120
  'Sec-Fetch-Mode': 'cors',
105
121
  'Sec-Fetch-Site': 'same-origin',
@@ -178,7 +194,7 @@ const generateBuildConfigs = (values = {}) => {
178
194
 
179
195
  // Client config
180
196
  if (values.components.includes('client')) {
181
- configs.client.config = makeConfig(`${Origin}/cxd/${project}-client/-/pipelines`, {
197
+ configs.client.config = makeConfig(`${gitlabConfig.url}/cxd/${project}-client/-/pipelines`, {
182
198
  ...dataBase,
183
199
  });
184
200
  }
@@ -205,7 +221,7 @@ const generateBuildConfigs = (values = {}) => {
205
221
  ],
206
222
  };
207
223
  configs.backend.config = makeConfig(
208
- `${Origin}/cxd/${project}-backend/-/pipelines`,
224
+ `${gitlabConfig.url}/cxd/${project}-backend/-/pipelines`,
209
225
  backendData,
210
226
  );
211
227
  }
@@ -217,7 +233,7 @@ const generateBuildStatusConfigs = (values = {}, configs) => {
217
233
 
218
234
  if (values.components.includes('client') && configs.client.buildId) {
219
235
  configs.client.statusConfig = makeConfig(
220
- `${Origin}/cxd/${project}-client/-/pipelines/${configs.client.buildId}`,
236
+ `${gitlabConfig.url}/cxd/${project}-client/-/pipelines/${configs.client.buildId}`,
221
237
  null,
222
238
  'get',
223
239
  );
@@ -225,7 +241,7 @@ const generateBuildStatusConfigs = (values = {}, configs) => {
225
241
 
226
242
  if (backendComps.some((c) => values.components.includes(c)) && configs.backend.buildId) {
227
243
  configs.backend.statusConfig = makeConfig(
228
- `${Origin}/cxd/${project}-backend/-/pipelines/${configs.backend.buildId}`,
244
+ `${gitlabConfig.url}/cxd/${project}-backend/-/pipelines/${configs.backend.buildId}`,
229
245
  null,
230
246
  'get',
231
247
  );
@@ -273,7 +289,7 @@ const generateDeployConfigs = (values = {}) => {
273
289
  }
274
290
 
275
291
  const project = projectMap[values.project] || projectMap.portal;
276
- const configs = makeConfig(`${Origin}/cxd/${project}-deployment/-/pipelines`, {
292
+ const configs = makeConfig(`${gitlabConfig.url}/cxd/${project}-deployment/-/pipelines`, {
277
293
  ref: `refs/heads/${deploymentBranchMap[values.instance]}`,
278
294
  variables_attributes,
279
295
  });
@@ -293,7 +309,7 @@ const convertParamsToMap = async (item, type) => {
293
309
  let live = false;
294
310
 
295
311
  if (!skipCheck) {
296
- if (!(csrfToken || Cookie || Origin || gitlabToken)) {
312
+ if (!gitlabConfig.token) {
297
313
  console.log('Configurations are missing...!');
298
314
  return null;
299
315
  }
@@ -301,7 +317,7 @@ const convertParamsToMap = async (item, type) => {
301
317
  console.log(`Checking website status...`);
302
318
 
303
319
  await axios
304
- .get(Origin)
320
+ .get(gitlabConfig.url)
305
321
  .then(() => {
306
322
  live = true;
307
323
 
@@ -340,7 +356,6 @@ module.exports = {
340
356
  generateDeployConfigs,
341
357
  generateBuildStatusConfigs,
342
358
  wait,
343
- gitlabToken,
344
359
  projectIdMap,
345
360
  mrPrompt,
346
361
  mrLang,
@@ -349,4 +364,6 @@ module.exports = {
349
364
  openAIModel,
350
365
  backupConfig,
351
366
  restoreConfig,
367
+ zohoConfig,
368
+ gitlabConfig,
352
369
  };