@things-factory/attachment-base 4.0.31 → 4.0.35
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/config/config.development.js +2 -1
- package/config/config.production.js +2 -1
- package/dist-server/routes.js +13 -3
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/attachment/attachment-mutation.js +29 -13
- package/dist-server/service/attachment/attachment-mutation.js.map +1 -1
- package/dist-server/service/attachment/attachment-query.js +1 -1
- package/dist-server/service/attachment/attachment-query.js.map +1 -1
- package/dist-server/service/attachment/attachment-types.js +19 -4
- package/dist-server/service/attachment/attachment-types.js.map +1 -1
- package/dist-server/storage-file.js +10 -7
- package/dist-server/storage-file.js.map +1 -1
- package/dist-server/storage-s3.js +59 -51
- package/dist-server/storage-s3.js.map +1 -1
- package/package.json +10 -5
- package/server/routes.ts +18 -1
- package/server/service/attachment/attachment-mutation.ts +26 -7
- package/server/service/attachment/attachment-query.ts +3 -1
- package/server/service/attachment/attachment-types.ts +12 -0
- package/server/storage-file.ts +15 -8
- package/server/storage-s3.ts +82 -77
- package/dist-server/controllers/index.js +0 -1
- package/dist-server/controllers/index.js.map +0 -1
- package/dist-server/storage-s3-v2.js +0 -94
- package/dist-server/storage-s3-v2.js.map +0 -1
- package/server/controllers/index.ts +0 -0
package/dist-server/routes.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const { STORAGE, ATTACHMENT_PATH } = require('./attachment-const');
|
|
4
3
|
require("./storage-file");
|
|
5
4
|
require("./storage-s3");
|
|
5
|
+
const attachment_const_1 = require("./attachment-const");
|
|
6
|
+
const multer = require('@koa/multer');
|
|
7
|
+
const upload = multer(); // note you can pass `multer` options here
|
|
6
8
|
// process.on('bootstrap-module-domain-private-route' as any, (app, routes) => {
|
|
7
9
|
process.on('bootstrap-module-global-public-route', (app, routes) => {
|
|
8
10
|
// TODO make this secure
|
|
9
|
-
routes.get(`/${ATTACHMENT_PATH}/:attachment`, async (context, next) => {
|
|
10
|
-
await STORAGE.sendFile(context, context.params.attachment, next);
|
|
11
|
+
routes.get(`/${attachment_const_1.ATTACHMENT_PATH}/:attachment`, async (context, next) => {
|
|
12
|
+
await attachment_const_1.STORAGE.sendFile(context, context.params.attachment, next);
|
|
13
|
+
});
|
|
14
|
+
routes.post(`/${attachment_const_1.ATTACHMENT_PATH}`, async (context, next) => {
|
|
15
|
+
const { files } = await upload(context.request);
|
|
16
|
+
const result = await Promise.all(files.map(file => attachment_const_1.STORAGE.uploadFile({ stream: file, filename: file.filename })));
|
|
17
|
+
context.status = 200;
|
|
18
|
+
// Support < IE 10 browser
|
|
19
|
+
context.res.setHeader('Content-Type', 'text/html;charset=UTF-8');
|
|
20
|
+
context.body = JSON.stringify(result);
|
|
11
21
|
});
|
|
12
22
|
});
|
|
13
23
|
//# sourceMappingURL=routes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../server/routes.ts"],"names":[],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../server/routes.ts"],"names":[],"mappings":";;AAAA,0BAAuB;AACvB,wBAAqB;AAErB,yDAA6D;AAE7D,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;AACrC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAA,CAAC,0CAA0C;AAElE,gFAAgF;AAChF,OAAO,CAAC,EAAE,CAAC,sCAA6C,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;IACxE,wBAAwB;IACxB,MAAM,CAAC,GAAG,CAAC,IAAI,kCAAe,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACpE,MAAM,0BAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,IAAI,kCAAe,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACzD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAE/C,MAAM,MAAM,GAAiD,MAAM,OAAO,CAAC,GAAG,CAC5E,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,0BAAO,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CACjF,CAAA;QAED,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;QACpB,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAA;QAChE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -16,15 +16,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
16
16
|
};
|
|
17
17
|
var _a;
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.multipleUpload = exports.singleUpload = exports.deleteAttachmentsByRef = exports.deleteAttachment = exports.createAttachments = exports.createAttachment = exports.AttachmentMutation = void 0;
|
|
20
|
-
const env_1 = require("@things-factory/env");
|
|
19
|
+
exports.multipleUpload = exports.singleUpload = exports.generateUploadURL = exports.deleteAttachmentsByRef = exports.deleteAttachment = exports.createAttachments = exports.createAttachment = exports.AttachmentMutation = void 0;
|
|
21
20
|
const graphql_upload_1 = require("graphql-upload");
|
|
22
21
|
const promises_all_1 = __importDefault(require("promises-all"));
|
|
23
22
|
const type_graphql_1 = require("type-graphql");
|
|
24
23
|
const typeorm_1 = require("typeorm");
|
|
25
|
-
const
|
|
24
|
+
const env_1 = require("@things-factory/env");
|
|
26
25
|
const attachment_const_1 = require("../../attachment-const");
|
|
27
26
|
const attachment_1 = require("./attachment");
|
|
27
|
+
const attachment_types_1 = require("./attachment-types");
|
|
28
28
|
let AttachmentMutation = class AttachmentMutation {
|
|
29
29
|
async createAttachment(attachment, context) {
|
|
30
30
|
return await createAttachment(null, { attachment }, context);
|
|
@@ -53,20 +53,23 @@ let AttachmentMutation = class AttachmentMutation {
|
|
|
53
53
|
async multipleUpload(files, context) {
|
|
54
54
|
return await multipleUpload(null, { files }, context);
|
|
55
55
|
}
|
|
56
|
+
async generateUploadURL(type, context) {
|
|
57
|
+
return await generateUploadURL(null, { type }, context);
|
|
58
|
+
}
|
|
56
59
|
};
|
|
57
60
|
__decorate([
|
|
58
61
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
59
62
|
(0, type_graphql_1.Mutation)(returns => attachment_1.Attachment),
|
|
60
|
-
__param(0, (0, type_graphql_1.Arg)('attachment', type =>
|
|
63
|
+
__param(0, (0, type_graphql_1.Arg)('attachment', type => attachment_types_1.NewAttachment)),
|
|
61
64
|
__param(1, (0, type_graphql_1.Ctx)()),
|
|
62
65
|
__metadata("design:type", Function),
|
|
63
|
-
__metadata("design:paramtypes", [
|
|
66
|
+
__metadata("design:paramtypes", [attachment_types_1.NewAttachment, Object]),
|
|
64
67
|
__metadata("design:returntype", Promise)
|
|
65
68
|
], AttachmentMutation.prototype, "createAttachment", null);
|
|
66
69
|
__decorate([
|
|
67
70
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
68
71
|
(0, type_graphql_1.Mutation)(returns => [attachment_1.Attachment]),
|
|
69
|
-
__param(0, (0, type_graphql_1.Arg)('attachments', type => [
|
|
72
|
+
__param(0, (0, type_graphql_1.Arg)('attachments', type => [attachment_types_1.NewAttachment])),
|
|
70
73
|
__param(1, (0, type_graphql_1.Ctx)()),
|
|
71
74
|
__metadata("design:type", Function),
|
|
72
75
|
__metadata("design:paramtypes", [Array, Object]),
|
|
@@ -76,10 +79,10 @@ __decorate([
|
|
|
76
79
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
77
80
|
(0, type_graphql_1.Mutation)(returns => attachment_1.Attachment),
|
|
78
81
|
__param(0, (0, type_graphql_1.Arg)('id')),
|
|
79
|
-
__param(1, (0, type_graphql_1.Arg)('patch', type =>
|
|
82
|
+
__param(1, (0, type_graphql_1.Arg)('patch', type => attachment_types_1.AttachmentPatch)),
|
|
80
83
|
__param(2, (0, type_graphql_1.Ctx)()),
|
|
81
84
|
__metadata("design:type", Function),
|
|
82
|
-
__metadata("design:paramtypes", [String,
|
|
85
|
+
__metadata("design:paramtypes", [String, attachment_types_1.AttachmentPatch, Object]),
|
|
83
86
|
__metadata("design:returntype", Promise)
|
|
84
87
|
], AttachmentMutation.prototype, "updateAttachment", null);
|
|
85
88
|
__decorate([
|
|
@@ -118,6 +121,14 @@ __decorate([
|
|
|
118
121
|
__metadata("design:paramtypes", [Array, Object]),
|
|
119
122
|
__metadata("design:returntype", Promise)
|
|
120
123
|
], AttachmentMutation.prototype, "multipleUpload", null);
|
|
124
|
+
__decorate([
|
|
125
|
+
(0, type_graphql_1.Mutation)(returns => attachment_types_1.UploadURL),
|
|
126
|
+
__param(0, (0, type_graphql_1.Arg)('type', type => String)),
|
|
127
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
128
|
+
__metadata("design:type", Function),
|
|
129
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
130
|
+
__metadata("design:returntype", Promise)
|
|
131
|
+
], AttachmentMutation.prototype, "generateUploadURL", null);
|
|
121
132
|
AttachmentMutation = __decorate([
|
|
122
133
|
(0, type_graphql_1.Resolver)(attachment_1.Attachment)
|
|
123
134
|
], AttachmentMutation);
|
|
@@ -126,11 +137,12 @@ async function createAttachment(_, { attachment }, context) {
|
|
|
126
137
|
const { file, category, refBy, description } = attachment;
|
|
127
138
|
const { createReadStream, filename, mimetype, encoding } = await file;
|
|
128
139
|
const stream = createReadStream();
|
|
129
|
-
|
|
140
|
+
const { id, path, size } = await attachment_const_1.STORAGE.uploadFile({ stream, filename });
|
|
141
|
+
const { domain, user } = context.state;
|
|
130
142
|
return await (0, typeorm_1.getRepository)(attachment_1.Attachment).save({
|
|
131
|
-
domain
|
|
132
|
-
creator:
|
|
133
|
-
updater:
|
|
143
|
+
domain,
|
|
144
|
+
creator: user,
|
|
145
|
+
updater: user,
|
|
134
146
|
id,
|
|
135
147
|
description,
|
|
136
148
|
name: filename,
|
|
@@ -170,7 +182,7 @@ exports.deleteAttachment = deleteAttachment;
|
|
|
170
182
|
async function deleteAttachmentsByRef(_, { refBys }, context) {
|
|
171
183
|
const { domain } = context.state;
|
|
172
184
|
const repository = (0, typeorm_1.getRepository)(attachment_1.Attachment);
|
|
173
|
-
const attachments = await
|
|
185
|
+
const attachments = await repository.find({
|
|
174
186
|
where: { domain, refBy: (0, typeorm_1.In)(refBys) }
|
|
175
187
|
});
|
|
176
188
|
//remove attachment from repo
|
|
@@ -189,6 +201,10 @@ async function deleteAttachmentsByRef(_, { refBys }, context) {
|
|
|
189
201
|
}
|
|
190
202
|
}
|
|
191
203
|
exports.deleteAttachmentsByRef = deleteAttachmentsByRef;
|
|
204
|
+
async function generateUploadURL(_, { type }, context) {
|
|
205
|
+
return await attachment_const_1.STORAGE.generateUploadURL(type);
|
|
206
|
+
}
|
|
207
|
+
exports.generateUploadURL = generateUploadURL;
|
|
192
208
|
async function singleUpload(_, { file }, context) {
|
|
193
209
|
return await createAttachment(null, { attachment: { file } }, context);
|
|
194
210
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-mutation.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-mutation.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"attachment-mutation.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-mutation.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,mDAA0D;AAC1D,gEAAsC;AACtC,+CAAsE;AACtE,qCAA2C;AAE3C,6CAA4C;AAE5C,6DAAgD;AAChD,6CAAyC;AACzC,yDAA8E;AAG9E,IAAa,kBAAkB,GAA/B,MAAa,kBAAkB;IAG7B,KAAK,CAAC,gBAAgB,CACsB,UAAyB,EAC5D,OAAY;QAEnB,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IAID,KAAK,CAAC,iBAAiB,CACwB,WAA4B,EAClE,OAAY;QAEnB,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAID,KAAK,CAAC,gBAAgB,CACT,EAAU,EACkB,KAAsB,EACtD,OAAY;QAEnB,MAAM,UAAU,GAAG,MAAM,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAC,OAAO,CAAC;YACzD,KAAK,EAAE;gBACL,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;gBAC5B,EAAE;aACH;SACF,CAAC,CAAA;QAEF,OAAO,MAAM,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAC,IAAI,+CACtC,UAAU,GACV,KAAK,KACR,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,IAC3B,CAAA;IACJ,CAAC;IAID,KAAK,CAAC,gBAAgB,CAAY,EAAU,EAAS,OAAY;QAC/D,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAID,KAAK,CAAC,sBAAsB,CACO,MAAgB,EAC1C,OAAY;QAEnB,OAAO,MAAM,sBAAsB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAID,KAAK,CAAC,YAAY,CAAqC,IAAgB,EAAS,OAAY;QAC1F,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;IAID,KAAK,CAAC,cAAc,CACqB,KAAmB,EACnD,OAAY;QAEnB,OAAO,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAGD,KAAK,CAAC,iBAAiB,CACQ,IAAY,EAClC,OAAY;QAEnB,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACzD,CAAC;CACF,CAAA;AA1EC;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,WAAA,IAAA,kBAAG,EAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,gCAAa,CAAC,CAAA;IACxC,WAAA,IAAA,kBAAG,GAAE,CAAA;;qCADgD,gCAAa;;0DAIpE;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,WAAA,IAAA,kBAAG,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,gCAAa,CAAC,CAAC,CAAA;IAC3C,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,WAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IACT,WAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kCAAe,CAAC,CAAA;IACrC,WAAA,IAAA,kBAAG,GAAE,CAAA;;6CADwC,kCAAe;;0DAe9D;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IACL,WAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;0DAEnD;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IAE1B,WAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/B,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;gEAGP;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IACZ,WAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,8BAAa,CAAC,CAAA;IAAoB,WAAA,IAAA,kBAAG,GAAE,CAAA;;yDAAlB,2BAAU,oBAAV,2BAAU;;sDAEtE;AAID;IAFC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,WAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,8BAAa,CAAC,CAAC,CAAA;IACrC,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;wDAGP;AAGD;IADC,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,4BAAS,CAAC;IAE5B,WAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;IAC3B,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AA5EU,kBAAkB;IAD9B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;GACR,kBAAkB,CA6E9B;AA7EY,gDAAkB;AA+ExB,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,UAAU,EAAE,EAAE,OAAY;IACzE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,CAAA;IACzD,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAA;IACrE,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IAEjC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,0BAAO,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;IACzE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEtC,OAAO,MAAM,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAC,IAAI,CAAC;QAC1C,MAAM;QACN,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,EAAE;QACF,WAAW;QACX,IAAI,EAAE,QAAQ;QACd,QAAQ;QACR,QAAQ;QACR,KAAK;QACL,QAAQ,EAAE,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;QACjD,IAAI,EAAE,IAAW;QACjB,IAAI;KACL,CAAC,CAAA;AACJ,CAAC;AAtBD,4CAsBC;AAEM,KAAK,UAAU,iBAAiB,CAAC,CAAM,EAAE,EAAE,WAAW,EAAE,EAAE,OAAY;IAC3E,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,sBAAW,CAAC,GAAG,CAC/C,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC,CAC5E,CAAA;IAED,IAAI,MAAM,CAAC,MAAM,EAAE;QACjB,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,YAAM,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAA;QAE1E,OAAO,MAAM,CAAA;KACd;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAZD,8CAYC;AAEM,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAY;IACjE,MAAM,UAAU,GAAG,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAA;IAC5C,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE;KAC5C,CAAC,CAAA;IAEF,IAAI,UAAU,EAAE;QACd,MAAM,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QACtC,MAAM,0BAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACzC,OAAO,IAAI,CAAA;KACZ;SAAM;QACL,OAAO,KAAK,CAAA;KACb;AACH,CAAC;AAbD,4CAaC;AAEM,KAAK,UAAU,sBAAsB,CAAC,CAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAY;IAC3E,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEhC,MAAM,UAAU,GAAG,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAA;IAC5C,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;QACxC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE;KACrC,CAAC,CAAA;IAEF,6BAA6B;IAC7B,MAAM,UAAU,CAAC,MAAM,CAAC;QACtB,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC;KAClB,CAAC,CAAA;IAEF,sCAAsC;IACtC,IAAI,WAAW,CAAC,MAAM,EAAE;QACtB,MAAM,OAAO,CAAC,GAAG,CACf,WAAW,CAAC,GAAG,CAAC,KAAK,EAAC,UAAU,EAAC,EAAE;YACjC,MAAM,0BAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAC3C,CAAC,CAAC,CACH,CAAA;QAED,OAAO,IAAI,CAAA;KACZ;SAAM;QACL,OAAO,KAAK,CAAA;KACb;AACH,CAAC;AAzBD,wDAyBC;AAEM,KAAK,UAAU,iBAAiB,CACrC,CAAM,EACN,EAAE,IAAI,EAAE,EACR,OAAY;IAEZ,OAAO,MAAM,0BAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;AAC9C,CAAC;AAND,8CAMC;AAEM,KAAK,UAAU,YAAY,CAAC,CAAM,EAAE,EAAE,IAAI,EAAE,EAAE,OAAY;IAC/D,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACxE,CAAC;AAFD,oCAEC;AAEM,KAAK,UAAU,cAAc,CAAC,CAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAY;IAClE,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AAC3E,CAAC;AAFD,wCAEC"}
|
|
@@ -14,9 +14,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
14
14
|
var _a;
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.AttachmentQuery = void 0;
|
|
17
|
-
const shell_1 = require("@things-factory/shell");
|
|
18
17
|
const type_graphql_1 = require("type-graphql");
|
|
19
18
|
const typeorm_1 = require("typeorm");
|
|
19
|
+
const shell_1 = require("@things-factory/shell");
|
|
20
20
|
const __1 = require("../");
|
|
21
21
|
const attachment_1 = require("./attachment");
|
|
22
22
|
let AttachmentQuery = class AttachmentQuery {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-query.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-query.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA
|
|
1
|
+
{"version":3,"file":"attachment-query.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-query.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAAwD;AACxD,qCAAuC;AAEvC,iDAAsF;AAEtF,2BAAoC;AACpC,6CAAyC;AAGzC,IAAa,eAAe,GAA5B,MAAa,eAAe;IAE1B,KAAK,CAAC,WAAW,CACR,OAAY,EACmC,OAAkB,EACb,UAAuB,EAC1B,QAAoB;QAE5E,MAAM,eAAe,GAAG,IAAA,yBAAiB,EAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACrG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAC,YAAY,iCAC9D,eAAe,KAClB,SAAS,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,IAC3C,CAAA;QAEF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGD,KAAK,CAAC,UAAU,CAAY,EAAU,EAAS,OAAY;QACzD,OAAO,MAAM,IAAA,uBAAa,EAAC,uBAAU,CAAC,CAAC,OAAO,CAAC;YAC7C,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE;YAC3C,SAAS,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;SAC5C,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AAtBC;IADC,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,kBAAc,CAAC;IAE9B,WAAA,IAAA,kBAAG,GAAE,CAAA;IACL,WAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,cAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACpD,WAAA,IAAA,kBAAG,EAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,WAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,eAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;;wEADiB,kBAAU,oBAAV,kBAAU;;kDAUnF;AAGD;IADC,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IACX,WAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,kBAAG,GAAE,CAAA;;;;iDAK7C;AAvBU,eAAe;IAD3B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;GACR,eAAe,CAwB3B;AAxBY,0CAAe"}
|
|
@@ -8,11 +8,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
-
var _a, _b;
|
|
11
|
+
var _a, _b, _c;
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.AttachmentPatch = exports.NewAttachment = exports.AttachmentList = void 0;
|
|
13
|
+
exports.AttachmentPatch = exports.NewAttachment = exports.UploadURL = exports.AttachmentList = void 0;
|
|
14
14
|
const graphql_upload_1 = require("graphql-upload");
|
|
15
15
|
const type_graphql_1 = require("type-graphql");
|
|
16
|
+
const shell_1 = require("@things-factory/shell");
|
|
16
17
|
const attachment_1 = require("./attachment");
|
|
17
18
|
let AttachmentList = class AttachmentList {
|
|
18
19
|
};
|
|
@@ -28,6 +29,20 @@ AttachmentList = __decorate([
|
|
|
28
29
|
(0, type_graphql_1.ObjectType)()
|
|
29
30
|
], AttachmentList);
|
|
30
31
|
exports.AttachmentList = AttachmentList;
|
|
32
|
+
let UploadURL = class UploadURL {
|
|
33
|
+
};
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, type_graphql_1.Field)(type => String),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], UploadURL.prototype, "url", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, type_graphql_1.Field)(type => shell_1.ScalarAny),
|
|
40
|
+
__metadata("design:type", typeof (_a = typeof shell_1.ScalarAny !== "undefined" && shell_1.ScalarAny) === "function" ? _a : Object)
|
|
41
|
+
], UploadURL.prototype, "fields", void 0);
|
|
42
|
+
UploadURL = __decorate([
|
|
43
|
+
(0, type_graphql_1.ObjectType)()
|
|
44
|
+
], UploadURL);
|
|
45
|
+
exports.UploadURL = UploadURL;
|
|
31
46
|
let NewAttachment = class NewAttachment {
|
|
32
47
|
};
|
|
33
48
|
__decorate([
|
|
@@ -36,7 +51,7 @@ __decorate([
|
|
|
36
51
|
], NewAttachment.prototype, "category", void 0);
|
|
37
52
|
__decorate([
|
|
38
53
|
(0, type_graphql_1.Field)(type => graphql_upload_1.GraphQLUpload),
|
|
39
|
-
__metadata("design:type", typeof (
|
|
54
|
+
__metadata("design:type", typeof (_b = typeof graphql_upload_1.FileUpload !== "undefined" && graphql_upload_1.FileUpload) === "function" ? _b : Object)
|
|
40
55
|
], NewAttachment.prototype, "file", void 0);
|
|
41
56
|
__decorate([
|
|
42
57
|
(0, type_graphql_1.Field)({ nullable: true }),
|
|
@@ -74,7 +89,7 @@ __decorate([
|
|
|
74
89
|
], AttachmentPatch.prototype, "category", void 0);
|
|
75
90
|
__decorate([
|
|
76
91
|
(0, type_graphql_1.Field)(type => graphql_upload_1.GraphQLUpload, { nullable: true }),
|
|
77
|
-
__metadata("design:type", typeof (
|
|
92
|
+
__metadata("design:type", typeof (_c = typeof graphql_upload_1.FileUpload !== "undefined" && graphql_upload_1.FileUpload) === "function" ? _c : Object)
|
|
78
93
|
], AttachmentPatch.prototype, "file", void 0);
|
|
79
94
|
__decorate([
|
|
80
95
|
(0, type_graphql_1.Field)({ nullable: true }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-types.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-types.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,mDAA0D;AAC1D,+CAAgE;
|
|
1
|
+
{"version":3,"file":"attachment-types.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-types.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,mDAA0D;AAC1D,+CAAgE;AAEhE,iDAAiD;AAEjD,6CAAyC;AAGzC,IAAa,cAAc,GAA3B,MAAa,cAAc;CAM1B,CAAA;AAJC;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;;6CACT;AAGnB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,CAAC;;6CACN;AALF,cAAc;IAD1B,IAAA,yBAAU,GAAE;GACA,cAAc,CAM1B;AANY,wCAAc;AAS3B,IAAa,SAAS,GAAtB,MAAa,SAAS;CAMrB,CAAA;AAJC;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;;sCACX;AAGX;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC;kDACjB,iBAAS,oBAAT,iBAAS;yCAAA;AALN,SAAS;IADrB,IAAA,yBAAU,GAAE;GACA,SAAS,CAMrB;AANY,8BAAS;AAStB,IAAa,aAAa,GAA1B,MAAa,aAAa;CAYzB,CAAA;AAVC;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CACV;AAGhB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,8BAAa,CAAC;kDACvB,2BAAU,oBAAV,2BAAU;2CAAA;AAGhB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDACP;AAGnB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CACb;AAXF,aAAa;IADzB,IAAA,wBAAS,GAAE;GACC,aAAa,CAYzB;AAZY,sCAAa;AAe1B,IAAa,eAAe,GAA5B,MAAa,eAAe;CAqB3B,CAAA;AAnBC;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;6CACd;AAGZ;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACP;AAGnB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDACV;AAGhB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDACV;AAGhB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDACV;AAGhB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,8BAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;kDAC3C,2BAAU,oBAAV,2BAAU;6CAAA;AAGhB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACb;AApBF,eAAe;IAD3B,IAAA,wBAAS,GAAE;GACC,eAAe,CAqB3B;AArBY,0CAAe"}
|
|
@@ -22,13 +22,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
const v4_1 = __importDefault(require("uuid/v4"));
|
|
26
25
|
const fs = __importStar(require("fs"));
|
|
27
26
|
const mkdirp = __importStar(require("mkdirp"));
|
|
28
27
|
const path_1 = require("path");
|
|
29
|
-
const
|
|
28
|
+
const v4_1 = __importDefault(require("uuid/v4"));
|
|
30
29
|
const env_1 = require("@things-factory/env");
|
|
31
30
|
const attachment_const_1 = require("./attachment-const");
|
|
31
|
+
const send = require('koa-send');
|
|
32
32
|
if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 'file') {
|
|
33
33
|
const uploadDir = env_1.config.getPath(null, attachment_const_1.STORAGE.base || 'attachments');
|
|
34
34
|
attachment_const_1.STORAGE.uploadFile = ({ stream, filename }) => {
|
|
@@ -36,11 +36,7 @@ if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 'file') {
|
|
|
36
36
|
const id = (0, v4_1.default)();
|
|
37
37
|
const ext = filename.split('.').pop();
|
|
38
38
|
const path = ext ? (0, path_1.resolve)(uploadDir, `${id}.${ext}`) : (0, path_1.resolve)(uploadDir, id);
|
|
39
|
-
const relativePath = path
|
|
40
|
-
.split('\\')
|
|
41
|
-
.pop()
|
|
42
|
-
.split('/')
|
|
43
|
-
.pop();
|
|
39
|
+
const relativePath = path.split('\\').pop().split('/').pop();
|
|
44
40
|
var size = 0;
|
|
45
41
|
return new Promise((resolve, reject) => stream
|
|
46
42
|
.on('error', error => {
|
|
@@ -65,6 +61,13 @@ if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 'file') {
|
|
|
65
61
|
const fullpath = (0, path_1.resolve)(uploadDir, attachment);
|
|
66
62
|
return fs.readFileSync(fullpath, encoding);
|
|
67
63
|
};
|
|
64
|
+
attachment_const_1.STORAGE.generateUploadURL = async (type) => {
|
|
65
|
+
const id = (0, v4_1.default)();
|
|
66
|
+
return await {
|
|
67
|
+
url: `/${attachment_const_1.ATTACHMENT_PATH}`,
|
|
68
|
+
fields: {}
|
|
69
|
+
};
|
|
70
|
+
};
|
|
68
71
|
env_1.logger.info('File Storage is Ready.');
|
|
69
72
|
}
|
|
70
73
|
//# sourceMappingURL=storage-file.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-file.js","sourceRoot":"","sources":["../server/storage-file.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"storage-file.js","sourceRoot":"","sources":["../server/storage-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,71 +4,62 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const v4_1 = __importDefault(require("uuid/v4"));
|
|
7
|
-
const
|
|
7
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
8
|
+
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
9
|
+
const s3_presigned_post_1 = require("@aws-sdk/s3-presigned-post");
|
|
8
10
|
const env_1 = require("@things-factory/env");
|
|
9
|
-
const
|
|
11
|
+
const attachment_const_1 = require("./attachment-const");
|
|
10
12
|
const mime = require('mime');
|
|
11
13
|
const { fs } = require('memfs');
|
|
12
|
-
const attachment_const_1 = require("./attachment-const");
|
|
13
14
|
if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 's3') {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const client = new client_s3_1.S3Client({
|
|
16
|
+
credentials: {
|
|
17
|
+
accessKeyId: attachment_const_1.STORAGE.accessKeyId,
|
|
18
|
+
secretAccessKey: attachment_const_1.STORAGE.secretAccessKey
|
|
19
|
+
},
|
|
20
|
+
region: attachment_const_1.STORAGE.region
|
|
21
|
+
});
|
|
22
|
+
const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
23
|
+
const chunks = [];
|
|
24
|
+
stream.on('data', chunk => chunks.push(chunk));
|
|
25
|
+
stream.once('end', () => resolve(Buffer.concat(chunks)));
|
|
26
|
+
stream.once('error', reject);
|
|
17
27
|
});
|
|
18
28
|
/* upload file */
|
|
19
|
-
attachment_const_1.STORAGE.uploadFile = ({ stream, filename }) => {
|
|
29
|
+
attachment_const_1.STORAGE.uploadFile = async ({ stream, filename }) => {
|
|
20
30
|
const id = (0, v4_1.default)();
|
|
21
31
|
const ext = filename.split('.').pop();
|
|
22
32
|
const key = ext ? `${id}.${ext}` : id;
|
|
23
33
|
var size = 0;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
S3.upload({
|
|
34
|
+
const upload = new lib_storage_1.Upload({
|
|
35
|
+
client,
|
|
36
|
+
params: {
|
|
28
37
|
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
29
38
|
Key: key,
|
|
30
|
-
Body:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return pass;
|
|
41
|
-
})())
|
|
42
|
-
.on('error', error => reject(error))
|
|
43
|
-
.on('data', chunk => (size += chunk.length)));
|
|
39
|
+
Body: stream
|
|
40
|
+
// ContentType: 'text/plain',
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const result = (await upload.done());
|
|
44
|
+
return {
|
|
45
|
+
id,
|
|
46
|
+
path: key,
|
|
47
|
+
size
|
|
48
|
+
};
|
|
44
49
|
};
|
|
45
|
-
attachment_const_1.STORAGE.deleteFile = path => {
|
|
46
|
-
|
|
50
|
+
attachment_const_1.STORAGE.deleteFile = async (path) => {
|
|
51
|
+
const command = new client_s3_1.DeleteObjectCommand({
|
|
47
52
|
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
48
53
|
Key: path
|
|
49
|
-
}
|
|
54
|
+
});
|
|
55
|
+
return await client.send(command);
|
|
50
56
|
};
|
|
51
|
-
/* creating bucket */
|
|
52
|
-
// s3.createBucket(
|
|
53
|
-
// {
|
|
54
|
-
// Bucket: STORAGE.bucketName,
|
|
55
|
-
// CreateBucketConfiguration: {
|
|
56
|
-
// // Set your region here
|
|
57
|
-
// LocationConstraint: 'eu-west-1'
|
|
58
|
-
// }
|
|
59
|
-
// },
|
|
60
|
-
// function(err, data) {
|
|
61
|
-
// if (err) console.log(err, err.stack)
|
|
62
|
-
// else console.log('Bucket Created Successfully', data.Location)
|
|
63
|
-
// }
|
|
64
|
-
// )
|
|
65
57
|
/* TODO Streaming to Streaming 으로 구현하라. */
|
|
66
58
|
attachment_const_1.STORAGE.sendFile = async (context, attachment, next) => {
|
|
67
|
-
const result = await
|
|
59
|
+
const result = await client.send(new client_s3_1.GetObjectCommand({
|
|
68
60
|
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
69
61
|
Key: attachment
|
|
70
|
-
})
|
|
71
|
-
fs.writeFileSync(`/${attachment}`, result.Body);
|
|
62
|
+
}));
|
|
72
63
|
context.set({
|
|
73
64
|
'Content-Length': result.ContentLength,
|
|
74
65
|
'Content-Type': mime.getType(attachment),
|
|
@@ -76,18 +67,35 @@ if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 's3') {
|
|
|
76
67
|
ETag: result.ETag,
|
|
77
68
|
'Cache-Control': 'public, max-age=31556926'
|
|
78
69
|
});
|
|
79
|
-
context.body =
|
|
70
|
+
context.body = result.Body;
|
|
80
71
|
};
|
|
81
72
|
attachment_const_1.STORAGE.readFile = async (attachment, encoding) => {
|
|
82
|
-
|
|
73
|
+
/*
|
|
74
|
+
* refered to
|
|
75
|
+
* https://transang.me/modern-fetch-and-how-to-get-buffer-output-from-aws-sdk-v3-getobjectcommand/#the-body-type
|
|
76
|
+
*/
|
|
77
|
+
const result = await client.send(new client_s3_1.GetObjectCommand({
|
|
83
78
|
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
84
79
|
Key: attachment
|
|
85
|
-
})
|
|
80
|
+
}));
|
|
86
81
|
var body = result.Body;
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
var buffer = await streamToBuffer(body);
|
|
83
|
+
switch (encoding) {
|
|
84
|
+
case 'base64':
|
|
85
|
+
return buffer.toString('base64');
|
|
86
|
+
default:
|
|
87
|
+
return await buffer;
|
|
89
88
|
}
|
|
90
|
-
|
|
89
|
+
};
|
|
90
|
+
attachment_const_1.STORAGE.generateUploadURL = async (type) => {
|
|
91
|
+
const expiresInMinutes = 1;
|
|
92
|
+
const id = (0, v4_1.default)();
|
|
93
|
+
return await (0, s3_presigned_post_1.createPresignedPost)(client, {
|
|
94
|
+
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
95
|
+
Key: id,
|
|
96
|
+
Expires: expiresInMinutes * 60,
|
|
97
|
+
Conditions: [['eq', '$Content-Type', type]]
|
|
98
|
+
});
|
|
91
99
|
};
|
|
92
100
|
env_1.logger.info('S3 Bucket Storage is Ready.');
|
|
93
101
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-s3.js","sourceRoot":"","sources":["../server/storage-s3.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"storage-s3.js","sourceRoot":"","sources":["../server/storage-s3.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/attachment-base",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.35",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -24,11 +24,16 @@
|
|
|
24
24
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
27
|
+
"@aws-sdk/client-s3": "^3.46.0",
|
|
28
|
+
"@aws-sdk/lib-storage": "^3.46.0",
|
|
29
|
+
"@aws-sdk/s3-presigned-post": "^3.46.0",
|
|
30
|
+
"@koa/multer": "^3.0.0",
|
|
31
|
+
"@things-factory/auth-base": "^4.0.35",
|
|
32
|
+
"@things-factory/env": "^4.0.35",
|
|
29
33
|
"aws-sdk": "^2.960.0",
|
|
30
34
|
"memfs": "^3.0.1",
|
|
31
|
-
"mime": "^2.4.4"
|
|
35
|
+
"mime": "^2.4.4",
|
|
36
|
+
"multer": "^1.3.0"
|
|
32
37
|
},
|
|
33
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "842a39426de15e808ee3aaf5972f1024afe5281f"
|
|
34
39
|
}
|
package/server/routes.ts
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
const { STORAGE, ATTACHMENT_PATH } = require('./attachment-const')
|
|
2
1
|
import './storage-file'
|
|
3
2
|
import './storage-s3'
|
|
4
3
|
|
|
4
|
+
import { ATTACHMENT_PATH, STORAGE } from './attachment-const'
|
|
5
|
+
|
|
6
|
+
const multer = require('@koa/multer')
|
|
7
|
+
const upload = multer() // note you can pass `multer` options here
|
|
8
|
+
|
|
5
9
|
// process.on('bootstrap-module-domain-private-route' as any, (app, routes) => {
|
|
6
10
|
process.on('bootstrap-module-global-public-route' as any, (app, routes) => {
|
|
7
11
|
// TODO make this secure
|
|
8
12
|
routes.get(`/${ATTACHMENT_PATH}/:attachment`, async (context, next) => {
|
|
9
13
|
await STORAGE.sendFile(context, context.params.attachment, next)
|
|
10
14
|
})
|
|
15
|
+
|
|
16
|
+
routes.post(`/${ATTACHMENT_PATH}`, async (context, next) => {
|
|
17
|
+
const { files } = await upload(context.request)
|
|
18
|
+
|
|
19
|
+
const result: { id: string; path: string; size: number }[] = await Promise.all(
|
|
20
|
+
files.map(file => STORAGE.uploadFile({ stream: file, filename: file.filename }))
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
context.status = 200
|
|
24
|
+
// Support < IE 10 browser
|
|
25
|
+
context.res.setHeader('Content-Type', 'text/html;charset=UTF-8')
|
|
26
|
+
context.body = JSON.stringify(result)
|
|
27
|
+
})
|
|
11
28
|
})
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { logger } from '@things-factory/env'
|
|
2
1
|
import { FileUpload, GraphQLUpload } from 'graphql-upload'
|
|
3
2
|
import promisesAll from 'promises-all'
|
|
4
3
|
import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
|
|
5
4
|
import { getRepository, In } from 'typeorm'
|
|
6
|
-
|
|
5
|
+
|
|
6
|
+
import { logger } from '@things-factory/env'
|
|
7
|
+
|
|
7
8
|
import { STORAGE } from '../../attachment-const'
|
|
8
9
|
import { Attachment } from './attachment'
|
|
10
|
+
import { AttachmentPatch, NewAttachment, UploadURL } from './attachment-types'
|
|
9
11
|
|
|
10
12
|
@Resolver(Attachment)
|
|
11
13
|
export class AttachmentMutation {
|
|
@@ -77,6 +79,14 @@ export class AttachmentMutation {
|
|
|
77
79
|
): Promise<Attachment[]> {
|
|
78
80
|
return await multipleUpload(null, { files }, context)
|
|
79
81
|
}
|
|
82
|
+
|
|
83
|
+
@Mutation(returns => UploadURL)
|
|
84
|
+
async generateUploadURL(
|
|
85
|
+
@Arg('type', type => String) type: string,
|
|
86
|
+
@Ctx() context: any
|
|
87
|
+
): Promise<{ url: string; fields: { [key: string]: string } }> {
|
|
88
|
+
return await generateUploadURL(null, { type }, context)
|
|
89
|
+
}
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
export async function createAttachment(_: any, { attachment }, context: any): Promise<Attachment> {
|
|
@@ -84,12 +94,13 @@ export async function createAttachment(_: any, { attachment }, context: any): Pr
|
|
|
84
94
|
const { createReadStream, filename, mimetype, encoding } = await file
|
|
85
95
|
const stream = createReadStream()
|
|
86
96
|
|
|
87
|
-
|
|
97
|
+
const { id, path, size } = await STORAGE.uploadFile({ stream, filename })
|
|
98
|
+
const { domain, user } = context.state
|
|
88
99
|
|
|
89
100
|
return await getRepository(Attachment).save({
|
|
90
|
-
domain
|
|
91
|
-
creator:
|
|
92
|
-
updater:
|
|
101
|
+
domain,
|
|
102
|
+
creator: user,
|
|
103
|
+
updater: user,
|
|
93
104
|
id,
|
|
94
105
|
description,
|
|
95
106
|
name: filename,
|
|
@@ -135,7 +146,7 @@ export async function deleteAttachmentsByRef(_: any, { refBys }, context: any):
|
|
|
135
146
|
const { domain } = context.state
|
|
136
147
|
|
|
137
148
|
const repository = getRepository(Attachment)
|
|
138
|
-
const attachments = await
|
|
149
|
+
const attachments = await repository.find({
|
|
139
150
|
where: { domain, refBy: In(refBys) }
|
|
140
151
|
})
|
|
141
152
|
|
|
@@ -158,6 +169,14 @@ export async function deleteAttachmentsByRef(_: any, { refBys }, context: any):
|
|
|
158
169
|
}
|
|
159
170
|
}
|
|
160
171
|
|
|
172
|
+
export async function generateUploadURL(
|
|
173
|
+
_: any,
|
|
174
|
+
{ type },
|
|
175
|
+
context: any
|
|
176
|
+
): Promise<{ url: string; fields: { [key: string]: string } }> {
|
|
177
|
+
return await STORAGE.generateUploadURL(type)
|
|
178
|
+
}
|
|
179
|
+
|
|
161
180
|
export async function singleUpload(_: any, { file }, context: any): Promise<Attachment> {
|
|
162
181
|
return await createAttachment(null, { attachment: { file } }, context)
|
|
163
182
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { convertListParams, Filter, Pagination, Sorting } from '@things-factory/shell'
|
|
2
1
|
import { Arg, Ctx, Query, Resolver } from 'type-graphql'
|
|
3
2
|
import { getRepository } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { convertListParams, Filter, Pagination, Sorting } from '@things-factory/shell'
|
|
5
|
+
|
|
4
6
|
import { AttachmentList } from '../'
|
|
5
7
|
import { Attachment } from './attachment'
|
|
6
8
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { FileUpload, GraphQLUpload } from 'graphql-upload'
|
|
2
2
|
import { Field, InputType, Int, ObjectType } from 'type-graphql'
|
|
3
|
+
|
|
4
|
+
import { ScalarAny } from '@things-factory/shell'
|
|
5
|
+
|
|
3
6
|
import { Attachment } from './attachment'
|
|
4
7
|
|
|
5
8
|
@ObjectType()
|
|
@@ -11,6 +14,15 @@ export class AttachmentList {
|
|
|
11
14
|
total: number
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
@ObjectType()
|
|
18
|
+
export class UploadURL {
|
|
19
|
+
@Field(type => String)
|
|
20
|
+
url: string
|
|
21
|
+
|
|
22
|
+
@Field(type => ScalarAny)
|
|
23
|
+
fields: ScalarAny
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
@InputType()
|
|
15
27
|
export class NewAttachment {
|
|
16
28
|
@Field({ nullable: true })
|
package/server/storage-file.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import uuid from 'uuid/v4'
|
|
2
1
|
import * as fs from 'fs'
|
|
3
2
|
import * as mkdirp from 'mkdirp'
|
|
4
3
|
import { resolve } from 'path'
|
|
5
|
-
|
|
4
|
+
import uuid from 'uuid/v4'
|
|
6
5
|
|
|
7
6
|
import { config, logger } from '@things-factory/env'
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
import { ATTACHMENT_PATH, STORAGE } from './attachment-const'
|
|
9
|
+
|
|
10
|
+
const send = require('koa-send')
|
|
9
11
|
|
|
10
12
|
if (STORAGE && STORAGE.type == 'file') {
|
|
11
13
|
const uploadDir = config.getPath(null, STORAGE.base || 'attachments')
|
|
@@ -16,11 +18,7 @@ if (STORAGE && STORAGE.type == 'file') {
|
|
|
16
18
|
const id = uuid()
|
|
17
19
|
const ext = filename.split('.').pop()
|
|
18
20
|
const path = ext ? resolve(uploadDir, `${id}.${ext}`) : resolve(uploadDir, id)
|
|
19
|
-
const relativePath = path
|
|
20
|
-
.split('\\')
|
|
21
|
-
.pop()
|
|
22
|
-
.split('/')
|
|
23
|
-
.pop()
|
|
21
|
+
const relativePath = path.split('\\').pop().split('/').pop()
|
|
24
22
|
var size: number = 0
|
|
25
23
|
|
|
26
24
|
return new Promise<{ id: string; path: string; size: number }>((resolve, reject) =>
|
|
@@ -54,5 +52,14 @@ if (STORAGE && STORAGE.type == 'file') {
|
|
|
54
52
|
return fs.readFileSync(fullpath, encoding)
|
|
55
53
|
}
|
|
56
54
|
|
|
55
|
+
STORAGE.generateUploadURL = async (type: string): Promise<{ url: string; fields: { [key: string]: string } }> => {
|
|
56
|
+
const id = uuid()
|
|
57
|
+
|
|
58
|
+
return await {
|
|
59
|
+
url: `/${ATTACHMENT_PATH}`,
|
|
60
|
+
fields: {}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
logger.info('File Storage is Ready.')
|
|
58
65
|
}
|
package/server/storage-s3.ts
CHANGED
|
@@ -1,90 +1,75 @@
|
|
|
1
|
+
import type { Readable } from 'stream'
|
|
1
2
|
import uuid from 'uuid/v4'
|
|
2
|
-
|
|
3
|
+
|
|
4
|
+
import { DeleteObjectCommand, GetObjectCommand, GetObjectCommandInput, S3Client } from '@aws-sdk/client-s3'
|
|
5
|
+
import { Upload } from '@aws-sdk/lib-storage'
|
|
6
|
+
import { createPresignedPost } from '@aws-sdk/s3-presigned-post'
|
|
3
7
|
import { logger } from '@things-factory/env'
|
|
4
|
-
const { PassThrough } = require('stream')
|
|
5
|
-
const mime = require('mime')
|
|
6
|
-
const { fs } = require('memfs')
|
|
7
8
|
|
|
8
9
|
import { STORAGE } from './attachment-const'
|
|
9
10
|
|
|
11
|
+
const mime = require('mime')
|
|
12
|
+
const { fs } = require('memfs')
|
|
13
|
+
|
|
10
14
|
if (STORAGE && STORAGE.type == 's3') {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const client = new S3Client({
|
|
16
|
+
credentials: {
|
|
17
|
+
accessKeyId: STORAGE.accessKeyId,
|
|
18
|
+
secretAccessKey: STORAGE.secretAccessKey
|
|
19
|
+
},
|
|
20
|
+
region: STORAGE.region
|
|
14
21
|
})
|
|
15
22
|
|
|
23
|
+
const streamToBuffer = (stream: Readable) =>
|
|
24
|
+
new Promise<Buffer>((resolve, reject) => {
|
|
25
|
+
const chunks: Buffer[] = []
|
|
26
|
+
stream.on('data', chunk => chunks.push(chunk))
|
|
27
|
+
stream.once('end', () => resolve(Buffer.concat(chunks)))
|
|
28
|
+
stream.once('error', reject)
|
|
29
|
+
})
|
|
30
|
+
|
|
16
31
|
/* upload file */
|
|
17
|
-
STORAGE.uploadFile = ({ stream, filename }) => {
|
|
32
|
+
STORAGE.uploadFile = async ({ stream, filename }) => {
|
|
18
33
|
const id = uuid()
|
|
19
34
|
const ext = filename.split('.').pop()
|
|
20
35
|
const key = ext ? `${id}.${ext}` : id
|
|
21
36
|
var size: number = 0
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Key: key,
|
|
33
|
-
Body: pass
|
|
34
|
-
},
|
|
35
|
-
(err, data) => (err ? reject(err) : resolve({ id, path: key, size }))
|
|
36
|
-
)
|
|
37
|
-
// Response data from S3
|
|
38
|
-
// {
|
|
39
|
-
// ETag:"b2b068edcc5517a75e1119c785e1cf87",
|
|
40
|
-
// Location:"https://opa-one.s3.amazonaws.com/873af101-4e92-4164-b738-062af5b2413b.png",
|
|
41
|
-
// key:"873af101-4e92-4164-b738-062af5b2413b.png",
|
|
42
|
-
// Key:"873af101-4e92-4164-b738-062af5b2413b.png",
|
|
43
|
-
// Bucket:"opa-one"
|
|
44
|
-
// }
|
|
45
|
-
return pass
|
|
46
|
-
})()
|
|
47
|
-
)
|
|
48
|
-
.on('error', error => reject(error))
|
|
49
|
-
.on('data', chunk => (size += chunk.length))
|
|
50
|
-
)
|
|
51
|
-
}
|
|
38
|
+
const upload = new Upload({
|
|
39
|
+
client,
|
|
40
|
+
params: {
|
|
41
|
+
Bucket: STORAGE.bucketName,
|
|
42
|
+
Key: key,
|
|
43
|
+
Body: stream
|
|
44
|
+
// ContentType: 'text/plain',
|
|
45
|
+
}
|
|
46
|
+
})
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
},
|
|
60
|
-
(err, data) => (err ? reject(err) : resolve(data))
|
|
61
|
-
)
|
|
62
|
-
)
|
|
48
|
+
const result = (await upload.done()) as any
|
|
49
|
+
return {
|
|
50
|
+
id,
|
|
51
|
+
path: key,
|
|
52
|
+
size
|
|
53
|
+
}
|
|
63
54
|
}
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// },
|
|
74
|
-
// function(err, data) {
|
|
75
|
-
// if (err) console.log(err, err.stack)
|
|
76
|
-
// else console.log('Bucket Created Successfully', data.Location)
|
|
77
|
-
// }
|
|
78
|
-
// )
|
|
56
|
+
STORAGE.deleteFile = async (path: string) => {
|
|
57
|
+
const command = new DeleteObjectCommand({
|
|
58
|
+
Bucket: STORAGE.bucketName,
|
|
59
|
+
Key: path
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return await client.send(command)
|
|
63
|
+
}
|
|
79
64
|
|
|
80
65
|
/* TODO Streaming to Streaming 으로 구현하라. */
|
|
81
66
|
STORAGE.sendFile = async (context, attachment, next) => {
|
|
82
|
-
const result = await
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
67
|
+
const result = await client.send(
|
|
68
|
+
new GetObjectCommand({
|
|
69
|
+
Bucket: STORAGE.bucketName,
|
|
70
|
+
Key: attachment
|
|
71
|
+
} as GetObjectCommandInput)
|
|
72
|
+
)
|
|
88
73
|
|
|
89
74
|
context.set({
|
|
90
75
|
'Content-Length': result.ContentLength,
|
|
@@ -94,22 +79,42 @@ if (STORAGE && STORAGE.type == 's3') {
|
|
|
94
79
|
'Cache-Control': 'public, max-age=31556926'
|
|
95
80
|
})
|
|
96
81
|
|
|
97
|
-
context.body =
|
|
82
|
+
context.body = result.Body
|
|
98
83
|
}
|
|
99
84
|
|
|
100
|
-
STORAGE.readFile = async (attachment, encoding) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
85
|
+
STORAGE.readFile = async (attachment: string, encoding: string) => {
|
|
86
|
+
/*
|
|
87
|
+
* refered to
|
|
88
|
+
* https://transang.me/modern-fetch-and-how-to-get-buffer-output-from-aws-sdk-v3-getobjectcommand/#the-body-type
|
|
89
|
+
*/
|
|
90
|
+
const result = await client.send(
|
|
91
|
+
new GetObjectCommand({
|
|
92
|
+
Bucket: STORAGE.bucketName,
|
|
93
|
+
Key: attachment
|
|
94
|
+
} as GetObjectCommandInput)
|
|
95
|
+
)
|
|
105
96
|
|
|
106
|
-
var body = result.Body
|
|
97
|
+
var body = result.Body as Readable
|
|
98
|
+
var buffer = await streamToBuffer(body)
|
|
107
99
|
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
switch (encoding) {
|
|
101
|
+
case 'base64':
|
|
102
|
+
return buffer.toString('base64')
|
|
103
|
+
default:
|
|
104
|
+
return await buffer
|
|
110
105
|
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
STORAGE.generateUploadURL = async (type: string): Promise<{ url: string; fields: { [key: string]: string } }> => {
|
|
109
|
+
const expiresInMinutes = 1
|
|
110
|
+
const id = uuid()
|
|
111
111
|
|
|
112
|
-
return
|
|
112
|
+
return await createPresignedPost(client, {
|
|
113
|
+
Bucket: STORAGE.bucketName,
|
|
114
|
+
Key: id,
|
|
115
|
+
Expires: expiresInMinutes * 60,
|
|
116
|
+
Conditions: [['eq', '$Content-Type', type]]
|
|
117
|
+
})
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
logger.info('S3 Bucket Storage is Ready.')
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/controllers/index.ts"],"names":[],"mappings":""}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const v4_1 = __importDefault(require("uuid/v4"));
|
|
7
|
-
const aws_sdk_1 = __importDefault(require("aws-sdk"));
|
|
8
|
-
const env_1 = require("@things-factory/env");
|
|
9
|
-
const { PassThrough } = require('stream');
|
|
10
|
-
const mime = require('mime');
|
|
11
|
-
const { fs } = require('memfs');
|
|
12
|
-
const attachment_const_1 = require("./attachment-const");
|
|
13
|
-
if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 's3') {
|
|
14
|
-
const S3 = new aws_sdk_1.default.S3({
|
|
15
|
-
accessKeyId: attachment_const_1.STORAGE.accessKeyId,
|
|
16
|
-
secretAccessKey: attachment_const_1.STORAGE.secretAccessKey
|
|
17
|
-
});
|
|
18
|
-
/* upload file */
|
|
19
|
-
attachment_const_1.STORAGE.uploadFile = ({ stream, filename }) => {
|
|
20
|
-
const id = (0, v4_1.default)();
|
|
21
|
-
const ext = filename.split('.').pop();
|
|
22
|
-
const key = ext ? `${id}.${ext}` : id;
|
|
23
|
-
var size = 0;
|
|
24
|
-
return new Promise((resolve, reject) => stream
|
|
25
|
-
.pipe((() => {
|
|
26
|
-
var pass = new PassThrough();
|
|
27
|
-
S3.upload({
|
|
28
|
-
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
29
|
-
Key: key,
|
|
30
|
-
Body: pass
|
|
31
|
-
}, (err, data) => (err ? reject(err) : resolve({ id, path: key, size })));
|
|
32
|
-
// Response data from S3
|
|
33
|
-
// {
|
|
34
|
-
// ETag:"b2b068edcc5517a75e1119c785e1cf87",
|
|
35
|
-
// Location:"https://opa-one.s3.amazonaws.com/873af101-4e92-4164-b738-062af5b2413b.png",
|
|
36
|
-
// key:"873af101-4e92-4164-b738-062af5b2413b.png",
|
|
37
|
-
// Key:"873af101-4e92-4164-b738-062af5b2413b.png",
|
|
38
|
-
// Bucket:"opa-one"
|
|
39
|
-
// }
|
|
40
|
-
return pass;
|
|
41
|
-
})())
|
|
42
|
-
.on('error', error => reject(error))
|
|
43
|
-
.on('data', chunk => (size += chunk.length)));
|
|
44
|
-
};
|
|
45
|
-
attachment_const_1.STORAGE.deleteFile = path => {
|
|
46
|
-
return new Promise((resolve, reject) => S3.deleteObject({
|
|
47
|
-
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
48
|
-
Key: path
|
|
49
|
-
}, (err, data) => (err ? reject(err) : resolve(data))));
|
|
50
|
-
};
|
|
51
|
-
/* creating bucket */
|
|
52
|
-
// s3.createBucket(
|
|
53
|
-
// {
|
|
54
|
-
// Bucket: STORAGE.bucketName,
|
|
55
|
-
// CreateBucketConfiguration: {
|
|
56
|
-
// // Set your region here
|
|
57
|
-
// LocationConstraint: 'eu-west-1'
|
|
58
|
-
// }
|
|
59
|
-
// },
|
|
60
|
-
// function(err, data) {
|
|
61
|
-
// if (err) console.log(err, err.stack)
|
|
62
|
-
// else console.log('Bucket Created Successfully', data.Location)
|
|
63
|
-
// }
|
|
64
|
-
// )
|
|
65
|
-
/* TODO Streaming to Streaming 으로 구현하라. */
|
|
66
|
-
attachment_const_1.STORAGE.sendFile = async (context, attachment, next) => {
|
|
67
|
-
const result = await S3.getObject({
|
|
68
|
-
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
69
|
-
Key: attachment
|
|
70
|
-
}).promise();
|
|
71
|
-
fs.writeFileSync(`/${attachment}`, result.Body);
|
|
72
|
-
context.set({
|
|
73
|
-
'Content-Length': result.ContentLength,
|
|
74
|
-
'Content-Type': mime.getType(attachment),
|
|
75
|
-
'Last-Modified': result.LastModified,
|
|
76
|
-
ETag: result.ETag,
|
|
77
|
-
'Cache-Control': 'public, max-age=31556926'
|
|
78
|
-
});
|
|
79
|
-
context.body = await fs.createReadStream(`/${attachment}`);
|
|
80
|
-
};
|
|
81
|
-
attachment_const_1.STORAGE.readFile = async (attachment, encoding) => {
|
|
82
|
-
const result = await S3.getObject({
|
|
83
|
-
Bucket: attachment_const_1.STORAGE.bucketName,
|
|
84
|
-
Key: attachment
|
|
85
|
-
}).promise();
|
|
86
|
-
var body = result.Body;
|
|
87
|
-
if (encoding) {
|
|
88
|
-
return body.toString(encoding);
|
|
89
|
-
}
|
|
90
|
-
return body;
|
|
91
|
-
};
|
|
92
|
-
env_1.logger.info('S3 Bucket Storage is Ready.');
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=storage-s3-v2.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage-s3-v2.js","sourceRoot":"","sources":["../server/storage-s3-v2.ts"],"names":[],"mappings":"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"}
|
|
File without changes
|