@xuda.io/drive_module 1.1.1476 → 1.1.1478
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/index.js +2207 -0
- package/index_ms.mjs +4 -0
- package/index_msa.mjs +170 -166
- package/package.json +1 -1
package/index.js
ADDED
|
@@ -0,0 +1,2207 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
global._conf = require(path.join(process.env.XUDA_HOME, process.env.XUDA_CONFIG));
|
|
3
|
+
console.log('Drive Module loaded...');
|
|
4
|
+
|
|
5
|
+
const _common = require(path.join(process.env.XUDA_HOME, 'common', 'xuda_node_common.mjs'));
|
|
6
|
+
const _utils = require(path.join(process.env.XUDA_HOME, 'common', 'xuda-cpi-utils.mjs'));
|
|
7
|
+
|
|
8
|
+
const _ = require('lodash');
|
|
9
|
+
|
|
10
|
+
const module_path = path.join(process.env.XUDA_HOME, 'cpi') + (!_conf.is_debug ? '/node_modules/@xuda.io' : '');
|
|
11
|
+
const fs_module = require(`${module_path}/fs_module`);
|
|
12
|
+
const db_module = require(`${module_path}/db_module`);
|
|
13
|
+
const misc_module = require(`${module_path}/misc_module`);
|
|
14
|
+
////////////////////////////////////////////
|
|
15
|
+
|
|
16
|
+
const rimraf = require('rimraf');
|
|
17
|
+
const fse = require('fs-extra');
|
|
18
|
+
// const crypto = require('node:crypto');
|
|
19
|
+
const unzipper = require('unzipper');
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const tesseract = require('node-tesseract-ocr');
|
|
22
|
+
const countryLanguage = require('country-language');
|
|
23
|
+
const url = require('url');
|
|
24
|
+
|
|
25
|
+
////////////////////////////////////////////
|
|
26
|
+
|
|
27
|
+
[
|
|
28
|
+
'get_drive_files',
|
|
29
|
+
'get_drive_file_info',
|
|
30
|
+
'delete_drive_files',
|
|
31
|
+
'extract_drive_file',
|
|
32
|
+
'upload_drive_file',
|
|
33
|
+
'update_drive_file',
|
|
34
|
+
'create_drive_folder',
|
|
35
|
+
'rename_drive_file',
|
|
36
|
+
'rename_drive_folder',
|
|
37
|
+
'update_drive_file_sharing_mode',
|
|
38
|
+
'delete_file_bulk',
|
|
39
|
+
'check_drive_file',
|
|
40
|
+
'update_drive_file_tags',
|
|
41
|
+
'update_drive_addons',
|
|
42
|
+
].forEach((method) => {
|
|
43
|
+
['workspace', 'studio', 'user'].forEach((type) => {
|
|
44
|
+
module.exports[method + '_' + type] = async function (req, job_id, headers, file_obj) {
|
|
45
|
+
req.drive_type = type;
|
|
46
|
+
|
|
47
|
+
//// TBD
|
|
48
|
+
// if (type === 'workspace' && !['get_drive_files', 'get_drive_file_info', 'check_drive_file'].includes(method)) {
|
|
49
|
+
// const { data: app_obj } = await db_module.get_app_obj(req.app_id);
|
|
50
|
+
// if (app_obj.app_type === 'datacenter') {
|
|
51
|
+
// const deploy_module = require(`${module_path}/deploy_module`);
|
|
52
|
+
// deploy_module.reset_deployment_cache(app_obj._id);
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
55
|
+
|
|
56
|
+
return await module.exports[method](req, job_id, headers, file_obj);
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const get_studio_path = function (raw_path, ref, file_name) {
|
|
62
|
+
return raw_path.replaceAll(path.join(_conf.studio_drive_path, ref), '').replaceAll('/' + file_name, '') || '/';
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
exports.get_drive_files = async function (req) {
|
|
66
|
+
try {
|
|
67
|
+
const { from = 0, to = 99999, drive_type, app_id, uid, type, date, search_string, sort_by = 'name', sort_dir = 'desc' } = req;
|
|
68
|
+
|
|
69
|
+
let { tags = [] } = req;
|
|
70
|
+
|
|
71
|
+
if (!['asc', 'desc'].includes(sort_dir)) {
|
|
72
|
+
throw 'invalid value for sort_dir (asc/desc)';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let tags_query = {};
|
|
76
|
+
const sort_by_obj = {
|
|
77
|
+
name: [type === 'file' ? 'originalname' : 'folder_name'],
|
|
78
|
+
date: ['date_modified'],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (!sort_by_obj[sort_by]) {
|
|
82
|
+
throw 'invalid value for sort_by value';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let sort = [];
|
|
86
|
+
for (item of sort_by_obj[sort_by]) {
|
|
87
|
+
sort.push({ [item]: sort_dir });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let opt = {
|
|
91
|
+
selector: {
|
|
92
|
+
docType: `${drive_type}_drive`,
|
|
93
|
+
stat: 3,
|
|
94
|
+
type,
|
|
95
|
+
},
|
|
96
|
+
limit: to - from,
|
|
97
|
+
skip: from,
|
|
98
|
+
sort,
|
|
99
|
+
// sort: [{ [sort_by_obj[sort_by]]: sort_dir }],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (req.path) {
|
|
103
|
+
opt.selector.file_path = req.path;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (search_string) {
|
|
107
|
+
let mix_conditions;
|
|
108
|
+
tags_query = search_string
|
|
109
|
+
.split(' ')
|
|
110
|
+
.filter((e) => e.includes(':'))
|
|
111
|
+
.reduce(
|
|
112
|
+
(ret, val) => {
|
|
113
|
+
var tagKey = val.split(':')[0];
|
|
114
|
+
var tagVal = val.split(':')[1];
|
|
115
|
+
|
|
116
|
+
if (tagKey === 'tag') {
|
|
117
|
+
tags.push(tagVal);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
mix_conditions = true;
|
|
121
|
+
if (tagKey === 'name') {
|
|
122
|
+
ret.$or.push({ originalname: { $regex: `(?i)${tagVal}` } });
|
|
123
|
+
}
|
|
124
|
+
if (tagKey === 'mime') {
|
|
125
|
+
ret.$or.push({ mime: { $regex: `(?i)${tagVal}` } });
|
|
126
|
+
}
|
|
127
|
+
if (tagKey === 'ext') {
|
|
128
|
+
ret.$or.push({ file_ext: { $regex: `(?i)${tagVal}` } });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return ret;
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
$or: [],
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
var new_search = search_string
|
|
139
|
+
.split(' ')
|
|
140
|
+
.filter((e) => !e.includes(':'))
|
|
141
|
+
.filter((e) => e)
|
|
142
|
+
.join(' ');
|
|
143
|
+
|
|
144
|
+
if (new_search) {
|
|
145
|
+
opt.selector = {
|
|
146
|
+
...opt.selector,
|
|
147
|
+
...{
|
|
148
|
+
$or: [
|
|
149
|
+
{
|
|
150
|
+
ocr: {
|
|
151
|
+
$regex: `(?i)${new_search}`,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
originalname: {
|
|
156
|
+
$regex: `(?i)${new_search}`,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (mix_conditions) {
|
|
165
|
+
if (new_search) {
|
|
166
|
+
tags_query.$or = [
|
|
167
|
+
...tags_query.$or,
|
|
168
|
+
{
|
|
169
|
+
ocr: {
|
|
170
|
+
$regex: `(?i)${new_search}`,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
originalname: {
|
|
175
|
+
$regex: `(?i)${new_search}`,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
opt.selector = { ...opt.selector, ...tags_query };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (tags?.length) {
|
|
185
|
+
opt.selector.tags = {
|
|
186
|
+
$all: tags,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
validate_drive_type(drive_type);
|
|
191
|
+
|
|
192
|
+
function formatBytes(bytes) {
|
|
193
|
+
if (bytes < 1024) return bytes + ' Bytes';
|
|
194
|
+
else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + ' KB';
|
|
195
|
+
else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + ' MB';
|
|
196
|
+
else return (bytes / 1073741824).toFixed(2) + ' GB';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const fetch_drive_files = async function (ret, file_doc, app_id_reference, uid, datasource_id, domain = process.env.XUDA_HOSTNAME, app_obj) {
|
|
200
|
+
let files = {
|
|
201
|
+
path: req.path || '/',
|
|
202
|
+
name: file_doc?.data?.folder_name || '/',
|
|
203
|
+
file_path: req.path || '/',
|
|
204
|
+
sizeInBytes: 0,
|
|
205
|
+
children: [],
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
for await (let doc of ret.docs) {
|
|
209
|
+
if (doc.type === 'file') {
|
|
210
|
+
let ts = '';
|
|
211
|
+
if (doc.date_modified && Date.now() - doc.date_modified < 4320 * 1000) {
|
|
212
|
+
ts = '?ts=' + Date.now();
|
|
213
|
+
} else if (app_obj?.app_build_id) {
|
|
214
|
+
ts = '?ts=' + app_obj?.app_build_id;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
files.sizeInBytes += doc.size;
|
|
219
|
+
files.children.push({
|
|
220
|
+
name: doc.originalname,
|
|
221
|
+
sizeInBytes: doc.size,
|
|
222
|
+
size: formatBytes(doc.size),
|
|
223
|
+
extension: doc?.file_ext?.substr(1),
|
|
224
|
+
type: doc.type,
|
|
225
|
+
access_link: `https://${domain}/${drive_type}-drive/${datasource_id || app_id}/${doc._id}${ts}`,
|
|
226
|
+
is_archive: doc.is_archive,
|
|
227
|
+
public: doc.public,
|
|
228
|
+
path: doc.file_path,
|
|
229
|
+
date_created: doc.date_created,
|
|
230
|
+
date_modified: doc.date_modified,
|
|
231
|
+
file_path: path.join(doc.file_path, doc.originalname),
|
|
232
|
+
tags: doc.tags || [],
|
|
233
|
+
});
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error(err.message);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (doc.type === 'directory') {
|
|
239
|
+
try {
|
|
240
|
+
const sizeInBytes = await get_folder_size(req.path, drive_type, app_id_reference, uid);
|
|
241
|
+
files.sizeInBytes += sizeInBytes;
|
|
242
|
+
files.children.push({
|
|
243
|
+
sizeInBytes,
|
|
244
|
+
size: formatBytes(sizeInBytes),
|
|
245
|
+
name: doc.folder_name,
|
|
246
|
+
path: '/' + doc._id,
|
|
247
|
+
file_path: '/' + doc._id,
|
|
248
|
+
type: doc.type,
|
|
249
|
+
is_folder: true,
|
|
250
|
+
date_created: doc.date_created,
|
|
251
|
+
tags: doc.tags || [],
|
|
252
|
+
});
|
|
253
|
+
} catch (err) {
|
|
254
|
+
console.error(err.message);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
files.size = formatBytes(files.sizeInBytes);
|
|
259
|
+
|
|
260
|
+
return files;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const get_workspace_files = async function () {
|
|
264
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
265
|
+
opt.selector.docType = 'workspace_drive';
|
|
266
|
+
|
|
267
|
+
const ret = await db_module.find_app_couch_query(app_id, opt);
|
|
268
|
+
|
|
269
|
+
const file_doc = await db_module.get_app_couch_doc(app_id, path.basename(req.path) || '/');
|
|
270
|
+
|
|
271
|
+
const { data: app_obj } = await db_module.get_app_obj(app_id);
|
|
272
|
+
|
|
273
|
+
const ret_fetch_drive_files = await fetch_drive_files(ret, file_doc, app_id_reference, null, app_obj.app_datacenter_id, app_obj.is_deployment ? app_obj.app_access_url : undefined, app_obj);
|
|
274
|
+
return {
|
|
275
|
+
code: 1,
|
|
276
|
+
data: ret_fetch_drive_files,
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
const get_user_files = async function () {
|
|
280
|
+
opt.selector.docType = 'user_drive';
|
|
281
|
+
opt.selector.uid = uid;
|
|
282
|
+
const ret = await db_module.find_couch_query('xuda_drive', opt);
|
|
283
|
+
const file_doc = await db_module.get_couch_doc('xuda_drive', path.basename(req.path) || '/');
|
|
284
|
+
return {
|
|
285
|
+
code: 1,
|
|
286
|
+
data: await fetch_drive_files(ret, file_doc, null, uid),
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
const get_studio_files = async function () {
|
|
290
|
+
if (search_string) {
|
|
291
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
292
|
+
opt.selector.docType = 'studio_drive';
|
|
293
|
+
const ret = await db_module.find_app_couch_query(app_id, opt);
|
|
294
|
+
|
|
295
|
+
const file_doc = await db_module.get_app_couch_doc(app_id, path.basename(req.path) || '/');
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
code: 1,
|
|
299
|
+
data: await fetch_drive_files(ret, file_doc, app_id_reference, null),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
304
|
+
|
|
305
|
+
var directoryPath = path.join(_conf.studio_drive_path, app_id_master, req.path || '/');
|
|
306
|
+
// var directoryPath =
|
|
307
|
+
// req.path !== "/"
|
|
308
|
+
// ? req.path || "/"
|
|
309
|
+
// : path.join(_conf.studio_drive_path, app_id_master);
|
|
310
|
+
|
|
311
|
+
const options = {
|
|
312
|
+
stat: true,
|
|
313
|
+
|
|
314
|
+
symbolicLinks: false,
|
|
315
|
+
size: true,
|
|
316
|
+
hash: false,
|
|
317
|
+
depth: 1,
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
if (!(await file_exists(directoryPath))) {
|
|
321
|
+
await create_directory(directoryPath, 0o775, true);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const dree_ret = await fs_module.dree_scan(directoryPath, options);
|
|
325
|
+
|
|
326
|
+
var tree = dree_ret.data; // dree.scan(directoryPath, options);
|
|
327
|
+
|
|
328
|
+
const rep = async function (file_path, type) {
|
|
329
|
+
file_path = file_path.replace(`${_conf.studio_drive_path}/${app_id_master}/`, '');
|
|
330
|
+
|
|
331
|
+
return `https://${process.env.XUDA_HOSTNAME}/studio-drive/${app_id_master}/${file_path}`;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const drill = async function (node) {
|
|
335
|
+
var i = 0;
|
|
336
|
+
var values_to_delete = [];
|
|
337
|
+
|
|
338
|
+
for await (var val of node) {
|
|
339
|
+
i++;
|
|
340
|
+
// filter by file type
|
|
341
|
+
if (type && type.toLowerCase() !== val.type.toLowerCase()) {
|
|
342
|
+
values_to_delete.push(i - 1);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const internal_path = val.path;
|
|
347
|
+
const directory_path = get_studio_path(val.path, app_id_master, val.relativePath);
|
|
348
|
+
const file_path = path.join(directory_path, val.name);
|
|
349
|
+
|
|
350
|
+
let ret = await db_module.get_app_couch_doc(app_id_master, file_path);
|
|
351
|
+
|
|
352
|
+
if (ret.code > -1) {
|
|
353
|
+
if (val.type === 'file') {
|
|
354
|
+
val.cy_data = ret.data;
|
|
355
|
+
|
|
356
|
+
val.access_link = await rep(internal_path, drive_type);
|
|
357
|
+
}
|
|
358
|
+
if (val.type === 'directory') {
|
|
359
|
+
val.name = ret.data.folder_name;
|
|
360
|
+
val.sizeInBytes = await get_folder_size(internal_path, drive_type, app_id_master);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
delete ret.data._id;
|
|
364
|
+
delete ret.data._rev;
|
|
365
|
+
|
|
366
|
+
delete ret.data.docType;
|
|
367
|
+
delete ret.data.stat;
|
|
368
|
+
} else {
|
|
369
|
+
if (val.type === 'directory') {
|
|
370
|
+
val.sizeInBytes = await get_folder_size(internal_path, drive_type, app_id_master);
|
|
371
|
+
}
|
|
372
|
+
// supports file uploaded directly to the server
|
|
373
|
+
val.access_link = await rep(val.path, 'studio'); //+ "?r=" + Date.now();
|
|
374
|
+
}
|
|
375
|
+
val.date_created = new Date(val.stat.birthtime).valueOf();
|
|
376
|
+
delete val.stat;
|
|
377
|
+
|
|
378
|
+
val.path = directory_path; // get_studio_path(val.path, app_id_master, val.relativePath);
|
|
379
|
+
val.file_path = file_path; // path.join(val.path, val.name);
|
|
380
|
+
val.tags = ret?.data?.tags || [];
|
|
381
|
+
}
|
|
382
|
+
for await (var index of values_to_delete.reverse()) {
|
|
383
|
+
node.splice(index, 1);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
if (tree?.children) {
|
|
388
|
+
if (type === 'file') {
|
|
389
|
+
tree.children = tree.children.filter((e) => e.type === type).slice(from, to + 1);
|
|
390
|
+
}
|
|
391
|
+
await drill(tree.children);
|
|
392
|
+
} else {
|
|
393
|
+
tree = {
|
|
394
|
+
children: [],
|
|
395
|
+
name: tree?.name,
|
|
396
|
+
size: 0,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
tree.path = get_studio_path(tree.path || tree.name, app_id_master, tree?.name || '');
|
|
401
|
+
tree.file_path = path.join(tree.path, tree.name);
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
code: 200,
|
|
405
|
+
data: tree,
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
switch (drive_type) {
|
|
410
|
+
case 'studio':
|
|
411
|
+
return get_studio_files();
|
|
412
|
+
|
|
413
|
+
case 'workspace':
|
|
414
|
+
return get_workspace_files();
|
|
415
|
+
|
|
416
|
+
case 'user':
|
|
417
|
+
return get_user_files();
|
|
418
|
+
|
|
419
|
+
default:
|
|
420
|
+
throw new Error('drive_type error');
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
// return err.message;
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
code: -1,
|
|
427
|
+
data: err.message,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
exports.get_drive_file_info = async function (req, job_id, headers) {
|
|
433
|
+
try {
|
|
434
|
+
const { type, drive_type, uid, app_id, file_path } = req;
|
|
435
|
+
|
|
436
|
+
let doc = await get_drive_doc(type, drive_type, app_id, uid, file_path, headers);
|
|
437
|
+
|
|
438
|
+
delete doc._id;
|
|
439
|
+
delete doc._rev;
|
|
440
|
+
|
|
441
|
+
delete doc.docType;
|
|
442
|
+
delete doc.stat;
|
|
443
|
+
if (doc.bucket) {
|
|
444
|
+
doc.regions = Object.entries(doc.bucket).length;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
delete doc.bucket;
|
|
448
|
+
|
|
449
|
+
if (doc.uid) {
|
|
450
|
+
let ret = await db_module.get_couch_doc('xuda_accounts', doc.uid);
|
|
451
|
+
doc.account_info = ret.data.account_info;
|
|
452
|
+
}
|
|
453
|
+
if (req.drive_type === 'workspace') {
|
|
454
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
455
|
+
const ret = await db_module.get_app_obj(app_id_master);
|
|
456
|
+
|
|
457
|
+
if (ret.code < 0) {
|
|
458
|
+
return ret;
|
|
459
|
+
}
|
|
460
|
+
const app_obj = ret.data;
|
|
461
|
+
doc.app_name = app_obj.app_name;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
code: 200,
|
|
466
|
+
data: {
|
|
467
|
+
name: doc.originalname,
|
|
468
|
+
cy_data: doc,
|
|
469
|
+
exif_data: doc.exif_data,
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
} catch (err) {
|
|
473
|
+
return {
|
|
474
|
+
code: -200,
|
|
475
|
+
data: err.message,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
exports.delete_drive_files = async function (req, job_id, headers) {
|
|
481
|
+
try {
|
|
482
|
+
const { drive_type, app_id, files_arr, uid } = req;
|
|
483
|
+
validate_drive_type(drive_type);
|
|
484
|
+
|
|
485
|
+
if (!Array.isArray(files_arr)) {
|
|
486
|
+
return {
|
|
487
|
+
code: -400,
|
|
488
|
+
data: 'error - files_arr must be Array',
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
for await (const file of files_arr) {
|
|
493
|
+
let doc = await get_drive_doc('file', drive_type, app_id, uid, file.file_path, headers);
|
|
494
|
+
|
|
495
|
+
switch (drive_type) {
|
|
496
|
+
case 'studio': {
|
|
497
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
498
|
+
const target_dir = path.join(_conf[`studio_drive_path`], app_id_reference, file.file_path);
|
|
499
|
+
console.log('target_dir', target_dir);
|
|
500
|
+
const ret = rimraf.sync(target_dir); // delete the file
|
|
501
|
+
|
|
502
|
+
if (doc.type === 'file') {
|
|
503
|
+
doc.ts = Date.now();
|
|
504
|
+
doc.stat = 4;
|
|
505
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id_reference);
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
case 'workspace': {
|
|
513
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
514
|
+
|
|
515
|
+
if (doc.type === 'file') {
|
|
516
|
+
if (doc.bucket) {
|
|
517
|
+
await module.exports.delete_file_from_bucket(doc.bucket);
|
|
518
|
+
} else {
|
|
519
|
+
const { data: app_obj } = await db_module.get_app_obj(app_id);
|
|
520
|
+
if (app_obj?.app_type === 'datacenter') {
|
|
521
|
+
const host = `root@${app_obj.app_hosting_server.ip}`;
|
|
522
|
+
await _utils.run_ssh_script(`ssh rm ${host}:/var/xuda/workspace_drive/${file_name}; `);
|
|
523
|
+
} else if (app_obj?.is_deployment) {
|
|
524
|
+
const { data: datacenter_obj } = await db_module.get_app_obj(app_obj.app_datacenter_id);
|
|
525
|
+
const host = `root@${datacenter_obj.app_hosting_server.ip}`;
|
|
526
|
+
await _utils.run_ssh_script(`ssh rm ${host}:/var/xuda/workspace_drive/${file_name}; `);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
doc.ts = Date.now();
|
|
532
|
+
doc.stat = 4;
|
|
533
|
+
save_ret = await save_drive_doc(drive_type, app_id, doc);
|
|
534
|
+
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
case 'user': {
|
|
539
|
+
if (doc.type === 'file') {
|
|
540
|
+
await module.exports.delete_file_from_bucket(doc.bucket);
|
|
541
|
+
}
|
|
542
|
+
doc.ts = Date.now();
|
|
543
|
+
doc.stat = 4;
|
|
544
|
+
save_ret = await save_drive_doc(drive_type, app_id, doc);
|
|
545
|
+
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
default:
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// switch (drive_type) {
|
|
554
|
+
// case 'workspace': {
|
|
555
|
+
// const app_id_reference = await _common.get_project_app_id(app_id);
|
|
556
|
+
// misc_module.rsync_drive_resources_to_remote_servers('workspace', app_id_reference);
|
|
557
|
+
// break;
|
|
558
|
+
// }
|
|
559
|
+
// case 'user': {
|
|
560
|
+
// misc_module.rsync_drive_resources_to_remote_servers('user', uid);
|
|
561
|
+
// break;
|
|
562
|
+
// }
|
|
563
|
+
// default:
|
|
564
|
+
// break;
|
|
565
|
+
// }
|
|
566
|
+
|
|
567
|
+
return {
|
|
568
|
+
code: 200,
|
|
569
|
+
data: req.files_arr,
|
|
570
|
+
};
|
|
571
|
+
} catch (err) {
|
|
572
|
+
return { code: -1, data: err.message };
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
exports.update_drive_file = async function (req, job_id, headers, file_obj) {
|
|
577
|
+
try {
|
|
578
|
+
const { drive_type, app_id, file_path, uid } = req;
|
|
579
|
+
validate_drive_type(drive_type);
|
|
580
|
+
|
|
581
|
+
const originalname = file_obj?.['originalname'];
|
|
582
|
+
|
|
583
|
+
const file_name = path.basename(file_path);
|
|
584
|
+
|
|
585
|
+
if (!originalname) {
|
|
586
|
+
return { code: -4, data: 'file data missing' };
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
let doc = await get_drive_doc('file', drive_type, app_id, uid, file_path, headers);
|
|
590
|
+
|
|
591
|
+
var target_file = file_path;
|
|
592
|
+
const master_id = await _common.get_project_app_id(app_id, true);
|
|
593
|
+
const tempPath = file_obj.path;
|
|
594
|
+
if (drive_type === 'studio') {
|
|
595
|
+
const target_dir = path.join(_conf[`studio_drive_path`], master_id, file_path);
|
|
596
|
+
try {
|
|
597
|
+
fse.unlinkSync(target_dir);
|
|
598
|
+
} catch (error) {}
|
|
599
|
+
|
|
600
|
+
fse.copyFileSync(tempPath, target_dir);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
doc.date_modified = Date.now();
|
|
604
|
+
|
|
605
|
+
const fs = require('fs').promises;
|
|
606
|
+
const stat = await fs.stat(tempPath);
|
|
607
|
+
if (stat.isFile()) {
|
|
608
|
+
doc.size = stat.size;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
doc = { ...doc, ...(await get_file_info(tempPath)) };
|
|
612
|
+
|
|
613
|
+
let save_ret;
|
|
614
|
+
let ref;
|
|
615
|
+
switch (drive_type) {
|
|
616
|
+
case 'studio': {
|
|
617
|
+
ref = await _common.get_project_app_id(app_id, true);
|
|
618
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
619
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
620
|
+
|
|
621
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id_reference);
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
case 'workspace': {
|
|
625
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
626
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
627
|
+
ref = app_id_master;
|
|
628
|
+
|
|
629
|
+
const { data: app_obj } = await db_module.get_app_obj(app_id);
|
|
630
|
+
if (app_obj?.app_type === 'datacenter') {
|
|
631
|
+
const host = `root@${app_obj.app_hosting_server.ip}`;
|
|
632
|
+
await _utils.run_ssh_script(`scp ${tempPath} ${host}:/var/xuda/workspace_drive/${doc.server_file_name}; `);
|
|
633
|
+
} else if (app_obj?.is_deployment) {
|
|
634
|
+
const { data: datacenter_obj } = await db_module.get_app_obj(app_obj.app_datacenter_id);
|
|
635
|
+
const host = `root@${datacenter_obj.app_hosting_server.ip}`;
|
|
636
|
+
await _utils.run_ssh_script(`scp ${tempPath} ${host}:/var/xuda/workspace_drive/${doc.server_file_name}; `);
|
|
637
|
+
} else {
|
|
638
|
+
doc.bucket[`${process.env.XUDA_HOSTNAME}`] = await upload_file_to_spaces(tempPath, app_id_master, drive_type, doc.server_file_name);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
642
|
+
// misc_module.rsync_drive_resources_to_remote_servers('workspace', app_id_master);
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
case 'user': {
|
|
646
|
+
ref = uid;
|
|
647
|
+
doc.bucket[`${process.env.XUDA_HOSTNAME}`] = await upload_file_to_spaces(tempPath, uid, drive_type, file_name);
|
|
648
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
649
|
+
// misc_module.rsync_drive_resources_to_remote_servers('user', doc.uid);
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
default:
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
fse.unlinkSync(tempPath);
|
|
657
|
+
|
|
658
|
+
if (save_ret.code < 0) {
|
|
659
|
+
return save_ret;
|
|
660
|
+
}
|
|
661
|
+
const server_file_name = `https://${process.env.XUDA_HOSTNAME}/${drive_type}-drive${drive_type === 'studio' ? `/${master_id}/${target_file}` : file_name}`;
|
|
662
|
+
|
|
663
|
+
let file_url = get_file_url(drive_type, file_name, ref);
|
|
664
|
+
|
|
665
|
+
// misc_module.purge_cloudflare_cache(false, server_file_name);
|
|
666
|
+
return {
|
|
667
|
+
code: 760,
|
|
668
|
+
data: {
|
|
669
|
+
server_file_name,
|
|
670
|
+
filename: file_obj.originalname,
|
|
671
|
+
file_url,
|
|
672
|
+
},
|
|
673
|
+
};
|
|
674
|
+
} catch (err) {
|
|
675
|
+
return { code: -400, data: err };
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
exports.create_drive_folder = async function (req, job_id, headers) {
|
|
680
|
+
try {
|
|
681
|
+
const { drive_type, app_id, folder_name, uid } = req;
|
|
682
|
+
validate_drive_type(drive_type);
|
|
683
|
+
|
|
684
|
+
var folder_id;
|
|
685
|
+
var app_id_master;
|
|
686
|
+
var target_dir;
|
|
687
|
+
var folder_exist;
|
|
688
|
+
|
|
689
|
+
var doc = {
|
|
690
|
+
docType: `${drive_type}_drive`,
|
|
691
|
+
stat: 3,
|
|
692
|
+
folder_name,
|
|
693
|
+
uid,
|
|
694
|
+
date_created: Date.now(),
|
|
695
|
+
date_modified: 0,
|
|
696
|
+
ip: headers?.['cf-connecting-ip'],
|
|
697
|
+
country: headers?.['cf-ipcountry'],
|
|
698
|
+
is_folder: true,
|
|
699
|
+
type: 'directory',
|
|
700
|
+
file_path: req.path,
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
switch (drive_type) {
|
|
704
|
+
case 'studio': {
|
|
705
|
+
folder_id = req.folder_name;
|
|
706
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
707
|
+
if (!req.path.includes(app_id_master)) {
|
|
708
|
+
return {
|
|
709
|
+
code: -1,
|
|
710
|
+
data: 'error - file path unauthorized',
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
target_dir = req.path + '/' + folder_id;
|
|
714
|
+
folder_exist = await file_exists(target_dir);
|
|
715
|
+
if (folder_exist) {
|
|
716
|
+
throw new Error('folder exist');
|
|
717
|
+
}
|
|
718
|
+
await create_directory(target_dir, 0o775, true);
|
|
719
|
+
doc._id = folder_id;
|
|
720
|
+
save_ret = await db_module.save_app_couch_doc(app_id_master, doc);
|
|
721
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id_master);
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
case 'workspace': {
|
|
726
|
+
folder_id = 'drive_folder_' + _utils.UUID(); // crypto.randomUUID();
|
|
727
|
+
app_id_reference = await _common.get_project_app_id(app_id);
|
|
728
|
+
doc._id = folder_id;
|
|
729
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
case 'user': {
|
|
734
|
+
folder_id = 'drive_folder_' + _utils.UUID(); //crypto.randomUUID();
|
|
735
|
+
doc._id = folder_id;
|
|
736
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
default:
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (save_ret.code < 0) {
|
|
744
|
+
return save_ret;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return {
|
|
748
|
+
code: 200,
|
|
749
|
+
data: target_dir,
|
|
750
|
+
};
|
|
751
|
+
} catch (err) {
|
|
752
|
+
return {
|
|
753
|
+
code: -200,
|
|
754
|
+
data: err.message,
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
exports.rename_drive_file = async function (req, job_id, headers) {
|
|
759
|
+
try {
|
|
760
|
+
const { drive_type, app_id, file_name_to, file_path } = req;
|
|
761
|
+
validate_drive_type(drive_type);
|
|
762
|
+
|
|
763
|
+
let doc = await get_drive_doc('file', drive_type, app_id, uid, file_path, headers);
|
|
764
|
+
|
|
765
|
+
if (drive_type === 'studio') {
|
|
766
|
+
await fs_module.rename(file_path, file_name_to);
|
|
767
|
+
|
|
768
|
+
doc._delete = true;
|
|
769
|
+
await db_module.save_app_couch_doc(app_id_master, doc_ret.data);
|
|
770
|
+
|
|
771
|
+
doc._id = file_name_to;
|
|
772
|
+
delete doc._rev;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
doc.date_modified = Date.now();
|
|
776
|
+
doc.originalname = file_name_to;
|
|
777
|
+
let save_ret;
|
|
778
|
+
|
|
779
|
+
switch (drive_type) {
|
|
780
|
+
case 'workspace':
|
|
781
|
+
case 'studio':
|
|
782
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
783
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
784
|
+
break;
|
|
785
|
+
|
|
786
|
+
case 'user':
|
|
787
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
788
|
+
break;
|
|
789
|
+
|
|
790
|
+
default:
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (save_ret.code < 0) {
|
|
795
|
+
throw new Error(save_ret.data);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return {
|
|
799
|
+
code: 200,
|
|
800
|
+
data: file_name_to,
|
|
801
|
+
};
|
|
802
|
+
} catch (err) {
|
|
803
|
+
return {
|
|
804
|
+
code: -200,
|
|
805
|
+
data: err.message,
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
exports.rename_drive_folder = async function (req) {
|
|
810
|
+
try {
|
|
811
|
+
const { drive_type, app_id, curr_path, new_path } = req;
|
|
812
|
+
validate_drive_type(drive_type);
|
|
813
|
+
|
|
814
|
+
let doc_ret;
|
|
815
|
+
switch (drive_type) {
|
|
816
|
+
case 'studio': {
|
|
817
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
818
|
+
|
|
819
|
+
if (!new_path.includes(app_id_reference)) {
|
|
820
|
+
throw new Error('error - new_path unauthorized');
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
doc_ret = await db_module.get_app_couch_doc(app_id_reference, curr_path);
|
|
824
|
+
await fs_module.rename(curr_path, new_path);
|
|
825
|
+
doc_ret.data._delete = true;
|
|
826
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc_ret.data);
|
|
827
|
+
|
|
828
|
+
doc_ret.data._id = file_name_to;
|
|
829
|
+
delete doc_ret.data._rev;
|
|
830
|
+
|
|
831
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id_reference);
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
case 'workspace': {
|
|
835
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
836
|
+
doc_ret = await db_module.get_app_couch_doc(app_id_reference, curr_path);
|
|
837
|
+
if (doc_ret.code < 0) {
|
|
838
|
+
throw new Error(doc_ret.data);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
case 'user':
|
|
845
|
+
doc_ret = await db_module.get_couch_doc('xuda_drive', curr_path);
|
|
846
|
+
if (doc_ret.code < 0) {
|
|
847
|
+
throw new Error(doc_ret.data);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
break;
|
|
851
|
+
|
|
852
|
+
default:
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (doc_ret.code > -1) {
|
|
857
|
+
var doc = doc_ret.data;
|
|
858
|
+
doc.date_modified = Date.now();
|
|
859
|
+
doc.folder_name = new_path;
|
|
860
|
+
let save_ret;
|
|
861
|
+
|
|
862
|
+
switch (drive_type) {
|
|
863
|
+
case 'workspace':
|
|
864
|
+
case 'studio':
|
|
865
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
866
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
867
|
+
break;
|
|
868
|
+
|
|
869
|
+
case 'user':
|
|
870
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
871
|
+
break;
|
|
872
|
+
|
|
873
|
+
default:
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (save_ret.code < 0) {
|
|
878
|
+
throw new Error(save_ret.data);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
code: 200,
|
|
883
|
+
data: new_path,
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
// if (drive_type === "studio" || drive_type === "workspace") {
|
|
887
|
+
// const app_id_reference = await _common.get_project_app_id(app_id);
|
|
888
|
+
|
|
889
|
+
// if (!new_path.includes(app_id_reference)) {
|
|
890
|
+
// return {
|
|
891
|
+
// code: -1,
|
|
892
|
+
// data: "error - new_path unauthorized",
|
|
893
|
+
// };
|
|
894
|
+
// }
|
|
895
|
+
// }
|
|
896
|
+
|
|
897
|
+
// fse.renameSync(curr_path, new_path);
|
|
898
|
+
|
|
899
|
+
return {
|
|
900
|
+
code: 200,
|
|
901
|
+
data: new_path,
|
|
902
|
+
};
|
|
903
|
+
} catch (err) {
|
|
904
|
+
return err.message;
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
exports.update_drive_file_sharing_mode = async function (req, job_id, headers) {
|
|
908
|
+
try {
|
|
909
|
+
const { type, drive_type, uid, app_id, file_path, is_public } = req;
|
|
910
|
+
|
|
911
|
+
validate_drive_type(drive_type);
|
|
912
|
+
|
|
913
|
+
let doc = await get_drive_doc(type, drive_type, app_id, uid, file_path, headers);
|
|
914
|
+
|
|
915
|
+
doc.ts = Date.now();
|
|
916
|
+
doc.public = is_public;
|
|
917
|
+
|
|
918
|
+
return await save_drive_doc(drive_type, app_id, doc);
|
|
919
|
+
} catch (err) {
|
|
920
|
+
return err.message;
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
exports.extract_drive_file = async function (req, job_id, headers) {
|
|
925
|
+
const { app_id, file_path, uid } = req;
|
|
926
|
+
|
|
927
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
928
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
929
|
+
|
|
930
|
+
let doc = await get_drive_doc('file', drive_type, app_id, uid, file_path, headers);
|
|
931
|
+
|
|
932
|
+
const ext = path.extname(file_path).toLowerCase();
|
|
933
|
+
|
|
934
|
+
if (!_conf.archive_drive_ext.includes(ext)) {
|
|
935
|
+
throw new Error('error - invalid archive file');
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (!file_exists(req)) {
|
|
939
|
+
throw new Error('error - file not found');
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
try {
|
|
943
|
+
const extract_dir = path.dirname(file_path);
|
|
944
|
+
|
|
945
|
+
fs.createReadStream(file_path)
|
|
946
|
+
.pipe(unzipper.Parse())
|
|
947
|
+
.on('entry', async function (entry) {
|
|
948
|
+
const fileName = entry.path;
|
|
949
|
+
const type = entry.type;
|
|
950
|
+
const size = entry.vars.uncompressedSize; // There is also compressedSize;
|
|
951
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
952
|
+
|
|
953
|
+
if (fileName.startsWith('__MACOSX/')) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
// var file_id = path.join(path.dirname(file_path), fileName) + "1";
|
|
957
|
+
|
|
958
|
+
var new_file_id = path.basename(fileName);
|
|
959
|
+
|
|
960
|
+
if (doc.drive_type !== 'studio') {
|
|
961
|
+
new_file_id = 'drv_' + app_id_master + '_' + (await _common.xuda_get_uuid(doc.drive_type)) + ext;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// const folder_name = 'drive_folder_' + (doc.drive_type === 'studio' ? path.basename(fileName) : crypto.randomUUID());
|
|
965
|
+
const folder_name = 'drive_folder_' + (doc.drive_type === 'studio' ? path.basename(fileName) : _utils.UUID());
|
|
966
|
+
|
|
967
|
+
var dir = path.dirname(fileName);
|
|
968
|
+
if (dir && dir !== '.') {
|
|
969
|
+
dir = 'drive_folder_' + dir;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
const file_doc_id = type === 'Directory' ? folder_name : new_file_id;
|
|
973
|
+
const extract_path = path.join(extract_dir, dir, file_doc_id);
|
|
974
|
+
|
|
975
|
+
if (type === 'Directory') {
|
|
976
|
+
fs.mkdirSync(extract_path, { recursive: true });
|
|
977
|
+
} else {
|
|
978
|
+
entry.pipe(fs.createWriteStream(extract_path));
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// console.log(fileName, entry);
|
|
982
|
+
|
|
983
|
+
var file_doc = {
|
|
984
|
+
_id: file_doc_id,
|
|
985
|
+
|
|
986
|
+
docType: `${doc.drive_type}_drive`, //=== "studio" ? "upload" : "drive",
|
|
987
|
+
stat: 3,
|
|
988
|
+
server_file_name: file_doc_id,
|
|
989
|
+
type: type.toLowerCase(),
|
|
990
|
+
// originalname: type === "Directory" ? folder_name : new_file_id,
|
|
991
|
+
uid: uid,
|
|
992
|
+
app_id: app_id_reference,
|
|
993
|
+
app_id_reference: app_id_master,
|
|
994
|
+
date_created: Date.now(),
|
|
995
|
+
date_modified: 0,
|
|
996
|
+
ip: headers['cf-connecting-ip'],
|
|
997
|
+
country: headers['cf-ipcountry'],
|
|
998
|
+
file_ext: ext,
|
|
999
|
+
is_archive: _conf.archive_drive_ext.includes(ext) ? true : false,
|
|
1000
|
+
size,
|
|
1001
|
+
};
|
|
1002
|
+
if (type === 'Directory') {
|
|
1003
|
+
file_doc.folder_name = path.basename(fileName);
|
|
1004
|
+
} else {
|
|
1005
|
+
file_doc.originalname = new_file_id;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
try {
|
|
1009
|
+
await db_module.save_app_couch_doc(app_id_reference, file_doc);
|
|
1010
|
+
} catch (error) {}
|
|
1011
|
+
})
|
|
1012
|
+
.on('close', () => {
|
|
1013
|
+
console.log('Extraction complete.');
|
|
1014
|
+
})
|
|
1015
|
+
.on('error', (error) => {
|
|
1016
|
+
console.error('An error occurred:', error);
|
|
1017
|
+
});
|
|
1018
|
+
} catch (err) {
|
|
1019
|
+
return {
|
|
1020
|
+
code: -200,
|
|
1021
|
+
data: err.message,
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
return {
|
|
1026
|
+
code: 200,
|
|
1027
|
+
data: '',
|
|
1028
|
+
};
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
const file_exists = async function (file_path) {
|
|
1032
|
+
return await fs_module.file_exists(file_path);
|
|
1033
|
+
};
|
|
1034
|
+
const create_directory = async function (file_path, permission) {
|
|
1035
|
+
return await fs_module.mkdir(file_path, permission);
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
exports.delete_file_bulk = async function (req) {
|
|
1039
|
+
if (typeof req.server_files !== 'object') {
|
|
1040
|
+
return {
|
|
1041
|
+
code: -1,
|
|
1042
|
+
data: 'error - server_files must be defined as array',
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
for await (const val of req.server_files) {
|
|
1047
|
+
await fs_module.delete_file(req.app_id, val, req);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
return { code: 1, data: req.server_files };
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
exports.upload_drive_file = async function (req, job_id, headers, file_obj) {
|
|
1054
|
+
try {
|
|
1055
|
+
const { drive_type, app_id, uid, make_public, tags = '' } = req;
|
|
1056
|
+
|
|
1057
|
+
/// validations
|
|
1058
|
+
validate_drive_type(drive_type);
|
|
1059
|
+
if (!file_obj?.['originalname']) {
|
|
1060
|
+
throw new Error('file data missing');
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
const ext = path.extname(file_obj.originalname).toLowerCase();
|
|
1064
|
+
let originalname = path.basename(file_obj.originalname);
|
|
1065
|
+
const tempPath = file_obj.path;
|
|
1066
|
+
|
|
1067
|
+
if (![..._conf.allowedExts_drive, ..._conf.archive_drive_ext].includes(ext)) {
|
|
1068
|
+
await fs_module.unlink(tempPath);
|
|
1069
|
+
throw new Error(`Only ${_conf.allowedExts_drive.toString()} files are allowed!`);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
let ref, file_name, target_file, save_ret;
|
|
1073
|
+
|
|
1074
|
+
const fs = require('fs').promises;
|
|
1075
|
+
const stat = await fs.stat(tempPath);
|
|
1076
|
+
|
|
1077
|
+
let tags_arr = [];
|
|
1078
|
+
try {
|
|
1079
|
+
if (tags) tags_arr = tags.split(',');
|
|
1080
|
+
} catch (error) {}
|
|
1081
|
+
const ts = Date.now();
|
|
1082
|
+
var doc = {
|
|
1083
|
+
docType: `${drive_type}_drive`,
|
|
1084
|
+
stat: 3,
|
|
1085
|
+
originalname,
|
|
1086
|
+
uid,
|
|
1087
|
+
type: 'file',
|
|
1088
|
+
date_created: ts,
|
|
1089
|
+
date_modified: ts,
|
|
1090
|
+
ip: headers['cf-connecting-ip'],
|
|
1091
|
+
country: headers['cf-ipcountry'],
|
|
1092
|
+
file_ext: ext,
|
|
1093
|
+
is_archive: _conf.archive_drive_ext.includes(ext) ? true : false,
|
|
1094
|
+
drive_type,
|
|
1095
|
+
mime: file_obj.mimetype,
|
|
1096
|
+
ocr_stat: ['image', 'application', 'text'].includes(file_obj.mimetype.split('/')[0]) ? 1 : 0,
|
|
1097
|
+
target_file,
|
|
1098
|
+
file_path: req.path || '/',
|
|
1099
|
+
size: stat.isFile() ? stat.size : 0,
|
|
1100
|
+
public: make_public,
|
|
1101
|
+
tags: tags_arr,
|
|
1102
|
+
};
|
|
1103
|
+
doc = { ...doc, ...(await get_file_info(tempPath)) };
|
|
1104
|
+
|
|
1105
|
+
let check_req = {
|
|
1106
|
+
app_id,
|
|
1107
|
+
uid,
|
|
1108
|
+
drive_type,
|
|
1109
|
+
file_path: path.join(doc.file_path, originalname),
|
|
1110
|
+
type: 'file',
|
|
1111
|
+
};
|
|
1112
|
+
const check_existing_file_ret = await module.exports.check_drive_file(check_req);
|
|
1113
|
+
|
|
1114
|
+
if (check_existing_file_ret.code < 0) {
|
|
1115
|
+
// const rename_file_name = async function (i) {
|
|
1116
|
+
// if (i > 1000) {
|
|
1117
|
+
// return { code: -1, data: 'too many retries renaming existing file' };
|
|
1118
|
+
// }
|
|
1119
|
+
|
|
1120
|
+
// let tmp_originalname = originalname + ` (${i})`;
|
|
1121
|
+
|
|
1122
|
+
// // check_req.file_name = tmp_originalname;
|
|
1123
|
+
// check_req.file_path = path.join(doc.file_path, tmp_originalname);
|
|
1124
|
+
|
|
1125
|
+
// const re_check_res = await module.exports.check_drive_file(check_req);
|
|
1126
|
+
// if (re_check_res.code < 0) {
|
|
1127
|
+
// i++;
|
|
1128
|
+
// return await rename_file_name(i);
|
|
1129
|
+
// }
|
|
1130
|
+
// return { code: 1, data: tmp_originalname };
|
|
1131
|
+
// };
|
|
1132
|
+
|
|
1133
|
+
const rename_file_name = async function (i) {
|
|
1134
|
+
if (i > 1000) {
|
|
1135
|
+
return { code: -1, data: 'too many retries renaming existing file' };
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Extract filename parts
|
|
1139
|
+
const parsed = path.parse(originalname);
|
|
1140
|
+
const baseName = parsed.name; // filename without extension
|
|
1141
|
+
const extension = parsed.ext; // .webp, .jpg, etc.
|
|
1142
|
+
|
|
1143
|
+
// Insert (i) before the extension
|
|
1144
|
+
let tmp_originalname = `${baseName} (${i})${extension}`;
|
|
1145
|
+
|
|
1146
|
+
check_req.file_path = path.join(doc.file_path, tmp_originalname);
|
|
1147
|
+
|
|
1148
|
+
const re_check_res = await module.exports.check_drive_file(check_req);
|
|
1149
|
+
if (re_check_res.code < 0) {
|
|
1150
|
+
return await rename_file_name(i + 1);
|
|
1151
|
+
}
|
|
1152
|
+
return { code: 1, data: tmp_originalname };
|
|
1153
|
+
};
|
|
1154
|
+
const rename_ret = await rename_file_name(1);
|
|
1155
|
+
if (rename_ret.code < 0) {
|
|
1156
|
+
return rename_ret;
|
|
1157
|
+
}
|
|
1158
|
+
doc.originalname = rename_ret.data;
|
|
1159
|
+
originalname = rename_ret.data;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
switch (drive_type) {
|
|
1163
|
+
case 'studio': {
|
|
1164
|
+
ref = await _common.get_project_app_id(req.app_id, true);
|
|
1165
|
+
const target_dir = path.join(_conf[`studio_drive_path`], ref);
|
|
1166
|
+
// file_name = path.join(req.path, file_obj.originalname);
|
|
1167
|
+
file_name = path.join(req.path, doc.originalname);
|
|
1168
|
+
|
|
1169
|
+
target_file = path.join(target_dir, file_name);
|
|
1170
|
+
|
|
1171
|
+
if (!(await fs_module.file_exists(target_dir))) {
|
|
1172
|
+
await fs_module.mkdir(target_dir, 0o775, true);
|
|
1173
|
+
}
|
|
1174
|
+
if (await fs_module.file_exists(target_file)) {
|
|
1175
|
+
return {
|
|
1176
|
+
code: -762,
|
|
1177
|
+
data: 'file already exist',
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
await fs_module.copy(tempPath, target_file);
|
|
1182
|
+
doc.server_file_name = file_name;
|
|
1183
|
+
|
|
1184
|
+
doc.app_id = app_id;
|
|
1185
|
+
doc.app_id_reference = ref;
|
|
1186
|
+
|
|
1187
|
+
doc._id = file_name;
|
|
1188
|
+
|
|
1189
|
+
save_ret = await db_module.save_app_couch_doc(ref, doc);
|
|
1190
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id);
|
|
1191
|
+
break;
|
|
1192
|
+
}
|
|
1193
|
+
case 'workspace': {
|
|
1194
|
+
debugger;
|
|
1195
|
+
ref = await _common.get_project_app_id(req.app_id, true);
|
|
1196
|
+
file_name = 'drv_' + ref + '_' + (await _common.xuda_get_uuid(drive_type)) + ext;
|
|
1197
|
+
|
|
1198
|
+
// keep the original filename to support migration
|
|
1199
|
+
if (file_obj.originalname.includes(`drv_${ref}`)) {
|
|
1200
|
+
file_name = file_obj.originalname;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
doc.server_file_name = file_name;
|
|
1204
|
+
|
|
1205
|
+
doc.app_id = app_id;
|
|
1206
|
+
doc.app_id_reference = ref;
|
|
1207
|
+
|
|
1208
|
+
// if file uploaded from deployment or from datacenter then save to the datacenter server fs
|
|
1209
|
+
const { data: app_obj } = await db_module.get_app_obj(app_id);
|
|
1210
|
+
if (app_obj?.app_type === 'datacenter') {
|
|
1211
|
+
const host = `root@${app_obj.app_hosting_server.ip}`;
|
|
1212
|
+
await _utils.run_ssh_script(`scp ${tempPath} ${host}:/var/xuda/workspace_drive/${file_name}; `);
|
|
1213
|
+
} else if (app_obj?.is_deployment) {
|
|
1214
|
+
const { data: datacenter_obj } = await db_module.get_app_obj(app_obj.app_datacenter_id);
|
|
1215
|
+
const host = `root@${datacenter_obj.app_hosting_server.ip}`;
|
|
1216
|
+
await _utils.run_ssh_script(`scp ${tempPath} ${host}:/var/xuda/workspace_drive/${file_name}; `);
|
|
1217
|
+
} else {
|
|
1218
|
+
doc.bucket = {
|
|
1219
|
+
[`${process.env.XUDA_HOSTNAME}`]: await upload_file_to_spaces(tempPath, ref, drive_type, file_name),
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
doc._id = file_name;
|
|
1223
|
+
save_ret = await db_module.save_app_couch_doc(await _common.get_project_app_id(req.app_id), doc);
|
|
1224
|
+
// misc_module.rsync_drive_resources_to_remote_servers('workspace', app_id);
|
|
1225
|
+
break;
|
|
1226
|
+
}
|
|
1227
|
+
case 'user': {
|
|
1228
|
+
// /// check existing file
|
|
1229
|
+
// const user_drive_res = await db_module.find_couch_query("xuda_drive", {
|
|
1230
|
+
// selector: { docType: "user_drive", originalname, uid, stat: 3 },
|
|
1231
|
+
// limit: 99,
|
|
1232
|
+
// });
|
|
1233
|
+
// if (user_drive_res.docs.length) {
|
|
1234
|
+
// return {
|
|
1235
|
+
// code: -762,
|
|
1236
|
+
// data: "file already exist",
|
|
1237
|
+
// duplicates: user_drive_res.docs,
|
|
1238
|
+
// };
|
|
1239
|
+
// }
|
|
1240
|
+
|
|
1241
|
+
ref = uid;
|
|
1242
|
+
file_name = 'drv_' + ref + '_' + (await _common.xuda_get_uuid(drive_type)) + ext;
|
|
1243
|
+
|
|
1244
|
+
doc.server_file_name = file_name;
|
|
1245
|
+
|
|
1246
|
+
doc.bucket = {
|
|
1247
|
+
[`${process.env.XUDA_HOSTNAME}`]: await upload_file_to_spaces(tempPath, ref, drive_type, file_name),
|
|
1248
|
+
};
|
|
1249
|
+
doc._id = file_name;
|
|
1250
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
1251
|
+
// misc_module.rsync_drive_resources_to_remote_servers('user', uid);
|
|
1252
|
+
break;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
default:
|
|
1256
|
+
break;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// let file_url = `https://${
|
|
1260
|
+
// process.env.XUDA_HOSTNAME
|
|
1261
|
+
// }/${drive_type}-drive/${ref}${
|
|
1262
|
+
// file_name.substr(0, 1) !== "/" ? "/" : ""
|
|
1263
|
+
// }${file_name}`;
|
|
1264
|
+
// if (["workspace"].includes(req.drive_type)) {
|
|
1265
|
+
// file_url = `https://${process.env.XUDA_HOSTNAME}/workspace-drive${
|
|
1266
|
+
// file_name.substr(0, 1) !== "/" ? "/" : ""
|
|
1267
|
+
// }${file_name}`;
|
|
1268
|
+
// }
|
|
1269
|
+
|
|
1270
|
+
let file_url = get_file_url(drive_type, file_name, ref);
|
|
1271
|
+
|
|
1272
|
+
await fs_module.unlink(tempPath);
|
|
1273
|
+
|
|
1274
|
+
return {
|
|
1275
|
+
code: 760,
|
|
1276
|
+
data: {
|
|
1277
|
+
server_file_name: file_name,
|
|
1278
|
+
filename: file_obj.originalname,
|
|
1279
|
+
file_url,
|
|
1280
|
+
},
|
|
1281
|
+
rename: check_existing_file_ret < 0,
|
|
1282
|
+
};
|
|
1283
|
+
} catch (err) {
|
|
1284
|
+
return { code: -400, data: err.message };
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
exports.check_drive_file = async function (req, job_id, headers, file_obj) {
|
|
1288
|
+
const { type = 'file', drive_type, app_id, uid, file_path } = req;
|
|
1289
|
+
|
|
1290
|
+
var master_app_id;
|
|
1291
|
+
|
|
1292
|
+
if (['studio', 'workspace'].includes(drive_type)) {
|
|
1293
|
+
master_app_id = await _common.get_project_app_id(app_id, true);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
let selector = {
|
|
1297
|
+
type,
|
|
1298
|
+
file_path: path.dirname(file_path),
|
|
1299
|
+
stat: 3,
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
if (type === 'file') {
|
|
1303
|
+
selector.originalname = path.basename(file_path);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
switch (drive_type) {
|
|
1307
|
+
case 'studio': {
|
|
1308
|
+
const target_dir = path.join(_conf[`studio_drive_path`], master_app_id);
|
|
1309
|
+
|
|
1310
|
+
target_file = path.join(target_dir, file_path);
|
|
1311
|
+
|
|
1312
|
+
if (await fs_module.file_exists(target_file)) {
|
|
1313
|
+
return {
|
|
1314
|
+
code: -764,
|
|
1315
|
+
data: 'file exist',
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
break;
|
|
1320
|
+
}
|
|
1321
|
+
case 'workspace': {
|
|
1322
|
+
selector.docType = 'workspace_drive';
|
|
1323
|
+
const workspace_drive_res = await db_module.find_app_couch_query(app_id, {
|
|
1324
|
+
selector,
|
|
1325
|
+
limit: 99,
|
|
1326
|
+
});
|
|
1327
|
+
if (workspace_drive_res.docs.length) {
|
|
1328
|
+
return {
|
|
1329
|
+
code: -764,
|
|
1330
|
+
data: 'file exist',
|
|
1331
|
+
duplicates: workspace_drive_res.docs,
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
break;
|
|
1336
|
+
}
|
|
1337
|
+
case 'user': {
|
|
1338
|
+
selector.docType = 'user_drive';
|
|
1339
|
+
const user_drive_res = await db_module.find_couch_query('xuda_drive', {
|
|
1340
|
+
selector,
|
|
1341
|
+
limit: 99,
|
|
1342
|
+
});
|
|
1343
|
+
if (user_drive_res.docs.length) {
|
|
1344
|
+
return {
|
|
1345
|
+
code: -764,
|
|
1346
|
+
data: 'file exist',
|
|
1347
|
+
duplicates: user_drive_res.docs,
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
default:
|
|
1355
|
+
return {
|
|
1356
|
+
code: -764,
|
|
1357
|
+
data: 'invalid method',
|
|
1358
|
+
};
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
return {
|
|
1363
|
+
code: 764,
|
|
1364
|
+
data: 'ok',
|
|
1365
|
+
};
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
const ocr_drive_file = async function (app_id, doc) {
|
|
1369
|
+
const { drive_type, uid, file_path, originalname } = doc;
|
|
1370
|
+
|
|
1371
|
+
// const _region = process.env.XUDA_HOSTNAME;
|
|
1372
|
+
let target_file = get_file_url(drive_type, path.join(file_path, doc._id), app_id || uid); // doc?.bucket?.[_region]?.Location;
|
|
1373
|
+
|
|
1374
|
+
// if (!target_file) throw 'bucket not find';
|
|
1375
|
+
|
|
1376
|
+
function addQueryParam(urlString, key, value) {
|
|
1377
|
+
// Parse the URL
|
|
1378
|
+
const parsedUrl = new url.URL(urlString);
|
|
1379
|
+
|
|
1380
|
+
// Set the query parameter
|
|
1381
|
+
parsedUrl.searchParams.set(key, value);
|
|
1382
|
+
|
|
1383
|
+
// Return the updated URL
|
|
1384
|
+
return parsedUrl.toString();
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
target_file = addQueryParam(target_file, 'xuda_internal_request_code', _conf.xuda_internal_request_code);
|
|
1388
|
+
|
|
1389
|
+
try {
|
|
1390
|
+
doc.ocr_stat = 2;
|
|
1391
|
+
doc.ocr_stat_date = Date.now();
|
|
1392
|
+
let save_ret = await save_drive_doc(drive_type, app_id, doc, file_path);
|
|
1393
|
+
|
|
1394
|
+
doc = await get_drive_doc('file', drive_type, app_id, uid, path.join(file_path, originalname));
|
|
1395
|
+
|
|
1396
|
+
var ocr = '';
|
|
1397
|
+
|
|
1398
|
+
function detectLanguageByCountry(cfCountry) {
|
|
1399
|
+
const countryData = countryLanguage.getCountry(cfCountry);
|
|
1400
|
+
let lang = 'eng';
|
|
1401
|
+
// Check if the country data is available
|
|
1402
|
+
if (countryData && countryData.languages && countryData.languages.length > 0) {
|
|
1403
|
+
// Return the first official language of the country
|
|
1404
|
+
|
|
1405
|
+
for (let language of countryData.languages) {
|
|
1406
|
+
lang += `+${language.iso639_2}`;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// Default to English if no language found
|
|
1411
|
+
return lang;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
let lang = detectLanguageByCountry(doc.country);
|
|
1415
|
+
|
|
1416
|
+
const generalConfig = { oem: 1, psm: 3, lang };
|
|
1417
|
+
|
|
1418
|
+
switch (doc.mime.split('/')[0]) {
|
|
1419
|
+
case 'image': {
|
|
1420
|
+
ocr = await tesseract.recognize(target_file, generalConfig);
|
|
1421
|
+
|
|
1422
|
+
break;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
case 'application': {
|
|
1426
|
+
switch (doc.mime.split('/')[1]) {
|
|
1427
|
+
case 'pdf': {
|
|
1428
|
+
const { convertPDF } = require('pdf2image');
|
|
1429
|
+
|
|
1430
|
+
const images = await convertPDF(target_file);
|
|
1431
|
+
for await (const imageData of images) {
|
|
1432
|
+
ocr += await tesseract.recognize(imageData.path, generalConfig);
|
|
1433
|
+
}
|
|
1434
|
+
break;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
case 'vnd.openxmlformats-officedocument.wordprocessingml.document': {
|
|
1438
|
+
const mammoth = require('mammoth');
|
|
1439
|
+
ocr = (await mammoth.extractRawText({ path: target_file })).value;
|
|
1440
|
+
break;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
case 'nd.ms-excel':
|
|
1444
|
+
case 'vnd.openxmlformats-officedocument.spreadsheetml.sheet': {
|
|
1445
|
+
const xlsx = require('node-xlsx').default;
|
|
1446
|
+
|
|
1447
|
+
const sheets = xlsx.parse(target_file);
|
|
1448
|
+
sheets.forEach((sheet) => {
|
|
1449
|
+
console.log(`Sheet: ${sheet.name}`);
|
|
1450
|
+
sheet.data.forEach((row) => {
|
|
1451
|
+
ocr += row.join(' '); // Join all cells in the row
|
|
1452
|
+
});
|
|
1453
|
+
});
|
|
1454
|
+
break;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
case 'vnd.ms-powerpoint':
|
|
1458
|
+
case 'vnd.openxmlformats-officedocument.presentationml.presentation':
|
|
1459
|
+
// tbd
|
|
1460
|
+
break;
|
|
1461
|
+
|
|
1462
|
+
default:
|
|
1463
|
+
ocr = (await fs_module.read_file(target_file)).data;
|
|
1464
|
+
break;
|
|
1465
|
+
}
|
|
1466
|
+
break;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
case 'text': {
|
|
1470
|
+
ocr = (await fs_module.read_file(target_file)).data;
|
|
1471
|
+
break;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
default:
|
|
1475
|
+
break;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
doc.ocr = ocr
|
|
1479
|
+
.replace(/<\/?[^>]+(>|$)/g, '')
|
|
1480
|
+
.replace(/[\n]/g, ' ')
|
|
1481
|
+
.replace(/[\f\t]/g, '');
|
|
1482
|
+
doc.ocr_lang = lang;
|
|
1483
|
+
doc.ocr_stat = 3;
|
|
1484
|
+
} catch (err) {
|
|
1485
|
+
doc.ocr_stat = 4;
|
|
1486
|
+
doc.ocr_error = err.message;
|
|
1487
|
+
} finally {
|
|
1488
|
+
doc.ocr_stat_ts = Date.now();
|
|
1489
|
+
|
|
1490
|
+
save_ret = await save_drive_doc(drive_type, app_id, doc, file_path);
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
const validate_drive_type = function (drive_type) {
|
|
1495
|
+
if (!['studio', 'workspace', 'user'].includes(drive_type)) {
|
|
1496
|
+
throw new Error('error - drive_type values allowed: studio, workspace or users');
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
exports.run_drive_pending_ocr = async function (req) {
|
|
1500
|
+
try {
|
|
1501
|
+
var opt = {
|
|
1502
|
+
selector: { docType: 'user_drive', ocr_stat: 1, stat: 3 },
|
|
1503
|
+
limit: 1,
|
|
1504
|
+
};
|
|
1505
|
+
|
|
1506
|
+
const user_drive_res = await db_module.find_couch_query('xuda_drive', opt);
|
|
1507
|
+
for await (let doc of user_drive_res.docs) {
|
|
1508
|
+
await ocr_drive_file(null, doc);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
let selector = {
|
|
1512
|
+
docType: 'app',
|
|
1513
|
+
app_status_code: {
|
|
1514
|
+
$eq: 3,
|
|
1515
|
+
},
|
|
1516
|
+
$or: [
|
|
1517
|
+
{
|
|
1518
|
+
app_type: 'master',
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
app_type: 'instance',
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
app_type: 'datacenter',
|
|
1525
|
+
},
|
|
1526
|
+
],
|
|
1527
|
+
};
|
|
1528
|
+
|
|
1529
|
+
const app_opt = {
|
|
1530
|
+
selector,
|
|
1531
|
+
limit: 99999,
|
|
1532
|
+
};
|
|
1533
|
+
|
|
1534
|
+
var app_res = await db_module.find_couch_query('xuda_master', app_opt);
|
|
1535
|
+
|
|
1536
|
+
opt.selector.docType = 'workspace_drive';
|
|
1537
|
+
for (let app of app_res.docs) {
|
|
1538
|
+
const app_drive_res = await db_module.find_app_couch_query(app._id, opt);
|
|
1539
|
+
for await (let doc of app_drive_res.docs) {
|
|
1540
|
+
await ocr_drive_file(app._id, doc);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
} catch (err) {
|
|
1544
|
+
return { code: -400, data: err.message };
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1547
|
+
|
|
1548
|
+
exports.get_drive_size = async function (req) {
|
|
1549
|
+
try {
|
|
1550
|
+
const { drive_type, app_id, uid } = req;
|
|
1551
|
+
let size = 0;
|
|
1552
|
+
// validate_drive_type(drive_type);
|
|
1553
|
+
|
|
1554
|
+
let app_id_master, directoryPath;
|
|
1555
|
+
switch (drive_type) {
|
|
1556
|
+
case 'user':
|
|
1557
|
+
directoryPath = '';
|
|
1558
|
+
|
|
1559
|
+
break;
|
|
1560
|
+
case 'workspace':
|
|
1561
|
+
directoryPath = '';
|
|
1562
|
+
app_id_master = await _common.get_project_app_id(app_id, true);
|
|
1563
|
+
break;
|
|
1564
|
+
|
|
1565
|
+
default:
|
|
1566
|
+
app_id_master = await _common.get_project_app_id(app_id, true);
|
|
1567
|
+
directoryPath = path.join(_conf[`${drive_type}_drive_path`], app_id_master, '/');
|
|
1568
|
+
|
|
1569
|
+
break;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
size = await get_folder_size(directoryPath, drive_type, app_id_master, uid);
|
|
1573
|
+
if (drive_type === 'workspace') {
|
|
1574
|
+
// calc datacenter
|
|
1575
|
+
size += await get_folder_size(directoryPath, drive_type, app_id);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
return { code: 200, data: size };
|
|
1579
|
+
} catch (err) {
|
|
1580
|
+
return { code: -200, data: err.message };
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
const upload_file_to_spaces = async function (tempPath, ref, drive_type, file_name) {
|
|
1585
|
+
const AWS = require('aws-sdk');
|
|
1586
|
+
|
|
1587
|
+
// Configure the AWS SDK to use DigitalOcean Spaces
|
|
1588
|
+
const spacesEndpoint = new AWS.Endpoint(_conf.storage_bucket[process.env.XUDA_HOSTNAME].endpoint);
|
|
1589
|
+
const s3 = new AWS.S3({
|
|
1590
|
+
endpoint: spacesEndpoint,
|
|
1591
|
+
accessKeyId: _conf.digitalocean.spaces_access_key,
|
|
1592
|
+
secretAccessKey: _conf.digitalocean.spaces_secret_key,
|
|
1593
|
+
region: _conf.storage_bucket[process.env.XUDA_HOSTNAME].region,
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
const fs = require('fs');
|
|
1597
|
+
const fileContent = fs.readFileSync(tempPath);
|
|
1598
|
+
|
|
1599
|
+
const params = {
|
|
1600
|
+
Bucket: `${process.env.XUDA_HOSTNAME}/${drive_type}`, // Replace with your Space name
|
|
1601
|
+
// Key: path.join(ref, crypto.randomUUID() + '_' + file_name), // File name you want to save as in Spaces
|
|
1602
|
+
Key: path.join(ref, _utils.UUID() + '_' + file_name), // File name you want to save as in Spaces
|
|
1603
|
+
Body: fileContent,
|
|
1604
|
+
ACL: 'public-read', // Makes the file publicly accessible. Adjust the ACL according to your needs.
|
|
1605
|
+
};
|
|
1606
|
+
|
|
1607
|
+
try {
|
|
1608
|
+
const data = await s3.upload(params).promise();
|
|
1609
|
+
|
|
1610
|
+
return data;
|
|
1611
|
+
} catch (err) {
|
|
1612
|
+
console.error('Error', err);
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
exports.copy_file_to_another_bucket = async function (source_region, target_region, file_name) {
|
|
1617
|
+
const AWS = require('aws-sdk');
|
|
1618
|
+
|
|
1619
|
+
const sourceEndpoint = new AWS.Endpoint(_conf.storage_bucket[source_region].endpoint);
|
|
1620
|
+
const sourceS3 = new AWS.S3({
|
|
1621
|
+
endpoint: sourceEndpoint,
|
|
1622
|
+
accessKeyId: _conf.digitalocean.spaces_access_key,
|
|
1623
|
+
secretAccessKey: _conf.digitalocean.spaces_secret_key,
|
|
1624
|
+
region: _conf.storage_bucket[source_region].region,
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
const targetEndpoint = new AWS.Endpoint(_conf.storage_bucket[target_region].endpoint);
|
|
1628
|
+
const targetS3 = new AWS.S3({
|
|
1629
|
+
endpoint: targetEndpoint,
|
|
1630
|
+
accessKeyId: _conf.digitalocean.spaces_access_key,
|
|
1631
|
+
secretAccessKey: _conf.digitalocean.spaces_secret_key,
|
|
1632
|
+
region: _conf.storage_bucket[target_region].region,
|
|
1633
|
+
});
|
|
1634
|
+
|
|
1635
|
+
try {
|
|
1636
|
+
// Get the object from the source bucket
|
|
1637
|
+
const { Body } = await sourceS3
|
|
1638
|
+
.getObject({
|
|
1639
|
+
Bucket: source_region,
|
|
1640
|
+
Key: file_name,
|
|
1641
|
+
})
|
|
1642
|
+
.promise();
|
|
1643
|
+
|
|
1644
|
+
// Upload the object to the destination bucket
|
|
1645
|
+
var ret = await targetS3
|
|
1646
|
+
.putObject({
|
|
1647
|
+
Bucket: target_region,
|
|
1648
|
+
Key: file_name,
|
|
1649
|
+
Body,
|
|
1650
|
+
ACL: 'public-read',
|
|
1651
|
+
})
|
|
1652
|
+
.promise();
|
|
1653
|
+
|
|
1654
|
+
ret.Location = `${_conf.storage_bucket[target_region].endpoint}/${target_region}/${file_name}`;
|
|
1655
|
+
ret.key = file_name;
|
|
1656
|
+
ret.Key = file_name;
|
|
1657
|
+
ret.Bucket = target_region;
|
|
1658
|
+
|
|
1659
|
+
return { code: 1, data: ret };
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
console.error('Error copying file:', err);
|
|
1662
|
+
return { code: -1, data: err.message };
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
|
|
1666
|
+
const get_folder_size = async function (dir, drive_type, app_id, uid) {
|
|
1667
|
+
let totalSize = 0;
|
|
1668
|
+
|
|
1669
|
+
const calculateSizeFs = async function (dirPath) {
|
|
1670
|
+
const fs = require('fs').promises;
|
|
1671
|
+
const files = await fs.readdir(dirPath);
|
|
1672
|
+
for (let file of files) {
|
|
1673
|
+
const filePath = path.join(dirPath, file);
|
|
1674
|
+
const stat = await fs.stat(filePath);
|
|
1675
|
+
if (stat.isFile()) {
|
|
1676
|
+
totalSize += stat.size;
|
|
1677
|
+
} else if (stat.isDirectory()) {
|
|
1678
|
+
await calculateSizeFs(filePath);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
const calculateSizeDocs = async function (dirPath) {
|
|
1684
|
+
let opt = {
|
|
1685
|
+
selector: {
|
|
1686
|
+
docType: `${drive_type}_drive`,
|
|
1687
|
+
stat: 3,
|
|
1688
|
+
file_path: path.join('/', dirPath),
|
|
1689
|
+
},
|
|
1690
|
+
limit: 99999,
|
|
1691
|
+
};
|
|
1692
|
+
|
|
1693
|
+
if (drive_type === 'user') {
|
|
1694
|
+
opt.selector.uid = uid;
|
|
1695
|
+
ret = await db_module.find_couch_query('xuda_drive', opt);
|
|
1696
|
+
} else {
|
|
1697
|
+
ret = await db_module.find_app_couch_query(app_id, opt);
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
for await (let doc of ret.docs) {
|
|
1701
|
+
if (doc.type === 'directory') {
|
|
1702
|
+
await calculateSizeDocs(path.join('/', doc._id));
|
|
1703
|
+
} else {
|
|
1704
|
+
totalSize += doc.size || 0;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
|
|
1709
|
+
if (['user', 'workspace'].includes(drive_type)) {
|
|
1710
|
+
await calculateSizeDocs(dir);
|
|
1711
|
+
} else {
|
|
1712
|
+
await calculateSizeFs(dir);
|
|
1713
|
+
}
|
|
1714
|
+
return totalSize;
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
const get_file_info = async function (file_path) {
|
|
1718
|
+
var doc = {};
|
|
1719
|
+
doc.exif_ret = await fs_module.get_exif(file_path);
|
|
1720
|
+
try {
|
|
1721
|
+
const sizeOf = require('image-size');
|
|
1722
|
+
const dimensions = sizeOf(file_path);
|
|
1723
|
+
doc.dimensions = `${dimensions.width}x${dimensions.height}`;
|
|
1724
|
+
} catch (error) {}
|
|
1725
|
+
return doc;
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
exports.delete_file_from_bucket = async function (bucket) {
|
|
1729
|
+
const AWS = require('aws-sdk');
|
|
1730
|
+
|
|
1731
|
+
// Configure the AWS SDK to use DigitalOcean Spaces
|
|
1732
|
+
const spacesEndpoint = new AWS.Endpoint(_conf.storage_bucket[process.env.XUDA_HOSTNAME].endpoint);
|
|
1733
|
+
const s3 = new AWS.S3({
|
|
1734
|
+
endpoint: spacesEndpoint,
|
|
1735
|
+
accessKeyId: _conf.digitalocean.spaces_access_key,
|
|
1736
|
+
secretAccessKey: _conf.digitalocean.spaces_secret_key,
|
|
1737
|
+
region: _conf.storage_bucket[process.env.XUDA_HOSTNAME].region,
|
|
1738
|
+
});
|
|
1739
|
+
|
|
1740
|
+
try {
|
|
1741
|
+
for await (let [key, val] of Object.entries(bucket)) {
|
|
1742
|
+
const data = await s3.deleteObject({ Bucket: key, Key: val.key }).promise();
|
|
1743
|
+
}
|
|
1744
|
+
// return data;
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
console.error('Error', err);
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
|
|
1750
|
+
// const get_folder_docs = async function (dir, drive_type, app_id) {
|
|
1751
|
+
// var docs = [];
|
|
1752
|
+
// const get_docs = async function (dirPath) {
|
|
1753
|
+
// const opt = {
|
|
1754
|
+
// selector: {
|
|
1755
|
+
// docType: `${drive_type}_drive`,
|
|
1756
|
+
// stat: 3,
|
|
1757
|
+
// file_path: path.join('/', dirPath),
|
|
1758
|
+
// },
|
|
1759
|
+
// limit: 99999,
|
|
1760
|
+
// };
|
|
1761
|
+
// const ret = drive_type === 'user' ? await db_module.find_couch_query('xuda_drive', opt) : await db_module.find_app_couch_query(app_id, opt);
|
|
1762
|
+
// for await (let doc of ret.docs) {
|
|
1763
|
+
// if (doc.type === 'directory') {
|
|
1764
|
+
// await get_docs(path.join('/', doc._id));
|
|
1765
|
+
// } else {
|
|
1766
|
+
// docs.push(doc);
|
|
1767
|
+
// }
|
|
1768
|
+
// }
|
|
1769
|
+
// };
|
|
1770
|
+
|
|
1771
|
+
// await get_docs(dir);
|
|
1772
|
+
|
|
1773
|
+
// return docs;
|
|
1774
|
+
// };
|
|
1775
|
+
|
|
1776
|
+
exports.update_drive_file_tags = async function (req, job_id, headers) {
|
|
1777
|
+
try {
|
|
1778
|
+
const { type, drive_type, app_id, uid, file_path, tags = [] } = req;
|
|
1779
|
+
|
|
1780
|
+
validate_drive_type(drive_type);
|
|
1781
|
+
|
|
1782
|
+
let doc = await get_drive_doc(type, drive_type, app_id, uid, file_path, headers);
|
|
1783
|
+
|
|
1784
|
+
doc.date_modified = Date.now();
|
|
1785
|
+
doc.tags = tags;
|
|
1786
|
+
|
|
1787
|
+
return await save_drive_doc(drive_type, app_id, doc);
|
|
1788
|
+
} catch (err) {
|
|
1789
|
+
return {
|
|
1790
|
+
code: -200,
|
|
1791
|
+
data: err.message,
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
const get_file_url = function (drive_type, file_name, ref) {
|
|
1797
|
+
let file_url = `https://${process.env.XUDA_HOSTNAME}/${drive_type}-drive/${ref}${file_name?.substr(0, 1) !== '/' ? '/' : ''}${file_name}`;
|
|
1798
|
+
// if (["workspace"].includes(drive_type)) {
|
|
1799
|
+
// file_url = `https://${process.env.XUDA_HOSTNAME}/workspace-drive${
|
|
1800
|
+
// file_name.substr(0, 1) !== "/" ? "/" : ""
|
|
1801
|
+
// }${file_name}`;
|
|
1802
|
+
// }
|
|
1803
|
+
return file_url;
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
const get_drive_doc = async function (type, drive_type, app_id, uid, file_path, headers) {
|
|
1807
|
+
let check_req = {
|
|
1808
|
+
app_id,
|
|
1809
|
+
uid,
|
|
1810
|
+
drive_type,
|
|
1811
|
+
file_path,
|
|
1812
|
+
type,
|
|
1813
|
+
};
|
|
1814
|
+
const check_existing_file_ret = await module.exports.check_drive_file(check_req);
|
|
1815
|
+
|
|
1816
|
+
let doc_ret;
|
|
1817
|
+
let doc;
|
|
1818
|
+
switch (drive_type) {
|
|
1819
|
+
case 'studio': {
|
|
1820
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
1821
|
+
doc_ret = await db_module.get_app_couch_doc(app_id_reference, file_path);
|
|
1822
|
+
break;
|
|
1823
|
+
}
|
|
1824
|
+
case 'user':
|
|
1825
|
+
doc_ret = await db_module.get_couch_doc('xuda_drive', check_existing_file_ret.duplicates[0]._id);
|
|
1826
|
+
break;
|
|
1827
|
+
|
|
1828
|
+
case 'workspace': {
|
|
1829
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
1830
|
+
const app_id_master = await _common.get_project_app_id(app_id, true);
|
|
1831
|
+
|
|
1832
|
+
doc_ret = await db_module.get_app_couch_doc(app_id_reference, check_existing_file_ret.duplicates[0]._id);
|
|
1833
|
+
|
|
1834
|
+
if (doc_ret?.data?.type === 'file' && !doc_ret?.data?._id.includes(app_id) && !doc_ret?.data?._id.includes(app_id_master)) {
|
|
1835
|
+
throw new Error('file_path unauthorized');
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
break;
|
|
1839
|
+
}
|
|
1840
|
+
default:
|
|
1841
|
+
break;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
if (doc_ret.code < 0) {
|
|
1845
|
+
if (drive_type === 'studio') {
|
|
1846
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
1847
|
+
const file_name = path.basename(file_path);
|
|
1848
|
+
const ext = path.extname(file_name).toLowerCase();
|
|
1849
|
+
const internal_file_path = path.join(_conf.studio_drive_path, app_id_reference, file_path);
|
|
1850
|
+
const statsObj = fs.statSync(internal_file_path);
|
|
1851
|
+
doc = {
|
|
1852
|
+
_id: file_path,
|
|
1853
|
+
docType: `studio_drive`,
|
|
1854
|
+
stat: 3,
|
|
1855
|
+
server_file_name: file_name,
|
|
1856
|
+
originalname: file_name,
|
|
1857
|
+
file_path: file_path,
|
|
1858
|
+
date_created: new Date(statsObj.birthtime).valueOf(),
|
|
1859
|
+
date_modified: 0,
|
|
1860
|
+
ip: headers?.['cf-connecting-ip'],
|
|
1861
|
+
country: headers?.['cf-ipcountry'],
|
|
1862
|
+
file_ext: ext,
|
|
1863
|
+
is_archive: _conf.archive_drive_ext.includes(ext) ? true : false,
|
|
1864
|
+
drive_type,
|
|
1865
|
+
app_id: await _common.get_project_app_id(app_id),
|
|
1866
|
+
app_id_reference: await _common.get_project_app_id(app_id, true),
|
|
1867
|
+
uid,
|
|
1868
|
+
};
|
|
1869
|
+
const save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
1870
|
+
if (save_ret.code < 0) {
|
|
1871
|
+
throw new Error('studio file doc save error');
|
|
1872
|
+
}
|
|
1873
|
+
doc._rev = save_ret.data.rev;
|
|
1874
|
+
} else {
|
|
1875
|
+
throw new Error('file doc not found');
|
|
1876
|
+
}
|
|
1877
|
+
} else {
|
|
1878
|
+
doc = doc_ret.data;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
return doc;
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
const save_drive_doc = async function (drive_type, app_id, doc) {
|
|
1885
|
+
let save_ret;
|
|
1886
|
+
|
|
1887
|
+
switch (drive_type) {
|
|
1888
|
+
case 'workspace':
|
|
1889
|
+
case 'studio':
|
|
1890
|
+
const app_id_reference = await _common.get_project_app_id(app_id);
|
|
1891
|
+
save_ret = await db_module.save_app_couch_doc(app_id_reference, doc);
|
|
1892
|
+
break;
|
|
1893
|
+
|
|
1894
|
+
case 'user':
|
|
1895
|
+
save_ret = await db_module.save_couch_doc('xuda_drive', doc);
|
|
1896
|
+
break;
|
|
1897
|
+
|
|
1898
|
+
default:
|
|
1899
|
+
break;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
if (save_ret.code < 0) {
|
|
1903
|
+
throw new Error(save_ret.data);
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
return save_ret;
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
exports.compile_javascript_program_in_studio_drive = async function (req, job_id) {
|
|
1910
|
+
debugger;
|
|
1911
|
+
|
|
1912
|
+
const queryRegistry = require('query-registry');
|
|
1913
|
+
|
|
1914
|
+
const { app_id, doc } = req;
|
|
1915
|
+
|
|
1916
|
+
try {
|
|
1917
|
+
const studio_drive_script_folder = path.join(_conf.studio_drive_path, app_id, 'scripts');
|
|
1918
|
+
const fs_module = require(`${module_path}/fs_module`);
|
|
1919
|
+
if (!(await fs_module.file_exists(studio_drive_script_folder))) {
|
|
1920
|
+
await fs_module.mkdir(studio_drive_script_folder, 0o775);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
const studio_drive_script_program_folder = path.join(studio_drive_script_folder, doc._id);
|
|
1924
|
+
|
|
1925
|
+
const src = path.join(studio_drive_script_program_folder, 'src');
|
|
1926
|
+
const dist = path.join(studio_drive_script_program_folder, 'dist');
|
|
1927
|
+
|
|
1928
|
+
if (!(await fs_module.file_exists(studio_drive_script_program_folder))) {
|
|
1929
|
+
await fs_module.mkdir(studio_drive_script_program_folder, 0o775);
|
|
1930
|
+
await fs_module.mkdir(src, 0o775);
|
|
1931
|
+
await fs_module.mkdir(dist, 0o775);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
const inputCode = doc.scriptData?.value || '';
|
|
1935
|
+
|
|
1936
|
+
function wrapCodeWithFunction(inputCode) {
|
|
1937
|
+
const lines = inputCode.split('\n');
|
|
1938
|
+
const importLines = [];
|
|
1939
|
+
const codeLines = [];
|
|
1940
|
+
|
|
1941
|
+
// Separate import statements from the rest of the code
|
|
1942
|
+
for (const line of lines) {
|
|
1943
|
+
if (line.trim().startsWith('import ')) {
|
|
1944
|
+
importLines.push(line);
|
|
1945
|
+
} else {
|
|
1946
|
+
codeLines.push(line);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// Wrap the non-import lines with the function
|
|
1951
|
+
const wrappedCode = [
|
|
1952
|
+
...importLines,
|
|
1953
|
+
'',
|
|
1954
|
+
'export default async function (params,xu, SESSION_ID, SESSION_OBJ, job_id) {',
|
|
1955
|
+
...codeLines.map((line) => ` ${line}`), // Indent the code inside the function
|
|
1956
|
+
'}',
|
|
1957
|
+
];
|
|
1958
|
+
|
|
1959
|
+
// Join the lines back into a single string
|
|
1960
|
+
return wrappedCode.join('\n');
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
let content = wrapCodeWithFunction(inputCode);
|
|
1964
|
+
///// insert the css
|
|
1965
|
+
const index_css = path.join(dist, 'index.css');
|
|
1966
|
+
if (await fs_module.file_exists(index_css)) {
|
|
1967
|
+
// const index_css_content = fs_module.read_file(index_css);
|
|
1968
|
+
content = ` export const css = true \n` + content;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
////////////////////////
|
|
1972
|
+
|
|
1973
|
+
const index_js = path.join(src, 'index.mjs');
|
|
1974
|
+
await fs_module.save_file(index_js, content);
|
|
1975
|
+
|
|
1976
|
+
///////////////////////
|
|
1977
|
+
|
|
1978
|
+
let packageJSON = {
|
|
1979
|
+
name: doc.properties?.menuName || doc._id,
|
|
1980
|
+
version: '1.0.0',
|
|
1981
|
+
description: '',
|
|
1982
|
+
main: 'index.js',
|
|
1983
|
+
scripts: { dev: 'vite', build: 'vite build', preview: 'vite preview' },
|
|
1984
|
+
license: 'ISC',
|
|
1985
|
+
dependencies: {},
|
|
1986
|
+
devDependencies: { vite: '^5.4.10' },
|
|
1987
|
+
author: doc?.studio_meta?.checkedInUserName || doc?.studio_meta?.createdByUid || '',
|
|
1988
|
+
};
|
|
1989
|
+
const package_json = path.join(studio_drive_script_program_folder, 'package.json');
|
|
1990
|
+
|
|
1991
|
+
/////////////////
|
|
1992
|
+
|
|
1993
|
+
// Match `import` and `require` statements
|
|
1994
|
+
const importRegex = /import\s+(?:.*?from\s+)?['"](.+?)['"]/g;
|
|
1995
|
+
const requireRegex = /require\(['"](.+?)['"]\)/g;
|
|
1996
|
+
|
|
1997
|
+
let devDependencies = packageJSON.devDependencies || {};
|
|
1998
|
+
let allDependencies = new Set();
|
|
1999
|
+
|
|
2000
|
+
const extractDependencies = (fileContent, regex) => {
|
|
2001
|
+
const matches = [];
|
|
2002
|
+
let match;
|
|
2003
|
+
while ((match = regex.exec(fileContent)) !== null) {
|
|
2004
|
+
let dep = match[1];
|
|
2005
|
+
// Ignore relative imports and CSS files
|
|
2006
|
+
if (!dep.startsWith('.') && !dep.startsWith('/') && !dep.endsWith('.css')) {
|
|
2007
|
+
// handles "invalid package name: 'vue-grid-layout/dist/vue-grid-layout.umd.min.js'"
|
|
2008
|
+
if (dep.includes('/')) dep = dep.split('/')[0]; // result vue-grid-layout
|
|
2009
|
+
|
|
2010
|
+
matches.push(dep);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return matches;
|
|
2014
|
+
};
|
|
2015
|
+
|
|
2016
|
+
const imports = extractDependencies(content, importRegex);
|
|
2017
|
+
const requires = extractDependencies(content, requireRegex);
|
|
2018
|
+
imports.concat(requires).forEach((dep) => allDependencies.add(dep));
|
|
2019
|
+
|
|
2020
|
+
// Add missing dependencies to package.json
|
|
2021
|
+
for await (const dep of allDependencies) {
|
|
2022
|
+
if (!devDependencies[dep]) {
|
|
2023
|
+
console.log(`Adding dependency: ${dep}`);
|
|
2024
|
+
const npm_ret = await queryRegistry.getPackageManifest({
|
|
2025
|
+
name: dep,
|
|
2026
|
+
});
|
|
2027
|
+
|
|
2028
|
+
devDependencies[dep] = npm_ret.version; // Use "latest" as the version or fetch actual versions if needed
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
// update versions from doc
|
|
2032
|
+
for (const [key, val] of Object.entries(doc?.scriptData?.dependencies || {})) {
|
|
2033
|
+
devDependencies[key] = val; // update version from doc
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// Update package.json
|
|
2037
|
+
packageJSON.devDependencies = devDependencies;
|
|
2038
|
+
|
|
2039
|
+
await fs_module.save_file(package_json, JSON.stringify(packageJSON, null, 2));
|
|
2040
|
+
/////////////////////////
|
|
2041
|
+
|
|
2042
|
+
const vite_config = path.join(studio_drive_script_program_folder, 'vite.config.js');
|
|
2043
|
+
|
|
2044
|
+
const code = `
|
|
2045
|
+
|
|
2046
|
+
export default {
|
|
2047
|
+
build: {
|
|
2048
|
+
lib: {
|
|
2049
|
+
entry: "src/index.mjs",
|
|
2050
|
+
formats: ["es"],
|
|
2051
|
+
name: "MyLibrary", // Global variable for UMD/IIFE formats
|
|
2052
|
+
},
|
|
2053
|
+
rollupOptions: {
|
|
2054
|
+
output: {
|
|
2055
|
+
manualChunks(id) {
|
|
2056
|
+
if (id.includes("node_modules")) {
|
|
2057
|
+
return "vendor";
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
},
|
|
2061
|
+
entryFileNames: "[name].mjs",
|
|
2062
|
+
chunkFileNames: "[name]-[hash].mjs",
|
|
2063
|
+
assetFileNames: (assetInfo) => {
|
|
2064
|
+
if (assetInfo.name && assetInfo.name.endsWith(".css")) {
|
|
2065
|
+
return "index[extname]";
|
|
2066
|
+
}
|
|
2067
|
+
return "[name]-[hash][extname]";
|
|
2068
|
+
},
|
|
2069
|
+
|
|
2070
|
+
|
|
2071
|
+
},
|
|
2072
|
+
},
|
|
2073
|
+
minify: false, // Disable minification for easier debugging
|
|
2074
|
+
},
|
|
2075
|
+
|
|
2076
|
+
define: {
|
|
2077
|
+
"process.env": process.env, // Pass environment variables
|
|
2078
|
+
},
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
|
|
2082
|
+
|
|
2083
|
+
`;
|
|
2084
|
+
|
|
2085
|
+
await fs_module.save_file(vite_config, code);
|
|
2086
|
+
//////////////////////
|
|
2087
|
+
|
|
2088
|
+
await _utils.run_ssh_script(`npm i --prefix ${studio_drive_script_program_folder};`);
|
|
2089
|
+
const build_ret = await _utils.run_ssh_script(`npm run build --prefix ${studio_drive_script_program_folder};`);
|
|
2090
|
+
|
|
2091
|
+
//////////////////////
|
|
2092
|
+
|
|
2093
|
+
misc_module.rsync_drive_resources_to_remote_servers('studio', app_id);
|
|
2094
|
+
/////////////////////
|
|
2095
|
+
const vite_build_res = {
|
|
2096
|
+
code: 1,
|
|
2097
|
+
data: {
|
|
2098
|
+
build_ret,
|
|
2099
|
+
dependencies: devDependencies,
|
|
2100
|
+
},
|
|
2101
|
+
};
|
|
2102
|
+
if (job_id) {
|
|
2103
|
+
return vite_build_res;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
doc.vite_build_res = vite_build_res;
|
|
2107
|
+
doc.scriptData.dependencies = devDependencies;
|
|
2108
|
+
|
|
2109
|
+
db_module.save_app_couch_doc(app_id, doc);
|
|
2110
|
+
} catch (err) {
|
|
2111
|
+
doc.vite_build_res = {
|
|
2112
|
+
code: -1,
|
|
2113
|
+
data: err.message,
|
|
2114
|
+
};
|
|
2115
|
+
console.error(doc);
|
|
2116
|
+
if (job_id) {
|
|
2117
|
+
return doc.vite_build_res;
|
|
2118
|
+
}
|
|
2119
|
+
db_module.save_app_couch_doc(app_id, doc);
|
|
2120
|
+
}
|
|
2121
|
+
};
|
|
2122
|
+
|
|
2123
|
+
exports.update_drive_addons = async function (req, job_id) {
|
|
2124
|
+
const { drive_type, app_id, uid, ocr, image_convertor, video_ai, ai_component_generator, edit_image } = req;
|
|
2125
|
+
|
|
2126
|
+
const set_drive_addons = function (drive_addons) {
|
|
2127
|
+
if (typeof ocr !== 'undefined') {
|
|
2128
|
+
drive_addons.ocr = ocr;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
if (typeof image_convertor !== 'undefined') {
|
|
2132
|
+
drive_addons.image_convertor = image_convertor;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
if (typeof video_ai !== 'undefined') {
|
|
2136
|
+
drive_addons.video_ai = video_ai;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
if (typeof ai_component_generator !== 'undefined') {
|
|
2140
|
+
drive_addons.ai_component_generator = ocr;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
if (typeof edit_image !== 'undefined') {
|
|
2144
|
+
drive_addons.edit_image = edit_image;
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
|
|
2148
|
+
let drive_addons = {};
|
|
2149
|
+
let save_ret;
|
|
2150
|
+
if (drive_type === 'workspace' || drive_type === 'studio') {
|
|
2151
|
+
const master_id = await _common.get_project_app_id(app_id, true);
|
|
2152
|
+
var app_obj_ret = await db_module.get_app_obj(master_id);
|
|
2153
|
+
if (app_obj_ret.data.drive_addons) {
|
|
2154
|
+
drive_addons = app_obj_ret.data.drive_addons;
|
|
2155
|
+
}
|
|
2156
|
+
set_drive_addons(drive_addons);
|
|
2157
|
+
save_ret = await db_module.save_app_couch_doc2(master_id, app_obj_ret.data);
|
|
2158
|
+
}
|
|
2159
|
+
if (drive_type === 'user') {
|
|
2160
|
+
let account_ret = await db_module.get_couch_doc('xuda_accounts', uid);
|
|
2161
|
+
|
|
2162
|
+
if (account_ret.data.drive_addons) {
|
|
2163
|
+
drive_addons = account_ret.data.drive_addons;
|
|
2164
|
+
}
|
|
2165
|
+
set_drive_addons(drive_addons);
|
|
2166
|
+
save_ret = await db_module.save_couch_doc('xuda_accounts', account_ret.data);
|
|
2167
|
+
}
|
|
2168
|
+
return save_ret;
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2171
|
+
setTimeout(async function () {
|
|
2172
|
+
// console.log(
|
|
2173
|
+
// await exports.search_drive_files({
|
|
2174
|
+
// app_id: "prj3937cb6f9a31c8c7dea25055bba845b1",
|
|
2175
|
+
// drive_type: "workspace",
|
|
2176
|
+
// search_string: "tag:mediucal tag:school name:dw name:dawdddaw d",
|
|
2177
|
+
// })
|
|
2178
|
+
// );
|
|
2179
|
+
// module.exports.run_drive_pending_ocr();
|
|
2180
|
+
// fix_date_modified();
|
|
2181
|
+
}, 2000);
|
|
2182
|
+
|
|
2183
|
+
// const fix_date_modified = async function () {
|
|
2184
|
+
// const app_id = 'dtcb1674f63e47ddcb11865cefdfb4483fb';
|
|
2185
|
+
// const ret = await db_module.find_app_couch_query(app_id, { selector: { docType: 'workspace_drive' }, limit: 99999 });
|
|
2186
|
+
|
|
2187
|
+
// for (doc of ret.docs) {
|
|
2188
|
+
// if (!doc.date_modified) {
|
|
2189
|
+
// doc.date_modified = doc.date_created;
|
|
2190
|
+
// }
|
|
2191
|
+
// }
|
|
2192
|
+
|
|
2193
|
+
// const save_ret = await db_module.sava_app_couch_bulk_docs(app_id, ret.docs);
|
|
2194
|
+
// console.log('fix_date_modified', save_ret, ret);
|
|
2195
|
+
|
|
2196
|
+
// // const db_name = 'db_prj_3uh4q1zj0llw3mj4wgifh1';
|
|
2197
|
+
// // const ret = await db_module.find_couch_query(db_name, { selector: { docType: 'workspace_drive' } });
|
|
2198
|
+
|
|
2199
|
+
// // for (doc of ret.docs) {
|
|
2200
|
+
// // if (!doc.date_modified) {
|
|
2201
|
+
// // doc.date_modified = 0;
|
|
2202
|
+
// // }
|
|
2203
|
+
// // }
|
|
2204
|
+
|
|
2205
|
+
// // const save_ret = await db_module.save_couch_bulk_docs(db_name, ret.docs);
|
|
2206
|
+
// // console.log('fix_date_modified', save_ret, ret);
|
|
2207
|
+
// };
|