@things-factory/attachment-base 10.1.111 → 10.1.112
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/dist-server/attachment-access.d.ts +21 -0
- package/dist-server/attachment-access.js +111 -0
- package/dist-server/attachment-access.js.map +1 -0
- package/dist-server/attachment-const.d.ts +5 -0
- package/dist-server/attachment-const.js +6 -1
- package/dist-server/attachment-const.js.map +1 -1
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/routes.js +59 -17
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/attachment/index.d.ts +1 -1
- package/dist-server/service/attachment-share/attachment-share-mutation.d.ts +11 -0
- package/dist-server/service/attachment-share/attachment-share-mutation.js +87 -0
- package/dist-server/service/attachment-share/attachment-share-mutation.js.map +1 -0
- package/dist-server/service/attachment-share/attachment-share-rule.d.ts +16 -0
- package/dist-server/service/attachment-share/attachment-share-rule.js +41 -0
- package/dist-server/service/attachment-share/attachment-share-rule.js.map +1 -0
- package/dist-server/service/attachment-share/attachment-share.d.ts +15 -0
- package/dist-server/service/attachment-share/attachment-share.js +72 -0
- package/dist-server/service/attachment-share/attachment-share.js.map +1 -0
- package/dist-server/service/attachment-share/index.d.ts +4 -0
- package/dist-server/service/attachment-share/index.js +8 -0
- package/dist-server/service/attachment-share/index.js.map +1 -0
- package/dist-server/service/index.d.ts +4 -2
- package/dist-server/service/index.js +7 -2
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/storage-azure-blob.js +1 -1
- package/dist-server/storage-azure-blob.js.map +1 -1
- package/dist-server/storage-s3.js +1 -1
- package/dist-server/storage-s3.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/tests/attachment-access.test.ts +93 -0
- package/tests/attachment-route.test.ts +88 -0
- package/translations/en.json +3 -2
- package/translations/ja.json +2 -1
- package/translations/ko.json +3 -2
- package/translations/ms.json +2 -1
- package/translations/zh.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-share.js","sourceRoot":"","sources":["../../../server/service/attachment-share/attachment-share.ts"],"names":[],"mappings":";;;;AAAA,qCAAgH;AAChH,+CAAoD;AAEpD,iDAA8C;AAC9C,yDAAgD;AAEhD,yDAAqD;AAErD;;;;;;GAMG;AAII,IAAM,eAAe,GAArB,MAAM,eAAe;CAqC3B,CAAA;AArCY,0CAAe;AAGjB;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;;2CACxD;AAInB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,WAAW,EAAE,uCAAuC,EAAE,CAAC;sCACxE,cAAM;+CAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,KAAsB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;;iDACrC;AAIhB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,uBAAU,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,uBAAU,EAAE,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC;sCACjE,uBAAU;mDAAA;AAGtB;IADC,IAAA,oBAAU,EAAC,CAAC,KAAsB,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;;qDACrC;AAIpB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;sCACjE,gBAAI;gDAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,KAAsB,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;;kDACpC;AAIlB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;sCAC5C,IAAI;kDAAA;AAIf;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;sCACvE,IAAI;kDAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC;sCACvC,IAAI;kDAAA;0BApCJ,eAAe;IAH3B,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,uBAAuB,EAAE,CAAC,KAAsB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5F,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,4EAA4E,EAAE,CAAC;GAC7F,eAAe,CAqC3B","sourcesContent":["import { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\nimport { Attachment } from '../attachment/attachment'\n\n/*\n * A link to one attachment handed outside the domain - Label Studio, a mail, a person told by hand (ADR-0106 decision 3).\n *\n * The row is the record and the off switch: who made it, for which attachment, until when, and whether it was taken\n * back. The URL carries this row's id and an HMAC over (id, attachment, domain, expiry); the attachment's own path is\n * not in it.\n */\n@Entity()\n@Index('ix_attachment_share_0', (share: AttachmentShare) => [share.domain, share.attachment])\n@ObjectType({ description: 'A signed, expiring link to one attachment, for someone outside the domain.' })\nexport class AttachmentShare {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the share link.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { description: 'The domain the attachment belongs to.' })\n domain: Domain\n\n @RelationId((share: AttachmentShare) => share.domain)\n domainId: string\n\n @ManyToOne(type => Attachment, { onDelete: 'CASCADE' })\n @Field(type => Attachment, { description: 'The attachment the link opens.' })\n attachment: Attachment\n\n @RelationId((share: AttachmentShare) => share.attachment)\n attachmentId: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who made the link.' })\n creator?: User\n\n @RelationId((share: AttachmentShare) => share.creator)\n creatorId?: string\n\n @Column()\n @Field({ description: 'When the link stops opening.' })\n expiresAt: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'When the link was taken back, if it was.' })\n revokedAt?: Date\n\n @CreateDateColumn()\n @Field({ description: 'When the link was made.' })\n createdAt: Date\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvers = exports.entities = void 0;
|
|
4
|
+
const attachment_share_1 = require("./attachment-share");
|
|
5
|
+
const attachment_share_mutation_1 = require("./attachment-share-mutation");
|
|
6
|
+
exports.entities = [attachment_share_1.AttachmentShare];
|
|
7
|
+
exports.resolvers = [attachment_share_mutation_1.AttachmentShareMutation];
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/attachment-share/index.ts"],"names":[],"mappings":";;;AAAA,yDAAoD;AACpD,2EAAqE;AAExD,QAAA,QAAQ,GAAG,CAAC,kCAAe,CAAC,CAAA;AAC5B,QAAA,SAAS,GAAG,CAAC,mDAAuB,CAAC,CAAA","sourcesContent":["import { AttachmentShare } from './attachment-share'\nimport { AttachmentShareMutation } from './attachment-share-mutation'\n\nexport const entities = [AttachmentShare]\nexport const resolvers = [AttachmentShareMutation]\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './attachment/attachment';
|
|
2
|
+
export * from './attachment-share/attachment-share';
|
|
3
|
+
export * from './attachment-share/attachment-share-rule';
|
|
2
4
|
export * from './attachment/attachment-types';
|
|
3
|
-
export declare const entities: typeof import("./attachment/attachment").Attachment[];
|
|
5
|
+
export declare const entities: (typeof import("./attachment-share/attachment-share").AttachmentShare | typeof import("./attachment/attachment").Attachment)[];
|
|
4
6
|
export declare const schema: {
|
|
5
|
-
resolverClasses: (typeof import("./attachment/attachment-mutation").
|
|
7
|
+
resolverClasses: (typeof import("./attachment-share/attachment-share-mutation").AttachmentShareMutation | typeof import("./attachment/attachment-query").AttachmentQuery | typeof import("./attachment/attachment-mutation").AttachmentMutation)[];
|
|
6
8
|
};
|
|
@@ -4,18 +4,23 @@ exports.schema = exports.entities = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
/* IMPORT ENTITIES AND RESOLVERS */
|
|
6
6
|
const attachment_1 = require("./attachment");
|
|
7
|
+
const attachment_share_1 = require("./attachment-share");
|
|
7
8
|
/* EXPORT ENTITY TYPES */
|
|
8
9
|
tslib_1.__exportStar(require("./attachment/attachment"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./attachment-share/attachment-share"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./attachment-share/attachment-share-rule"), exports);
|
|
9
12
|
/* EXPORT TYPES */
|
|
10
13
|
tslib_1.__exportStar(require("./attachment/attachment-types"), exports);
|
|
11
14
|
exports.entities = [
|
|
12
15
|
/* ENTITIES */
|
|
13
|
-
...attachment_1.entities
|
|
16
|
+
...attachment_1.entities,
|
|
17
|
+
...attachment_share_1.entities
|
|
14
18
|
];
|
|
15
19
|
exports.schema = {
|
|
16
20
|
resolverClasses: [
|
|
17
21
|
/* RESOLVER CLASSES */
|
|
18
|
-
...attachment_1.resolvers
|
|
22
|
+
...attachment_1.resolvers,
|
|
23
|
+
...attachment_share_1.resolvers
|
|
19
24
|
]
|
|
20
25
|
};
|
|
21
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,mCAAmC;AACnC,6CAA6F;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,mCAAmC;AACnC,6CAA6F;AAC7F,yDAA6G;AAE7G,yBAAyB;AACzB,kEAAuC;AACvC,8EAAmD;AACnD,mFAAwD;AACxD,kBAAkB;AAClB,wEAA6C;AAEhC,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,qBAAgB;IACnB,GAAG,2BAAqB;CACzB,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,sBAAmB;QACtB,GAAG,4BAAwB;KAC5B;CACF,CAAA","sourcesContent":["/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as AttachmentEntity, resolvers as AttachmentResolvers } from './attachment'\nimport { entities as AttachmentShareEntity, resolvers as AttachmentShareResolvers } from './attachment-share'\n\n/* EXPORT ENTITY TYPES */\nexport * from './attachment/attachment'\nexport * from './attachment-share/attachment-share'\nexport * from './attachment-share/attachment-share-rule'\n/* EXPORT TYPES */\nexport * from './attachment/attachment-types'\n\nexport const entities = [\n /* ENTITIES */\n ...AttachmentEntity,\n ...AttachmentShareEntity\n]\n\nexport const schema = {\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...AttachmentResolvers,\n ...AttachmentShareResolvers\n ]\n}\n"]}
|
|
@@ -54,7 +54,7 @@ if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 'azureblob'
|
|
|
54
54
|
'Content-Type': mime.getType(attachment),
|
|
55
55
|
'Last-Modified': result.lastModified.toUTCString(),
|
|
56
56
|
ETag: result.etag,
|
|
57
|
-
'Cache-Control':
|
|
57
|
+
'Cache-Control': attachment_const_1.ATTACHMENT_CACHE_CONTROL
|
|
58
58
|
});
|
|
59
59
|
context.body = body;
|
|
60
60
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-azure-blob.js","sourceRoot":"","sources":["../server/storage-azure-blob.ts"],"names":[],"mappings":";;AAAA,sDAAuD;AACvD,6CAA4C;AAE5C,
|
|
1
|
+
{"version":3,"file":"storage-azure-blob.js","sourceRoot":"","sources":["../server/storage-azure-blob.ts"],"names":[],"mappings":"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","sourcesContent":["import { BlobServiceClient } from '@azure/storage-blob'\nimport { logger } from '@things-factory/env'\n\nimport { ATTACHMENT_CACHE_CONTROL, STORAGE } from './attachment-const'\n\nconst crypto = require('crypto')\nconst mime = require('mime')\n\nif (STORAGE && STORAGE.type == 'azureblob') {\n const blobServiceClient = BlobServiceClient.fromConnectionString(STORAGE.connectionString)\n\n /* upload file */\n STORAGE.uploadFile = async ({ id, file }) => {\n const { createReadStream, filename, mimetype, encoding } = await file\n\n const containerClient = blobServiceClient.getContainerClient(STORAGE.containerName)\n id = id || crypto.randomUUID()\n const ext = filename.split('.').pop()\n const key = ext ? `${id}.${ext}` : id\n\n const blockBlobClient = containerClient.getBlockBlobClient(key)\n const stream = createReadStream()\n const buffer = await streamToBuffer(stream)\n\n await blockBlobClient.upload(buffer, buffer.length, {\n blobHTTPHeaders: {\n blobContentType: mimetype\n }\n })\n\n // await blockBlobClient.uploadStream(stream, undefined, undefined, {\n // blobHTTPHeaders: {\n // blobContentType: mimetype\n // }\n // })\n\n const url = `${STORAGE.url}/${STORAGE.containerName}/${key}`\n return {\n id,\n path: key,\n filename,\n size: buffer.length,\n mimetype,\n encoding\n }\n }\n\n STORAGE.deleteFile = async (path: string) => {\n const containerClient = blobServiceClient.getContainerClient(STORAGE.containerName)\n const blockBlobClient = containerClient.getBlockBlobClient(path)\n await blockBlobClient.deleteIfExists()\n }\n\n /* TODO Streaming to Streaming 으로 구현하라. */\n STORAGE.sendFile = async (context, attachment, next) => {\n const containerClient = blobServiceClient.getContainerClient(STORAGE.containerName)\n const blockBlobClient = containerClient.getBlockBlobClient(attachment)\n\n const result = await blockBlobClient.getProperties()\n const response = await blockBlobClient.download(0)\n const body = response.readableStreamBody\n\n context.set({\n 'Content-Length': result.contentLength,\n 'Content-Type': mime.getType(attachment),\n 'Last-Modified': result.lastModified.toUTCString(),\n ETag: result.etag,\n 'Cache-Control': ATTACHMENT_CACHE_CONTROL\n })\n\n context.body = body\n }\n\n STORAGE.readFile = async (attachment: string, encoding: string) => {\n const containerClient = blobServiceClient.getContainerClient(STORAGE.containerName)\n const blockBlobClient = containerClient.getBlockBlobClient(attachment)\n\n const response = await blockBlobClient.download(0)\n const body = response.readableStreamBody\n\n const buffer = Buffer.from(await streamToBuffer(body))\n\n switch (encoding) {\n case 'base64':\n return buffer.toString('base64')\n default:\n return buffer\n }\n }\n\n STORAGE.generateUploadURL = async (type: string): Promise<{ url: string; fields: { [key: string]: string } }> => {\n const expiresInMinutes = 1\n const id = crypto.randomUUID()\n\n return {\n url: `${STORAGE.url}/${STORAGE.containerName}/${id}`,\n fields: {}\n }\n }\n\n logger.info('Azure Blob Storage is Ready.')\n}\n\nasync function streamToBuffer(stream): Promise<Buffer> {\n return new Promise<Buffer>((resolve, reject) => {\n const chunks = []\n stream.on('data', chunk => chunks.push(chunk))\n stream.on('end', () => resolve(Buffer.concat(chunks)))\n stream.on('error', reject)\n })\n}\n"]}
|
|
@@ -72,7 +72,7 @@ if (attachment_const_1.STORAGE && attachment_const_1.STORAGE.type == 's3') {
|
|
|
72
72
|
'Content-Type': mime.getType(attachment),
|
|
73
73
|
'Last-Modified': result.LastModified.toUTCString(),
|
|
74
74
|
ETag: result.ETag,
|
|
75
|
-
'Cache-Control':
|
|
75
|
+
'Cache-Control': attachment_const_1.ATTACHMENT_CACHE_CONTROL
|
|
76
76
|
});
|
|
77
77
|
context.body = result.Body;
|
|
78
78
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-s3.js","sourceRoot":"","sources":["../server/storage-s3.ts"],"names":[],"mappings":";;AAEA,kDAM2B;AAC3B,sDAA6C;AAC7C,kEAAgE;AAChE,6CAA4C;AAE5C,
|
|
1
|
+
{"version":3,"file":"storage-s3.js","sourceRoot":"","sources":["../server/storage-s3.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Readable } from 'stream'\n\nimport {\n DeleteObjectCommand,\n GetObjectCommand,\n GetObjectCommandInput,\n HeadObjectCommand,\n S3Client\n} from '@aws-sdk/client-s3'\nimport { Upload } from '@aws-sdk/lib-storage'\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post'\nimport { logger } from '@things-factory/env'\n\nimport { ATTACHMENT_CACHE_CONTROL, STORAGE } from './attachment-const'\n\nconst crypto = require('crypto')\nconst mime = require('mime')\n\nif (STORAGE && STORAGE.type == 's3') {\n const client = new S3Client({\n credentials: {\n accessKeyId: STORAGE.accessKeyId,\n secretAccessKey: STORAGE.secretAccessKey\n },\n region: STORAGE.region\n })\n\n const streamToBuffer = (stream: Readable) =>\n new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = []\n stream.on('data', chunk => chunks.push(chunk))\n stream.once('end', () => resolve(Buffer.concat(chunks)))\n stream.once('error', reject)\n })\n\n /* upload file */\n STORAGE.uploadFile = async ({ id, file }) => {\n var { createReadStream, filename, mimetype, encoding } = await file\n filename = Buffer.from(filename, 'latin1')\n .toString('utf-8')\n .normalize('NFC') /* Because busboy uses latin1 encoding */\n\n const stream = createReadStream()\n id = id || crypto.randomUUID()\n const ext = filename.split('.').pop()\n const key = ext ? `${id}.${ext}` : id\n\n const upload = new Upload({\n client,\n params: {\n Bucket: STORAGE.bucketName,\n Key: key,\n Body: stream\n }\n })\n\n await upload.done()\n\n const headObjectCommand = new HeadObjectCommand({\n Bucket: STORAGE.bucketName,\n Key: key\n })\n\n const { ContentLength } = await client.send(headObjectCommand)\n\n return {\n id,\n path: key,\n filename,\n size: ContentLength,\n mimetype,\n encoding\n }\n }\n\n STORAGE.deleteFile = async (path: string) => {\n const command = new DeleteObjectCommand({\n Bucket: STORAGE.bucketName,\n Key: path\n })\n\n return await client.send(command)\n }\n\n /* TODO Streaming to Streaming 으로 구현하라. */\n STORAGE.sendFile = async (context, attachment, next) => {\n const result = await client.send(\n new GetObjectCommand({\n Bucket: STORAGE.bucketName,\n Key: attachment\n } as GetObjectCommandInput)\n )\n\n context.set({\n 'Content-Length': result.ContentLength,\n 'Content-Type': mime.getType(attachment),\n 'Last-Modified': result.LastModified.toUTCString(),\n ETag: result.ETag,\n 'Cache-Control': ATTACHMENT_CACHE_CONTROL\n })\n\n context.body = result.Body\n }\n\n STORAGE.readFile = async (attachment: string, encoding: string) => {\n /*\n * refered to\n * https://transang.me/modern-fetch-and-how-to-get-buffer-output-from-aws-sdk-v3-getobjectcommand/#the-body-type\n */\n const result = await client.send(\n new GetObjectCommand({\n Bucket: STORAGE.bucketName,\n Key: attachment\n } as GetObjectCommandInput)\n )\n\n var body = result.Body as Readable\n var buffer = await streamToBuffer(body)\n\n switch (encoding) {\n case 'base64':\n return buffer.toString('base64')\n default:\n return await buffer\n }\n }\n\n STORAGE.generateUploadURL = async (type: string): Promise<{ url: string; fields: { [key: string]: string } }> => {\n const expiresInMinutes = 1\n const id = crypto.randomUUID()\n\n return await createPresignedPost(client, {\n Bucket: STORAGE.bucketName,\n Key: id,\n Expires: expiresInMinutes * 60,\n Conditions: [['eq', '$Content-Type', type]]\n })\n }\n\n logger.info('S3 Bucket Storage is Ready.')\n}\n"]}
|