@xuda.io/drive_module 1.1.1498 → 1.1.1499
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.mjs +101 -0
- package/index_ms.mjs +4 -0
- package/index_msa.mjs +4 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { rimraf } from 'rimraf';
|
|
|
4
4
|
import fse from 'fs-extra';
|
|
5
5
|
import unzipper from 'unzipper';
|
|
6
6
|
import fs from 'fs';
|
|
7
|
+
import os from 'os';
|
|
7
8
|
import tesseract from 'node-tesseract-ocr';
|
|
8
9
|
import countryLanguage from 'country-language';
|
|
9
10
|
import url from 'url';
|
|
@@ -3763,6 +3764,106 @@ export const read_user_drive_folder = async (req) => {
|
|
|
3763
3764
|
}
|
|
3764
3765
|
};
|
|
3765
3766
|
|
|
3767
|
+
// fetch_drive_file_to_tmp: copy ONE drive file's bytes onto this box as a temp
|
|
3768
|
+
// file so a server-side document generator can open it, edit it and save the
|
|
3769
|
+
// result back as a new drive file. This is what lets the office plugins (pptx,
|
|
3770
|
+
// docx, xlsx) modify a deck/document the user already has instead of only
|
|
3771
|
+
// creating new ones: user + workspace files live in object storage, so there is
|
|
3772
|
+
// otherwise no path on disk to hand to a parser.
|
|
3773
|
+
//
|
|
3774
|
+
// The file is resolved by drive doc id (drv_...) or by its drive path
|
|
3775
|
+
// (/Folder/name.ext). The caller owns the temp file and must unlink it.
|
|
3776
|
+
//
|
|
3777
|
+
// req: { uid, app_id?, drive_type: 'user'|'workspace'|'studio', file }
|
|
3778
|
+
// -> { tmp_path, originalname, file_path, doc_id, size, mime, drive_type }
|
|
3779
|
+
export const fetch_drive_file_to_tmp = async (req) => {
|
|
3780
|
+
try {
|
|
3781
|
+
const { uid, app_id, drive_type = 'user' } = req || {};
|
|
3782
|
+
const file_ref = String(req?.file || req?.file_id || req?.file_path || '').trim();
|
|
3783
|
+
|
|
3784
|
+
if (!uid) return { code: -1, data: 'uid required' };
|
|
3785
|
+
if (!file_ref) return { code: -1, data: 'file required' };
|
|
3786
|
+
validate_drive_type(drive_type);
|
|
3787
|
+
|
|
3788
|
+
const write_tmp = async (buffer, name) => {
|
|
3789
|
+
const tmp_path = path.join(os.tmpdir(), `xuda_drive_${await _common.xuda_get_uuid('tmp')}${path.extname(name) || ''}`);
|
|
3790
|
+
await fs.promises.writeFile(tmp_path, buffer);
|
|
3791
|
+
return tmp_path;
|
|
3792
|
+
};
|
|
3793
|
+
|
|
3794
|
+
// studio drive is plain files on this box, addressed by their relative path.
|
|
3795
|
+
if (drive_type === 'studio') {
|
|
3796
|
+
const ref = await _common.get_project_app_id(app_id, true);
|
|
3797
|
+
const rel = file_ref.replace(/^\/+/, '');
|
|
3798
|
+
const full = path.join(_conf.studio_drive_path, ref, rel);
|
|
3799
|
+
// Contain the read inside the app's own studio folder.
|
|
3800
|
+
const root = path.join(_conf.studio_drive_path, ref);
|
|
3801
|
+
if (!path.resolve(full).startsWith(path.resolve(root) + path.sep)) {
|
|
3802
|
+
return { code: -1, data: 'file_path unauthorized' };
|
|
3803
|
+
}
|
|
3804
|
+
if (!(await fs_module.file_exists(full))) return { code: -1, data: `file not found: ${file_ref}` };
|
|
3805
|
+
const buffer = await fs.promises.readFile(full);
|
|
3806
|
+
const originalname = path.basename(full);
|
|
3807
|
+
return {
|
|
3808
|
+
code: 1,
|
|
3809
|
+
data: {
|
|
3810
|
+
tmp_path: await write_tmp(buffer, originalname),
|
|
3811
|
+
originalname,
|
|
3812
|
+
file_path: path.posix.join('/', path.dirname(rel) === '.' ? '' : path.dirname(rel)),
|
|
3813
|
+
doc_id: rel,
|
|
3814
|
+
size: buffer.length,
|
|
3815
|
+
mime: _drive_content_type_for(originalname),
|
|
3816
|
+
drive_type,
|
|
3817
|
+
},
|
|
3818
|
+
};
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
const project_id = drive_type === 'user' ? await get_account_default_project_id(uid) : await _common.get_project_app_id(app_id);
|
|
3822
|
+
|
|
3823
|
+
// Either the doc id itself, or a /folder/name.ext path within the drive.
|
|
3824
|
+
const by_id = /^drv_/.test(file_ref);
|
|
3825
|
+
const selector = { docType: `${drive_type}_drive`, type: 'file', stat: 3 };
|
|
3826
|
+
if (by_id) {
|
|
3827
|
+
selector._id = file_ref;
|
|
3828
|
+
} else {
|
|
3829
|
+
const with_slash = file_ref.startsWith('/') ? file_ref : `/${file_ref}`;
|
|
3830
|
+
const dir = path.posix.dirname(with_slash);
|
|
3831
|
+
selector.file_path = dir === '.' ? '/' : dir;
|
|
3832
|
+
selector.originalname = path.posix.basename(with_slash);
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
const find_ret = await db_module.find_app_couch_query(project_id, { selector, limit: 1 });
|
|
3836
|
+
const doc = find_ret?.docs?.[0];
|
|
3837
|
+
if (!doc) return { code: -1, data: `file not found: ${file_ref}` };
|
|
3838
|
+
|
|
3839
|
+
const region = _pick_file_region(doc);
|
|
3840
|
+
const b = (region && doc.bucket?.[region]) || {};
|
|
3841
|
+
const Bucket = b.Bucket || b.bucket || (region && _conf.storage_bucket?.[region]?.name);
|
|
3842
|
+
const Key = b.Key || b.key;
|
|
3843
|
+
const s3 = region ? _drive_s3_for(region) : null;
|
|
3844
|
+
if (!s3 || !Bucket || !Key) return { code: -1, data: 'file bytes unavailable' };
|
|
3845
|
+
|
|
3846
|
+
const obj = await s3.send(new GetObjectCommand({ Bucket, Key }));
|
|
3847
|
+
const buffer = await _stream_to_buffer(obj.Body);
|
|
3848
|
+
const originalname = doc.originalname || path.basename(Key);
|
|
3849
|
+
|
|
3850
|
+
return {
|
|
3851
|
+
code: 1,
|
|
3852
|
+
data: {
|
|
3853
|
+
tmp_path: await write_tmp(buffer, originalname),
|
|
3854
|
+
originalname,
|
|
3855
|
+
file_path: doc.file_path || '/',
|
|
3856
|
+
doc_id: doc._id,
|
|
3857
|
+
size: buffer.length,
|
|
3858
|
+
mime: doc.mime || _drive_content_type_for(originalname),
|
|
3859
|
+
drive_type,
|
|
3860
|
+
},
|
|
3861
|
+
};
|
|
3862
|
+
} catch (err) {
|
|
3863
|
+
return { code: -400, data: err.message };
|
|
3864
|
+
}
|
|
3865
|
+
};
|
|
3866
|
+
|
|
3766
3867
|
// put_site_files — snapshot a set of static-site files into ONE region's
|
|
3767
3868
|
// Spaces bucket under sites/{site_id}/{version}/{path}, public-read. Each
|
|
3768
3869
|
// deploy writes a fresh immutable version directory, so older versions stay
|
package/index_ms.mjs
CHANGED
|
@@ -197,6 +197,10 @@ export const read_user_drive_folder = async function (...args) {
|
|
|
197
197
|
return await broker.send_to_queue("read_user_drive_folder", ...args);
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
+
export const fetch_drive_file_to_tmp = async function (...args) {
|
|
201
|
+
return await broker.send_to_queue("fetch_drive_file_to_tmp", ...args);
|
|
202
|
+
};
|
|
203
|
+
|
|
200
204
|
export const put_site_files = async function (...args) {
|
|
201
205
|
return await broker.send_to_queue("put_site_files", ...args);
|
|
202
206
|
};
|
package/index_msa.mjs
CHANGED
|
@@ -197,6 +197,10 @@ export const read_user_drive_folder = function (...args) {
|
|
|
197
197
|
broker.send_to_queue_async("read_user_drive_folder", ...args);
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
+
export const fetch_drive_file_to_tmp = function (...args) {
|
|
201
|
+
broker.send_to_queue_async("fetch_drive_file_to_tmp", ...args);
|
|
202
|
+
};
|
|
203
|
+
|
|
200
204
|
export const put_site_files = function (...args) {
|
|
201
205
|
broker.send_to_queue_async("put_site_files", ...args);
|
|
202
206
|
};
|