closer-cli 2.48.0 → 2.48.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.
- package/CHANGELOG.md +16 -0
- package/cmds/importData.js +249 -39
- package/cmds/importMedia.js +39 -45
- package/helpers.js +67 -798
- package/index.js +4 -4
- package/package.json +5 -8
- package/cmds/importData_cmds/multiple.js +0 -341
- package/cmds/importData_cmds/single.js +0 -281
package/helpers.js
CHANGED
|
@@ -1,57 +1,32 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
1
2
|
/* eslint-disable no-console */
|
|
2
3
|
/* eslint-disable no-param-reassign */
|
|
3
4
|
/* eslint-disable implicit-arrow-linebreak */
|
|
4
|
-
import {
|
|
5
|
-
readdirSync,
|
|
6
|
-
existsSync,
|
|
7
|
-
mkdirSync,
|
|
8
|
-
copyFileSync,
|
|
9
|
-
createWriteStream,
|
|
10
|
-
createReadStream,
|
|
11
|
-
rename,
|
|
12
|
-
statSync
|
|
13
|
-
} from 'fs'
|
|
5
|
+
import { readdirSync, existsSync, mkdirSync, createWriteStream } from 'fs'
|
|
14
6
|
import path from 'path'
|
|
15
|
-
import WebSocket from 'ws'
|
|
16
|
-
import chalk from 'chalk'
|
|
17
|
-
import { parse } from 'csv-parse/sync'
|
|
18
|
-
import { stringify } from 'csv-stringify/sync'
|
|
19
7
|
import got from 'got'
|
|
20
8
|
import slugify from 'slugify'
|
|
21
|
-
import { deleteAsync } from 'del'
|
|
22
|
-
import eventStream from 'event-stream'
|
|
23
9
|
|
|
24
|
-
const { split, mapSync } = eventStream
|
|
25
10
|
const { stream } = got
|
|
26
11
|
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
user: 'users.csv',
|
|
46
|
-
customer: 'customers.csv',
|
|
47
|
-
label: 'labels.csv',
|
|
48
|
-
filterPosition: 'filterPosition.csv',
|
|
49
|
-
fieldConfiguration: 'fieldConfigurations.csv',
|
|
50
|
-
stockAvailability: 'stockAvailability.csv',
|
|
51
|
-
configuration: 'configurations.csv',
|
|
52
|
-
userCustomer: 'userCustomers.csv',
|
|
53
|
-
team: 'teams.csv'
|
|
54
|
-
}
|
|
12
|
+
export const CsvType = [
|
|
13
|
+
'products',
|
|
14
|
+
'localizedProducts',
|
|
15
|
+
'localizedFilters',
|
|
16
|
+
'localizedVariants',
|
|
17
|
+
'prices',
|
|
18
|
+
'groups',
|
|
19
|
+
'lookups',
|
|
20
|
+
'users',
|
|
21
|
+
'customers',
|
|
22
|
+
'labels',
|
|
23
|
+
'filterPosition',
|
|
24
|
+
'fieldConfigurations',
|
|
25
|
+
'stockAvailability',
|
|
26
|
+
'configurations',
|
|
27
|
+
'userCustomers',
|
|
28
|
+
'teams'
|
|
29
|
+
]
|
|
55
30
|
|
|
56
31
|
export function getCsvFilesFromDir(dir) {
|
|
57
32
|
return readdirSync(dir).filter(file => path.extname(file).toLowerCase() === '.csv')
|
|
@@ -61,519 +36,6 @@ export function getGoogleSheetCsvUrl(docId, sheet) {
|
|
|
61
36
|
return `https://docs.google.com/spreadsheets/d/${docId}/gviz/tq?tqx=out:csv&sheet=${sheet}`
|
|
62
37
|
}
|
|
63
38
|
|
|
64
|
-
export function importCsvFromFile({
|
|
65
|
-
file,
|
|
66
|
-
csvType,
|
|
67
|
-
outputDir,
|
|
68
|
-
spinner,
|
|
69
|
-
ws,
|
|
70
|
-
delimiter = ';',
|
|
71
|
-
importProcess
|
|
72
|
-
}) {
|
|
73
|
-
return new Promise(resolve => {
|
|
74
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
75
|
-
|
|
76
|
-
const hrstart = process.hrtime()
|
|
77
|
-
const importFileStart = new Date()
|
|
78
|
-
|
|
79
|
-
let readStream = null
|
|
80
|
-
|
|
81
|
-
const dirPathProcessing = path.resolve(outputDir, '_processing')
|
|
82
|
-
|
|
83
|
-
if (!existsSync(dirPathProcessing)) {
|
|
84
|
-
mkdirSync(dirPathProcessing, { recursive: true })
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const filename = path.basename(file)
|
|
88
|
-
const filepath = path.resolve(dirPathProcessing, filename)
|
|
89
|
-
|
|
90
|
-
copyFileSync(file, filepath)
|
|
91
|
-
|
|
92
|
-
const errorCsvFile = path.resolve(outputDir, `${importProcess.name}_${csvType}_errors.csv`)
|
|
93
|
-
const errorFileStream = createWriteStream(errorCsvFile)
|
|
94
|
-
|
|
95
|
-
const skippedCsvFile = path.resolve(outputDir, `${importProcess.name}_${csvType}_skipped.csv`)
|
|
96
|
-
const skippedFileStream = createWriteStream(skippedCsvFile)
|
|
97
|
-
|
|
98
|
-
let header = ''
|
|
99
|
-
let lineNumber = 0
|
|
100
|
-
let countImported = 0
|
|
101
|
-
let countFailed = 0
|
|
102
|
-
let countSkipped = 0
|
|
103
|
-
const partitions = new Set()
|
|
104
|
-
|
|
105
|
-
spinner.start('Loading...')
|
|
106
|
-
|
|
107
|
-
const importRowSuccess = csvRow => {
|
|
108
|
-
partitions.add(csvRow.Partition || '')
|
|
109
|
-
|
|
110
|
-
countImported += 1
|
|
111
|
-
|
|
112
|
-
spinner.text = printImportProcessResult({
|
|
113
|
-
csvType,
|
|
114
|
-
countImported,
|
|
115
|
-
countFailed,
|
|
116
|
-
countSkipped,
|
|
117
|
-
importFileStart,
|
|
118
|
-
importFileEnd: new Date(),
|
|
119
|
-
executionTime: getExecutionTime(hrstart),
|
|
120
|
-
name: filename
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
readStream.resume()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const importRowError = csvRow => {
|
|
127
|
-
partitions.add(csvRow.Partition || '')
|
|
128
|
-
|
|
129
|
-
countFailed += 1
|
|
130
|
-
|
|
131
|
-
spinner.text = printImportProcessResult({
|
|
132
|
-
csvType,
|
|
133
|
-
countImported,
|
|
134
|
-
countFailed,
|
|
135
|
-
countSkipped,
|
|
136
|
-
importFileStart,
|
|
137
|
-
importFileEnd: new Date(),
|
|
138
|
-
executionTime: getExecutionTime(hrstart),
|
|
139
|
-
name: filename
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
errorFileStream.write(
|
|
143
|
-
stringify([csvRow], {
|
|
144
|
-
header: countFailed === 1,
|
|
145
|
-
quoted: true,
|
|
146
|
-
delimiter: ';'
|
|
147
|
-
})
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
readStream.resume()
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const importFatal = (csvRow, errorMessage) => {
|
|
154
|
-
partitions.add(csvRow.Partition || '')
|
|
155
|
-
|
|
156
|
-
spinner.fail(
|
|
157
|
-
printImportProcessResult({
|
|
158
|
-
csvType,
|
|
159
|
-
countImported,
|
|
160
|
-
countFailed,
|
|
161
|
-
countSkipped,
|
|
162
|
-
importFileStart,
|
|
163
|
-
importFileEnd: new Date(),
|
|
164
|
-
executionTime: getExecutionTime(hrstart),
|
|
165
|
-
name: filename,
|
|
166
|
-
fatalError: errorMessage
|
|
167
|
-
})
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
resolve({
|
|
171
|
-
csvType,
|
|
172
|
-
countImported,
|
|
173
|
-
countFailed,
|
|
174
|
-
countSkipped,
|
|
175
|
-
executionTime: getExecutionTime(hrstart),
|
|
176
|
-
importFileStart,
|
|
177
|
-
importFileEnd: new Date(),
|
|
178
|
-
inputFile: file,
|
|
179
|
-
fatalError: `FATAL: ${errorMessage}`,
|
|
180
|
-
partitions
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
readStream.destroy()
|
|
184
|
-
errorFileStream.end()
|
|
185
|
-
skippedFileStream.end()
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const importSuccess = () => {
|
|
189
|
-
if (countFailed > 0 || countSkipped > 0) {
|
|
190
|
-
spinner.warn()
|
|
191
|
-
} else {
|
|
192
|
-
spinner.succeed()
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
errorFileStream.end()
|
|
196
|
-
skippedFileStream.end()
|
|
197
|
-
|
|
198
|
-
deleteAsync(filepath)
|
|
199
|
-
|
|
200
|
-
resolve({
|
|
201
|
-
csvType,
|
|
202
|
-
countImported,
|
|
203
|
-
countFailed,
|
|
204
|
-
countSkipped,
|
|
205
|
-
importFileStart,
|
|
206
|
-
importFileEnd: new Date(),
|
|
207
|
-
executionTime: getExecutionTime(hrstart),
|
|
208
|
-
inputFile: file,
|
|
209
|
-
partitions
|
|
210
|
-
})
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
socket.on('open', () => {
|
|
214
|
-
readStream = createReadStream(file)
|
|
215
|
-
.pipe(split())
|
|
216
|
-
.pipe(
|
|
217
|
-
mapSync(line => {
|
|
218
|
-
readStream.pause()
|
|
219
|
-
|
|
220
|
-
if (lineNumber === 0) {
|
|
221
|
-
header = line
|
|
222
|
-
readStream.resume()
|
|
223
|
-
} else {
|
|
224
|
-
try {
|
|
225
|
-
const rows = parse(`${header}\n${line}`, {
|
|
226
|
-
columns: true,
|
|
227
|
-
skip_empty_lines: true,
|
|
228
|
-
skipLinesWithEmptyValues: true,
|
|
229
|
-
delimiter
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
if (rows.length > 0) {
|
|
233
|
-
const packet = {
|
|
234
|
-
type: 'importCsvRow',
|
|
235
|
-
payload: {
|
|
236
|
-
csvRow: rows[0],
|
|
237
|
-
csvType,
|
|
238
|
-
lineNumber,
|
|
239
|
-
importProcess
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
socket.send(JSON.stringify(packet))
|
|
243
|
-
} else {
|
|
244
|
-
readStream.resume()
|
|
245
|
-
}
|
|
246
|
-
} catch (e) {
|
|
247
|
-
countSkipped += 1
|
|
248
|
-
skippedFileStream.write(`${line},${e.message}`)
|
|
249
|
-
readStream.resume()
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
lineNumber += 1
|
|
254
|
-
})
|
|
255
|
-
)
|
|
256
|
-
.on('error', e => importFatal(e.message))
|
|
257
|
-
.on('end', importSuccess)
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
socket.on('message', packet => {
|
|
261
|
-
const { type, payload } = JSON.parse(packet)
|
|
262
|
-
|
|
263
|
-
switch (type) {
|
|
264
|
-
case 'importRowSuccess':
|
|
265
|
-
importRowSuccess(payload.csvRow)
|
|
266
|
-
break
|
|
267
|
-
case 'importRowError':
|
|
268
|
-
importRowError(payload.csvRow)
|
|
269
|
-
break
|
|
270
|
-
case 'importRowFatal':
|
|
271
|
-
importFatal(payload.csvRow, payload.error)
|
|
272
|
-
break
|
|
273
|
-
default:
|
|
274
|
-
break
|
|
275
|
-
}
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
socket.on('error', e => {
|
|
279
|
-
importFatal(e.message)
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export function sendImportErrorMail(ws, importProcess, csvReport) {
|
|
285
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
286
|
-
|
|
287
|
-
socket.on('open', () => {
|
|
288
|
-
socket.send(
|
|
289
|
-
JSON.stringify({
|
|
290
|
-
type: 'sendImportErrorMail',
|
|
291
|
-
payload: { csvReport, importProcess }
|
|
292
|
-
})
|
|
293
|
-
)
|
|
294
|
-
})
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function validateCsvFromFile(file, csvType, ws, delimiter, importProcess) {
|
|
298
|
-
return new Promise(resolve => {
|
|
299
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
300
|
-
const hrstart = process.hrtime()
|
|
301
|
-
|
|
302
|
-
let readStream = null
|
|
303
|
-
|
|
304
|
-
let header = ''
|
|
305
|
-
let lineNumber = 0
|
|
306
|
-
const filename = path.basename(file)
|
|
307
|
-
|
|
308
|
-
socket.on('open', () => {
|
|
309
|
-
readStream = createReadStream(file)
|
|
310
|
-
.pipe(split())
|
|
311
|
-
.pipe(
|
|
312
|
-
mapSync(line => {
|
|
313
|
-
readStream.pause()
|
|
314
|
-
|
|
315
|
-
if (lineNumber === 0) {
|
|
316
|
-
header = line
|
|
317
|
-
readStream.resume()
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (lineNumber === 1) {
|
|
321
|
-
if (line === '') {
|
|
322
|
-
resolve({
|
|
323
|
-
csvType,
|
|
324
|
-
executionTime: getExecutionTime(hrstart),
|
|
325
|
-
inputFile: filename
|
|
326
|
-
})
|
|
327
|
-
} else {
|
|
328
|
-
const rows = parse(`${header}\n${line}`, {
|
|
329
|
-
columns: true,
|
|
330
|
-
skip_empty_lines: true,
|
|
331
|
-
skipLinesWithEmptyValues: true,
|
|
332
|
-
delimiter
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
const packet = {
|
|
336
|
-
type: 'validateCsvHeaderRequest',
|
|
337
|
-
payload: {
|
|
338
|
-
csvColumns: Object.keys(rows[0]),
|
|
339
|
-
csvType,
|
|
340
|
-
importProcess
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
socket.send(JSON.stringify(packet))
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
readStream.destroy()
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
lineNumber += 1
|
|
351
|
-
})
|
|
352
|
-
)
|
|
353
|
-
.on('error', e => {
|
|
354
|
-
resolve({
|
|
355
|
-
csvType,
|
|
356
|
-
executionTime: getExecutionTime(hrstart),
|
|
357
|
-
inputFile: filename,
|
|
358
|
-
error: e.message
|
|
359
|
-
})
|
|
360
|
-
})
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
socket.on('message', packet => {
|
|
364
|
-
const { type, payload } = JSON.parse(packet)
|
|
365
|
-
switch (type) {
|
|
366
|
-
case 'validateCsvHeaderResponse': {
|
|
367
|
-
const result = {
|
|
368
|
-
csvType,
|
|
369
|
-
executionTime: getExecutionTime(hrstart),
|
|
370
|
-
inputFile: filename
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (payload.error) {
|
|
374
|
-
result.error = payload.error
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
resolve(result)
|
|
378
|
-
break
|
|
379
|
-
}
|
|
380
|
-
default:
|
|
381
|
-
break
|
|
382
|
-
}
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
socket.on('error', e => {
|
|
386
|
-
resolve({
|
|
387
|
-
csvType,
|
|
388
|
-
executionTime: getExecutionTime(hrstart),
|
|
389
|
-
inputFile: file,
|
|
390
|
-
error: e.message
|
|
391
|
-
})
|
|
392
|
-
})
|
|
393
|
-
})
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
export function getExecutionTime(importProcessStart) {
|
|
397
|
-
const hrend = process.hrtime(importProcessStart)
|
|
398
|
-
return ((hrend[0] * 1e9 + hrend[1]) / 1e9).toFixed(1)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export function printValidationProcessHeader() {
|
|
402
|
-
console.log('\n=== Validation Process Result ===\n')
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
export function printImportProcessHeader() {
|
|
406
|
-
console.log('\n=== Import Process Result ===\n')
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
export function printValidationProcessResult({
|
|
410
|
-
inputFile,
|
|
411
|
-
error
|
|
412
|
-
// eslint-disable-next-line consistent-return
|
|
413
|
-
}) {
|
|
414
|
-
let message = ''
|
|
415
|
-
const filename = path.basename(inputFile)
|
|
416
|
-
|
|
417
|
-
if (error) {
|
|
418
|
-
message = `[${chalk.red(filename)}] not valid ${chalk.gray(`[${error}]`)}`
|
|
419
|
-
} else {
|
|
420
|
-
message = `[${chalk.green(filename)}] valid`
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
console.log(message)
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
export function printImportProcessResult({
|
|
427
|
-
countImported,
|
|
428
|
-
countFailed,
|
|
429
|
-
countSkipped,
|
|
430
|
-
executionTime,
|
|
431
|
-
name,
|
|
432
|
-
fatalError
|
|
433
|
-
// eslint-disable-next-line consistent-return
|
|
434
|
-
}) {
|
|
435
|
-
let message = ''
|
|
436
|
-
|
|
437
|
-
if (fatalError) {
|
|
438
|
-
message = `[${chalk.red(name)}] ${chalk.red(fatalError)}`
|
|
439
|
-
return message
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
message = `[${colorByResult(
|
|
443
|
-
name,
|
|
444
|
-
countImported,
|
|
445
|
-
countFailed,
|
|
446
|
-
countSkipped
|
|
447
|
-
)}] imported ${colorGreaterThanZero(countImported, 'green')} items`
|
|
448
|
-
|
|
449
|
-
if (countFailed) {
|
|
450
|
-
message += `, failed ${colorGreaterThanZero(countFailed, 'red')} items`
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (countSkipped) {
|
|
454
|
-
message += `, skipped ${colorGreaterThanZero(countSkipped, 'red')} items`
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
message += ` ${chalk.gray(`[${executionTime}s]`)}`
|
|
458
|
-
|
|
459
|
-
return message
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
export function colorByResult(value, countImported, countFailed, countSkipped) {
|
|
463
|
-
let color = 'green'
|
|
464
|
-
|
|
465
|
-
if (countImported > 0 && (countFailed > 0 || countSkipped > 0)) {
|
|
466
|
-
color = 'yellow'
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
if (countImported === 0 && (countFailed > 0 || countSkipped > 0)) {
|
|
470
|
-
color = 'red'
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return chalk[color](value)
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export function colorGreaterThanZero(value, color) {
|
|
477
|
-
if (value > 0) {
|
|
478
|
-
return chalk[color](value)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return value
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
export function refreshOrders(spinner, ws, importProcess) {
|
|
485
|
-
return new Promise(resolve => {
|
|
486
|
-
const hrstart = process.hrtime()
|
|
487
|
-
|
|
488
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
489
|
-
|
|
490
|
-
spinner.start('Refreshing orders (draft, template)...')
|
|
491
|
-
|
|
492
|
-
socket.on('open', () => {
|
|
493
|
-
socket.send(JSON.stringify({ type: 'refreshOrdersRequest', payload: { importProcess } }))
|
|
494
|
-
})
|
|
495
|
-
|
|
496
|
-
socket.on('message', packet => {
|
|
497
|
-
const { type, payload } = JSON.parse(packet)
|
|
498
|
-
switch (type) {
|
|
499
|
-
case 'refreshOrdersResponse': {
|
|
500
|
-
spinner.text = printRefreshedOrders({
|
|
501
|
-
...payload,
|
|
502
|
-
executionTime: getExecutionTime(hrstart)
|
|
503
|
-
})
|
|
504
|
-
spinner.succeed()
|
|
505
|
-
resolve({
|
|
506
|
-
totalCount: payload.totalCount,
|
|
507
|
-
refreshed: payload.refreshed,
|
|
508
|
-
errored: payload.errored,
|
|
509
|
-
name: importProcess.name,
|
|
510
|
-
executionTime: getExecutionTime(hrstart)
|
|
511
|
-
})
|
|
512
|
-
break
|
|
513
|
-
}
|
|
514
|
-
default:
|
|
515
|
-
break
|
|
516
|
-
}
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
socket.on('error', e => {
|
|
520
|
-
resolve({ error: e.message })
|
|
521
|
-
})
|
|
522
|
-
})
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// eslint-disable-next-line consistent-return
|
|
526
|
-
export function printRefreshedOrders({ refreshed, errored, executionTime }) {
|
|
527
|
-
let message = ''
|
|
528
|
-
|
|
529
|
-
const stringRefreshed = colorGreaterThanZero(refreshed.length, 'green')
|
|
530
|
-
const stringErrored = colorGreaterThanZero(errored.length, 'red')
|
|
531
|
-
|
|
532
|
-
message += `Refreshed ${stringRefreshed} orders (draft, template)`
|
|
533
|
-
|
|
534
|
-
if (errored.length) {
|
|
535
|
-
message += `, refresh failed for ${stringErrored} orders.`
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
message += ` ${chalk.gray(`[${executionTime}s]`)}`
|
|
539
|
-
|
|
540
|
-
return message
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
export function deleteRowsBeforeImportDate(importProcess, partitionsForCsvType, spinner, ws) {
|
|
544
|
-
return new Promise(resolve => {
|
|
545
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
546
|
-
|
|
547
|
-
spinner.start('Deleting old database records for chosen partitions...')
|
|
548
|
-
|
|
549
|
-
socket.on('open', () => {
|
|
550
|
-
socket.send(
|
|
551
|
-
JSON.stringify({
|
|
552
|
-
type: 'deleteRowsBeforeImportDateRequest',
|
|
553
|
-
payload: { importProcess, partitionsForCsvType }
|
|
554
|
-
})
|
|
555
|
-
)
|
|
556
|
-
})
|
|
557
|
-
|
|
558
|
-
socket.on('message', packet => {
|
|
559
|
-
const { type } = JSON.parse(packet)
|
|
560
|
-
switch (type) {
|
|
561
|
-
case 'deleteRowsBeforeImportDateResponse': {
|
|
562
|
-
spinner.succeed('Database records deleted (soft)')
|
|
563
|
-
resolve()
|
|
564
|
-
break
|
|
565
|
-
}
|
|
566
|
-
default:
|
|
567
|
-
break
|
|
568
|
-
}
|
|
569
|
-
})
|
|
570
|
-
|
|
571
|
-
socket.on('error', e => {
|
|
572
|
-
resolve({ error: e.message })
|
|
573
|
-
})
|
|
574
|
-
})
|
|
575
|
-
}
|
|
576
|
-
|
|
577
39
|
export async function download(url, destPath, fileName) {
|
|
578
40
|
return new Promise((resolve, reject) => {
|
|
579
41
|
const filePath = path.resolve(destPath, fileName)
|
|
@@ -601,210 +63,7 @@ export async function download(url, destPath, fileName) {
|
|
|
601
63
|
})
|
|
602
64
|
}
|
|
603
65
|
|
|
604
|
-
export function
|
|
605
|
-
return new Promise((resolve, reject) => {
|
|
606
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
607
|
-
|
|
608
|
-
spinner.start('Executing tasks before start...')
|
|
609
|
-
|
|
610
|
-
socket.on('open', () => {
|
|
611
|
-
socket.send(
|
|
612
|
-
JSON.stringify({ type: 'callBeforeDataImportProcessRequest', payload: { importProcess } })
|
|
613
|
-
)
|
|
614
|
-
})
|
|
615
|
-
|
|
616
|
-
socket.on('message', packet => {
|
|
617
|
-
const { type, payload } = JSON.parse(packet)
|
|
618
|
-
switch (type) {
|
|
619
|
-
case 'callBeforeDataImportProcessResponse': {
|
|
620
|
-
if (payload.error) {
|
|
621
|
-
spinner.fail(payload.error)
|
|
622
|
-
reject()
|
|
623
|
-
} else {
|
|
624
|
-
spinner.succeed('Tasks executed before start')
|
|
625
|
-
resolve()
|
|
626
|
-
}
|
|
627
|
-
break
|
|
628
|
-
}
|
|
629
|
-
default:
|
|
630
|
-
break
|
|
631
|
-
}
|
|
632
|
-
})
|
|
633
|
-
|
|
634
|
-
socket.on('error', e => {
|
|
635
|
-
resolve({ error: e.message })
|
|
636
|
-
})
|
|
637
|
-
})
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
export function callAfterDataImportProcess(spinner, ws, importProcess) {
|
|
641
|
-
return new Promise(resolve => {
|
|
642
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
643
|
-
|
|
644
|
-
spinner.start('Executing tasks after the end process...')
|
|
645
|
-
|
|
646
|
-
socket.on('open', () => {
|
|
647
|
-
socket.send(
|
|
648
|
-
JSON.stringify({ type: 'callAfterDataImportProcessRequest', payload: { importProcess } })
|
|
649
|
-
)
|
|
650
|
-
})
|
|
651
|
-
|
|
652
|
-
socket.on('message', packet => {
|
|
653
|
-
const { type } = JSON.parse(packet)
|
|
654
|
-
switch (type) {
|
|
655
|
-
case 'callAfterDataImportProcessResponse': {
|
|
656
|
-
spinner.succeed('Tasks executed after the end process')
|
|
657
|
-
resolve()
|
|
658
|
-
break
|
|
659
|
-
}
|
|
660
|
-
default:
|
|
661
|
-
break
|
|
662
|
-
}
|
|
663
|
-
})
|
|
664
|
-
|
|
665
|
-
socket.on('error', e => {
|
|
666
|
-
resolve({ error: e.message })
|
|
667
|
-
})
|
|
668
|
-
})
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
export function callAfterMediaImportProcess(spinner, ws, report) {
|
|
672
|
-
return new Promise(resolve => {
|
|
673
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
674
|
-
|
|
675
|
-
spinner.start('Executing tasks after the end process...')
|
|
676
|
-
|
|
677
|
-
socket.on('open', () => {
|
|
678
|
-
socket.send(JSON.stringify({ type: 'callAfterMediaImportProcessRequest', payload: report }))
|
|
679
|
-
})
|
|
680
|
-
|
|
681
|
-
socket.on('message', packet => {
|
|
682
|
-
const { type } = JSON.parse(packet)
|
|
683
|
-
switch (type) {
|
|
684
|
-
case 'callAfterMediaImportProcessResponse': {
|
|
685
|
-
spinner.succeed('Tasks executed after the end process')
|
|
686
|
-
resolve()
|
|
687
|
-
break
|
|
688
|
-
}
|
|
689
|
-
default:
|
|
690
|
-
break
|
|
691
|
-
}
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
socket.on('error', e => {
|
|
695
|
-
resolve({ error: e.message })
|
|
696
|
-
})
|
|
697
|
-
})
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
export function importMedia(reprocess, spinner, ws) {
|
|
701
|
-
return new Promise(resolve => {
|
|
702
|
-
const hrstart = process.hrtime()
|
|
703
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
704
|
-
|
|
705
|
-
let countAssetImported = 0
|
|
706
|
-
let countAssetSkipped = 0
|
|
707
|
-
let countAssetFailed = 0
|
|
708
|
-
let countProductAssetImported = 0
|
|
709
|
-
|
|
710
|
-
const updateSpinnerText = () => {
|
|
711
|
-
spinner.text = printImportProcessResult({
|
|
712
|
-
countImported: countAssetImported,
|
|
713
|
-
countSkipped: countAssetSkipped,
|
|
714
|
-
countFailed: countAssetFailed,
|
|
715
|
-
executionTime: getExecutionTime(hrstart),
|
|
716
|
-
name: 'Asset'
|
|
717
|
-
})
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
socket.on('open', () => {
|
|
721
|
-
socket.send(JSON.stringify({ type: 'import.images', payload: { reprocess } }))
|
|
722
|
-
})
|
|
723
|
-
|
|
724
|
-
socket.on('message', packet => {
|
|
725
|
-
const { type, payload } = JSON.parse(packet)
|
|
726
|
-
|
|
727
|
-
switch (type) {
|
|
728
|
-
case 'import.images.start':
|
|
729
|
-
spinner.start('[Asset] Importing Assets...')
|
|
730
|
-
break
|
|
731
|
-
case 'import.images.imageAsset.success':
|
|
732
|
-
countAssetImported += 1
|
|
733
|
-
updateSpinnerText()
|
|
734
|
-
break
|
|
735
|
-
case 'import.images.imageAsset.skipped':
|
|
736
|
-
countAssetSkipped += 1
|
|
737
|
-
updateSpinnerText()
|
|
738
|
-
break
|
|
739
|
-
case 'import.images.imageAsset.failed':
|
|
740
|
-
countAssetFailed += 1
|
|
741
|
-
updateSpinnerText()
|
|
742
|
-
break
|
|
743
|
-
case 'import.images.productAssets.start':
|
|
744
|
-
countProductAssetImported = payload.count
|
|
745
|
-
spinner.succeed()
|
|
746
|
-
spinner.start(`[ProductAsset] Importing ${countProductAssetImported} Product Assets...`)
|
|
747
|
-
break
|
|
748
|
-
case 'import.images.productAssets.end':
|
|
749
|
-
spinner.succeed(
|
|
750
|
-
printImportProcessResult({
|
|
751
|
-
countImported: payload.count,
|
|
752
|
-
countFailed: 0,
|
|
753
|
-
executionTime: getExecutionTime(hrstart),
|
|
754
|
-
name: 'ProductAsset'
|
|
755
|
-
})
|
|
756
|
-
)
|
|
757
|
-
break
|
|
758
|
-
case 'import.images.end':
|
|
759
|
-
resolve({
|
|
760
|
-
countAssetImported,
|
|
761
|
-
countAssetSkipped,
|
|
762
|
-
countAssetFailed,
|
|
763
|
-
countProductAssetImported
|
|
764
|
-
})
|
|
765
|
-
break
|
|
766
|
-
default:
|
|
767
|
-
break
|
|
768
|
-
}
|
|
769
|
-
})
|
|
770
|
-
|
|
771
|
-
socket.on('error', e => {
|
|
772
|
-
resolve({ error: e.message })
|
|
773
|
-
})
|
|
774
|
-
})
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
export function flushMedia(spinner, ws) {
|
|
778
|
-
return new Promise((resolve, reject) => {
|
|
779
|
-
const socket = createSocketConnection(ws.endpoint, ws.secret)
|
|
780
|
-
|
|
781
|
-
spinner.start('Flushing... ')
|
|
782
|
-
|
|
783
|
-
socket.on('open', () => {
|
|
784
|
-
socket.send(JSON.stringify({ type: 'flush.media.request' }))
|
|
785
|
-
})
|
|
786
|
-
|
|
787
|
-
socket.on('message', packet => {
|
|
788
|
-
const { type } = JSON.parse(packet)
|
|
789
|
-
switch (type) {
|
|
790
|
-
case 'flush.media.response': {
|
|
791
|
-
spinner.succeed('Flushing completed')
|
|
792
|
-
resolve()
|
|
793
|
-
break
|
|
794
|
-
}
|
|
795
|
-
default:
|
|
796
|
-
break
|
|
797
|
-
}
|
|
798
|
-
})
|
|
799
|
-
|
|
800
|
-
socket.on('error', e => {
|
|
801
|
-
spinner.fail(e.message)
|
|
802
|
-
reject(e)
|
|
803
|
-
})
|
|
804
|
-
})
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
export function getArchiveFolder(instanceEndpoint) {
|
|
66
|
+
export function getImportDirName(instanceEndpoint) {
|
|
808
67
|
const prefix = 'closer'
|
|
809
68
|
const instance = slugify(instanceEndpoint.split('/')[0], {
|
|
810
69
|
lower: true,
|
|
@@ -813,30 +72,6 @@ export function getArchiveFolder(instanceEndpoint) {
|
|
|
813
72
|
return `${prefix}_${instance}`
|
|
814
73
|
}
|
|
815
74
|
|
|
816
|
-
export function renameWithTimestamp(dirPath) {
|
|
817
|
-
const ts = getTimestampForFilename()
|
|
818
|
-
|
|
819
|
-
const files = getCsvFilesFromDir(dirPath).map(filename => {
|
|
820
|
-
const oldPath = path.resolve(dirPath, filename)
|
|
821
|
-
const [name, ext] = oldPath.split('.')
|
|
822
|
-
const newPath = `${name}_${ts}.${ext}`
|
|
823
|
-
return {
|
|
824
|
-
oldPath,
|
|
825
|
-
newPath
|
|
826
|
-
}
|
|
827
|
-
})
|
|
828
|
-
|
|
829
|
-
files.forEach(file => rename(file.oldPath, file.newPath, () => {}))
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
const getTimestampForFilename = () => {
|
|
833
|
-
const date = new Date()
|
|
834
|
-
const [isoDateString, isoTimeString] = date.toISOString().split('T')
|
|
835
|
-
const dateString = isoDateString.split('-').join('')
|
|
836
|
-
const timeString = isoTimeString.split(':').join('').split('.')[0]
|
|
837
|
-
return `${dateString}_${timeString}`.split(':').join('')
|
|
838
|
-
}
|
|
839
|
-
|
|
840
75
|
export function getHumanTimestamp(date) {
|
|
841
76
|
const [isoDateString, isoTimeString] = date.toISOString().split('T')
|
|
842
77
|
const dateString = isoDateString.split('-').join('')
|
|
@@ -844,18 +79,52 @@ export function getHumanTimestamp(date) {
|
|
|
844
79
|
return `${dateString}_${timeString}`.split(':').join('')
|
|
845
80
|
}
|
|
846
81
|
|
|
847
|
-
export
|
|
848
|
-
|
|
849
|
-
|
|
82
|
+
// export function createSocketConnection(endpoint, secret) {
|
|
83
|
+
// const protocol = endpoint.includes('localhost') || endpoint.includes('127.0.0.1') ? 'ws' : 'wss'
|
|
84
|
+
// const url = `${protocol}://${endpoint}/import`
|
|
85
|
+
// const socket = new WebSocket(url, {
|
|
86
|
+
// headers: { 'x-closer-secret': secret }
|
|
87
|
+
// })
|
|
850
88
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
89
|
+
// return socket
|
|
90
|
+
// }
|
|
854
91
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
return { filename: file, mtimeMS: stat.mtimeMs, mtime: stat.mtime, size: stat.size }
|
|
858
|
-
})
|
|
92
|
+
// export function colorByResult(value, countImported, countFailed, countSkipped) {
|
|
93
|
+
// let color = 'green'
|
|
859
94
|
|
|
860
|
-
|
|
861
|
-
|
|
95
|
+
// if (countImported > 0 && (countFailed > 0 || countSkipped > 0)) {
|
|
96
|
+
// color = 'yellow'
|
|
97
|
+
// }
|
|
98
|
+
|
|
99
|
+
// if (countImported === 0 && (countFailed > 0 || countSkipped > 0)) {
|
|
100
|
+
// color = 'red'
|
|
101
|
+
// }
|
|
102
|
+
|
|
103
|
+
// return chalk[color](value)
|
|
104
|
+
// }
|
|
105
|
+
|
|
106
|
+
// export function colorGreaterThanZero(value, color) {
|
|
107
|
+
// if (value > 0) {
|
|
108
|
+
// return chalk[color](value)
|
|
109
|
+
// }
|
|
110
|
+
|
|
111
|
+
// return value
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
// eslint-disable-next-line consistent-return
|
|
115
|
+
// export function printRefreshedOrders({ refreshed, errored, executionTime }) {
|
|
116
|
+
// let message = ''
|
|
117
|
+
|
|
118
|
+
// const stringRefreshed = colorGreaterThanZero(refreshed.length, 'green')
|
|
119
|
+
// const stringErrored = colorGreaterThanZero(errored.length, 'red')
|
|
120
|
+
|
|
121
|
+
// message += `Refreshed ${stringRefreshed} orders (draft, template)`
|
|
122
|
+
|
|
123
|
+
// if (errored.length) {
|
|
124
|
+
// message += `, refresh failed for ${stringErrored} orders.`
|
|
125
|
+
// }
|
|
126
|
+
|
|
127
|
+
// message += ` ${chalk.gray(`[${executionTime}s]`)}`
|
|
128
|
+
|
|
129
|
+
// return message
|
|
130
|
+
// }
|