@nocobase/plugin-file-manager 2.2.0-beta.13 → 2.2.0-beta.14

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.
Files changed (65) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/client/templates/file.d.ts +1 -1
  3. package/dist/client-v2/125.9cdb7cf3ef4712ef.js +10 -0
  4. package/dist/client-v2/450.d49b00f3c0388c74.js +10 -0
  5. package/dist/client-v2/index.d.ts +1 -1
  6. package/dist/client-v2/index.js +1 -1
  7. package/dist/client-v2/models/DisplayPreviewFieldModel.d.ts +22 -0
  8. package/dist/client-v2/models/UploadActionModel.d.ts +26 -0
  9. package/dist/client-v2/previewer/filePreviewTypes.d.ts +15 -1
  10. package/dist/externalVersion.js +12 -9
  11. package/dist/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +59 -116
  12. package/dist/node_modules/@aws-sdk/client-s3/package.json +1 -1
  13. package/dist/node_modules/@aws-sdk/lib-storage/dist-cjs/index.js +59 -116
  14. package/dist/node_modules/@aws-sdk/lib-storage/package.json +1 -1
  15. package/dist/node_modules/@aws-sdk/s3-request-presigner/LICENSE +201 -0
  16. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-cjs/index.js +11113 -0
  17. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-es/constants.js +9 -0
  18. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-es/getSignedUrl.js +66 -0
  19. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-es/index.js +2 -0
  20. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-es/presigner.js +58 -0
  21. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/constants.d.ts +9 -0
  22. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/getSignedUrl.d.ts +6 -0
  23. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/index.d.ts +2 -0
  24. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/presigner.d.ts +15 -0
  25. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/ts3.4/constants.d.ts +9 -0
  26. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/ts3.4/getSignedUrl.d.ts +11 -0
  27. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/ts3.4/index.d.ts +2 -0
  28. package/dist/node_modules/@aws-sdk/s3-request-presigner/dist-types/ts3.4/presigner.d.ts +40 -0
  29. package/dist/node_modules/@aws-sdk/s3-request-presigner/package.json +1 -0
  30. package/dist/node_modules/ali-oss/package.json +1 -1
  31. package/dist/node_modules/cos-nodejs-sdk-v5/package.json +1 -1
  32. package/dist/node_modules/mime-match/package.json +1 -1
  33. package/dist/node_modules/mime-types/package.json +1 -1
  34. package/dist/node_modules/mkdirp/package.json +1 -1
  35. package/dist/node_modules/url-join/package.json +1 -1
  36. package/dist/server/actions/get-file.d.ts +13 -0
  37. package/dist/server/actions/get-file.js +133 -0
  38. package/dist/server/actions/index.d.ts +1 -3
  39. package/dist/server/actions/index.js +8 -1
  40. package/dist/server/commands/repair-filenames.js +34 -14
  41. package/dist/server/file-access.d.ts +11 -0
  42. package/dist/server/file-access.js +134 -0
  43. package/dist/server/index.d.ts +2 -1
  44. package/dist/server/index.js +7 -1
  45. package/dist/server/resolve-file-access-filter.d.ts +11 -0
  46. package/dist/server/resolve-file-access-filter.js +63 -0
  47. package/dist/server/server.d.ts +23 -2
  48. package/dist/server/server.js +102 -10
  49. package/dist/server/storages/ali-oss.d.ts +2 -1
  50. package/dist/server/storages/ali-oss.js +12 -0
  51. package/dist/server/storages/index.d.ts +15 -2
  52. package/dist/server/storages/index.js +28 -5
  53. package/dist/server/storages/local.d.ts +2 -2
  54. package/dist/server/storages/local.js +9 -3
  55. package/dist/server/storages/s3.d.ts +2 -1
  56. package/dist/server/storages/s3.js +14 -0
  57. package/dist/server/storages/tx-cos.d.ts +2 -1
  58. package/dist/server/storages/tx-cos.js +27 -0
  59. package/dist/server/temporary-access.d.ts +31 -0
  60. package/dist/server/temporary-access.js +169 -0
  61. package/dist/server/utils.d.ts +27 -0
  62. package/dist/server/utils.js +83 -2
  63. package/package.json +5 -3
  64. package/dist/client-v2/125.0b8eef1f19b87042.js +0 -10
  65. package/dist/client-v2/450.c060947ac34d26e1.js +0 -10
@@ -53,6 +53,11 @@ var import__ = require(".");
53
53
  var import_constants = require("../../constants");
54
54
  var import_utils2 = require("../utils");
55
55
  const DEFAULT_BASE_URL = "/storage/uploads";
56
+ function appendDownloadParam(url) {
57
+ const [urlWithoutHash, hash] = url.split("#", 2);
58
+ const separator = urlWithoutHash.includes("?") ? "&" : "?";
59
+ return `${urlWithoutHash}${separator}download=1${hash ? `#${hash}` : ""}`;
60
+ }
56
61
  function pathError(message) {
57
62
  const error = new Error(message);
58
63
  error.code = "PATH_TRAVERSAL";
@@ -182,12 +187,13 @@ class local_default extends import__.StorageType {
182
187
  );
183
188
  return [count, undeleted];
184
189
  }
185
- async getFileURL(file, preview = false) {
186
- const url = await super.getFileURL(file, preview);
190
+ async getFileURL(file, preview = false, options = {}) {
191
+ const url = await super.getFileURL(file, preview, options);
187
192
  if ((0, import_utils.isURL)(url)) {
188
193
  return url;
189
194
  }
190
- return (0, import_url_join.default)(process.env.APP_PUBLIC_PATH, url);
195
+ const publicUrl = (0, import_url_join.default)(process.env.APP_PUBLIC_PATH, url);
196
+ return options.download ? appendDownloadParam(publicUrl) : publicUrl;
191
197
  }
192
198
  async getFileStream(file) {
193
199
  const filePath = resolveSafePath(getDocumentRoot(this.storage), file.path, file.filename);
@@ -7,7 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { S3Client } from '@aws-sdk/client-s3';
10
- import { AttachmentModel, StorageModel, StorageType } from '.';
10
+ import { AttachmentModel, GetFileURLOptions, StorageModel, StorageType } from '.';
11
11
  export default class extends StorageType {
12
12
  static defaults(): {
13
13
  title: string;
@@ -24,6 +24,7 @@ export default class extends StorageType {
24
24
  static filenameKey: string;
25
25
  client: S3Client;
26
26
  constructor(storage: StorageModel);
27
+ getFileURL(file: AttachmentModel, preview?: boolean, options?: GetFileURLOptions): Promise<string>;
27
28
  make(): {
28
29
  s3: S3Client;
29
30
  _handleFile(req: any, file: any, cb: any): Promise<void>;
@@ -31,6 +31,7 @@ __export(s3_exports, {
31
31
  module.exports = __toCommonJS(s3_exports);
32
32
  var import_client_s3 = require("@aws-sdk/client-s3");
33
33
  var import_lib_storage = require("@aws-sdk/lib-storage");
34
+ var import_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
34
35
  var import_stream = require("stream");
35
36
  var import__ = require(".");
36
37
  var import_constants = require("../../constants");
@@ -81,6 +82,19 @@ class s3_default extends import__.StorageType {
81
82
  this.client.middlewareStack.remove("flexibleChecksumsMiddleware");
82
83
  this.client.middlewareStack.remove("flexibleChecksumsInputMiddleware");
83
84
  }
85
+ async getFileURL(file, preview = false, options = {}) {
86
+ if (!options.download) {
87
+ return super.getFileURL(file, preview, options);
88
+ }
89
+ const command = new import_client_s3.GetObjectCommand({
90
+ Bucket: this.storage.options.bucket,
91
+ Key: this.getFileKey(file),
92
+ ResponseContentDisposition: (0, import__.getDownloadContentDisposition)(file.filename)
93
+ });
94
+ return (0, import_s3_request_presigner.getSignedUrl)(this.client, command, {
95
+ expiresIn: this.storage.options.signedUrlExpires || 900
96
+ });
97
+ }
84
98
  make() {
85
99
  const { bucket, acl = "public-read" } = this.storage.options;
86
100
  const keyGetter = (0, import_utils2.cloudFilenameGetter)(this.storage);
@@ -6,7 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- import { AttachmentModel, StorageType } from '.';
9
+ import { AttachmentModel, GetFileURLOptions, StorageType } from '.';
10
10
  declare class TxCosStorage {
11
11
  cos: any;
12
12
  getFilename: Function;
@@ -36,6 +36,7 @@ export default class extends StorageType {
36
36
  };
37
37
  static filenameKey: string;
38
38
  make(): TxCosStorage;
39
+ getFileURL(file: AttachmentModel, preview?: boolean, options?: GetFileURLOptions): Promise<string>;
39
40
  exists(record: AttachmentModel): Promise<boolean>;
40
41
  copy(source: AttachmentModel, target: AttachmentModel): Promise<void>;
41
42
  delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]>;
@@ -160,6 +160,33 @@ class tx_cos_default extends import__.StorageType {
160
160
  filename: (0, import_utils.cloudFilenameGetter)(this.storage)
161
161
  });
162
162
  }
163
+ async getFileURL(file, preview = false, options = {}) {
164
+ if (!options.download) {
165
+ return super.getFileURL(file, preview, options);
166
+ }
167
+ const { cos } = this.make();
168
+ return new Promise((resolve, reject) => {
169
+ cos.getObjectUrl(
170
+ {
171
+ Region: this.storage.options.Region,
172
+ Bucket: this.storage.options.Bucket,
173
+ Key: (0, import_utils.getFileKey)(file),
174
+ Sign: true,
175
+ Expires: this.storage.options.signedUrlExpires || 900,
176
+ Query: {
177
+ "response-content-disposition": (0, import__.getDownloadContentDisposition)(file.filename)
178
+ }
179
+ },
180
+ (error, data) => {
181
+ if (error) {
182
+ reject(error);
183
+ return;
184
+ }
185
+ resolve(data.Url);
186
+ }
187
+ );
188
+ });
189
+ }
163
190
  async exists(record) {
164
191
  const { cos } = this.make();
165
192
  try {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ /// <reference types="node" />
10
+ import type { Context, Next } from '@nocobase/actions';
11
+ import type { DataSource } from '@nocobase/data-source-manager';
12
+ import { type JwtPayload, type SignOptions } from 'jsonwebtoken';
13
+ import type { PluginFileManagerServer } from './server';
14
+ export declare const CREATE_TEMPORARY_URL_ACTION = "createTemporaryURL";
15
+ export declare const TEMPORARY_FILE_ACCESS_AUDIENCE = "temporary-file-access";
16
+ export type TemporaryFileAccessPayload = JwtPayload & {
17
+ app: string;
18
+ dataSource: string;
19
+ collection: string;
20
+ id: string;
21
+ storageId: string | number;
22
+ role?: string;
23
+ };
24
+ type TemporaryFileAccessResource = Pick<TemporaryFileAccessPayload, 'app' | 'dataSource' | 'collection' | 'id' | 'storageId' | 'sub' | 'role'>;
25
+ export declare function getTemporaryFileAccessExpiresIn(): SignOptions['expiresIn'];
26
+ export declare function deriveTemporaryFileAccessSecret(plugin: PluginFileManagerServer): Buffer;
27
+ export declare function signTemporaryFileAccessToken(plugin: PluginFileManagerServer, resource: TemporaryFileAccessResource, options?: Pick<SignOptions, 'expiresIn'>): string;
28
+ export declare function verifyTemporaryFileAccessToken(plugin: PluginFileManagerServer, token: string): TemporaryFileAccessPayload;
29
+ export declare function createTemporaryURLAction(ctx: Context, next: Next): Promise<never>;
30
+ export declare function registerTemporaryFileAccess(dataSource: DataSource): void;
31
+ export {};
@@ -0,0 +1,169 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+ var temporary_access_exports = {};
38
+ __export(temporary_access_exports, {
39
+ CREATE_TEMPORARY_URL_ACTION: () => CREATE_TEMPORARY_URL_ACTION,
40
+ TEMPORARY_FILE_ACCESS_AUDIENCE: () => TEMPORARY_FILE_ACCESS_AUDIENCE,
41
+ createTemporaryURLAction: () => createTemporaryURLAction,
42
+ deriveTemporaryFileAccessSecret: () => deriveTemporaryFileAccessSecret,
43
+ getTemporaryFileAccessExpiresIn: () => getTemporaryFileAccessExpiresIn,
44
+ registerTemporaryFileAccess: () => registerTemporaryFileAccess,
45
+ signTemporaryFileAccessToken: () => signTemporaryFileAccessToken,
46
+ verifyTemporaryFileAccessToken: () => verifyTemporaryFileAccessToken
47
+ });
48
+ module.exports = __toCommonJS(temporary_access_exports);
49
+ var import_crypto = require("crypto");
50
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
51
+ var import_utils = require("./utils");
52
+ var import_resolve_file_access_filter = require("./resolve-file-access-filter");
53
+ const CREATE_TEMPORARY_URL_ACTION = "createTemporaryURL";
54
+ const TEMPORARY_FILE_ACCESS_AUDIENCE = "temporary-file-access";
55
+ const DEFAULT_EXPIRES_IN = "10m";
56
+ const MIN_EXPIRES_IN_SECONDS = 5 * 60;
57
+ const MAX_EXPIRES_IN_SECONDS = 10 * 60;
58
+ function isFileCollection(collection) {
59
+ var _a;
60
+ return Boolean(collection && (collection.name === "attachments" || ((_a = collection.options) == null ? void 0 : _a.template) === "file"));
61
+ }
62
+ function getTemporaryFileAccessExpiresIn() {
63
+ const value = process.env.TEMPORARY_FILE_ACCESS_EXPIRES_IN || DEFAULT_EXPIRES_IN;
64
+ const matched = /^(\d+)(s|m)$/.exec(value);
65
+ const seconds = matched ? Number(matched[1]) * (matched[2] === "m" ? 60 : 1) : Number.NaN;
66
+ if (!Number.isFinite(seconds) || seconds < MIN_EXPIRES_IN_SECONDS || seconds > MAX_EXPIRES_IN_SECONDS) {
67
+ throw new Error("TEMPORARY_FILE_ACCESS_EXPIRES_IN must be between 5m and 10m");
68
+ }
69
+ return value;
70
+ }
71
+ function deriveTemporaryFileAccessSecret(plugin) {
72
+ const appName = plugin.app.name || "main";
73
+ const authSecret = plugin.app.authManager.jwt.getSecret();
74
+ return (0, import_crypto.createHmac)("sha256", authSecret).update(`temporary-file-access:${appName}`).digest();
75
+ }
76
+ function signTemporaryFileAccessToken(plugin, resource, options = {}) {
77
+ const currentUserId = resource.sub;
78
+ return import_jsonwebtoken.default.sign(
79
+ {
80
+ app: resource.app,
81
+ dataSource: resource.dataSource,
82
+ collection: resource.collection,
83
+ id: String(resource.id),
84
+ storageId: resource.storageId,
85
+ ...resource.role ? { role: resource.role } : {}
86
+ },
87
+ deriveTemporaryFileAccessSecret(plugin),
88
+ {
89
+ algorithm: "HS256",
90
+ audience: TEMPORARY_FILE_ACCESS_AUDIENCE,
91
+ ...currentUserId ? { subject: String(currentUserId) } : {},
92
+ expiresIn: options.expiresIn || getTemporaryFileAccessExpiresIn()
93
+ }
94
+ );
95
+ }
96
+ function verifyTemporaryFileAccessToken(plugin, token) {
97
+ const decoded = import_jsonwebtoken.default.verify(token, deriveTemporaryFileAccessSecret(plugin), {
98
+ algorithms: ["HS256"],
99
+ audience: TEMPORARY_FILE_ACCESS_AUDIENCE
100
+ });
101
+ if (!decoded || typeof decoded === "string") {
102
+ throw new Error("Invalid temporary file access token");
103
+ }
104
+ return decoded;
105
+ }
106
+ async function createTemporaryURLAction(ctx, next) {
107
+ var _a, _b, _c;
108
+ const collectionName = ctx.action.resourceName;
109
+ const collection = ctx.dataSource.collectionManager.getCollection(collectionName);
110
+ if (!isFileCollection(collection)) {
111
+ return ctx.throw(404);
112
+ }
113
+ if (!(0, import_utils.hasStandardFileId)(collection)) {
114
+ ctx.logger.error("file collection is missing standard id field", {
115
+ method: "file-manager.createTemporaryURL",
116
+ collection: collection.name
117
+ });
118
+ return ctx.throw(500);
119
+ }
120
+ const id = ctx.action.params.filterByTk;
121
+ let filter = { id };
122
+ if (ctx.app.options.acl !== false && ((_a = ctx.dataSource.options) == null ? void 0 : _a.useACL) !== false && ((_b = ctx.dataSource.options) == null ? void 0 : _b.acl) !== false) {
123
+ filter = await (0, import_resolve_file_access_filter.resolveFileAccessFilter)(ctx, collection, filter);
124
+ }
125
+ const file = await ctx.getCurrentRepository().findOne({
126
+ filter,
127
+ fields: ["id", "storageId", "extname"],
128
+ context: ctx
129
+ });
130
+ const storageId = (0, import_utils.getFileRecordValue)(file, "storageId");
131
+ if (!file || typeof storageId !== "string" && typeof storageId !== "number") {
132
+ return ctx.throw(404);
133
+ }
134
+ const plugin = ctx.app.pm.get("file-manager");
135
+ const appName = ctx.app.name || "main";
136
+ const dataSourceName = ctx.dataSource.name;
137
+ const fileId = (0, import_utils.getFileAccessPathSegment)(id, (0, import_utils.getFileRecordValue)(file, "extname"));
138
+ const token = signTemporaryFileAccessToken(plugin, {
139
+ app: appName,
140
+ dataSource: dataSourceName,
141
+ collection: collection.name,
142
+ id: String(id),
143
+ storageId,
144
+ sub: ((_c = ctx.state.currentUser) == null ? void 0 : _c.id) ? String(ctx.state.currentUser.id) : void 0,
145
+ role: ctx.state.currentRole
146
+ });
147
+ const basePath = (0, import_utils.getFilePublicBasePath)();
148
+ const url = `${basePath}/files/${encodeURIComponent(appName)}/${encodeURIComponent(
149
+ dataSourceName
150
+ )}/${encodeURIComponent(collection.name)}/${fileId}?temporaryAccessToken=${encodeURIComponent(token)}`;
151
+ ctx.set("Cache-Control", "no-store");
152
+ ctx.body = { url };
153
+ await next();
154
+ }
155
+ function registerTemporaryFileAccess(dataSource) {
156
+ dataSource.resourceManager.registerActionHandler(CREATE_TEMPORARY_URL_ACTION, createTemporaryURLAction);
157
+ dataSource.acl.allow("*", CREATE_TEMPORARY_URL_ACTION, "loggedIn");
158
+ }
159
+ // Annotate the CommonJS export names for ESM import in node:
160
+ 0 && (module.exports = {
161
+ CREATE_TEMPORARY_URL_ACTION,
162
+ TEMPORARY_FILE_ACCESS_AUDIENCE,
163
+ createTemporaryURLAction,
164
+ deriveTemporaryFileAccessSecret,
165
+ getTemporaryFileAccessExpiresIn,
166
+ registerTemporaryFileAccess,
167
+ signTemporaryFileAccessToken,
168
+ verifyTemporaryFileAccessToken
169
+ });
@@ -6,10 +6,37 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import type { Collection } from '@nocobase/database';
10
+ import type { AttachmentModel } from './storages';
9
11
  export declare function getFilename(req: any, file: any, cb: any): void;
10
12
  export declare const cloudFilenameGetter: (storage: any) => (req: any, file: any, cb: any) => void;
11
13
  export declare const diskFilenameGetter: (storage: any) => (req: any, file: any, cb: any) => void;
12
14
  export declare function getFileKey(record: any): any;
15
+ export declare function trimPublicPath(path?: string): string;
16
+ export declare function getFilePublicBasePath(): string;
17
+ export declare function normalizeFileAccessExtname(value: unknown): string;
18
+ export declare function getFileAccessPathSegment(id: string | number, extname: unknown): string;
19
+ export declare function hasStandardFileId(collection: Collection): boolean;
20
+ export declare function getRecordCollectionName(file: AttachmentModel): string;
21
+ export declare function getFilePlainObject(file: AttachmentModel): {
22
+ id?: number;
23
+ title: string;
24
+ filename: string;
25
+ extname?: string;
26
+ mimetype?: string;
27
+ path: string;
28
+ url?: string;
29
+ storageId?: number;
30
+ source?: {
31
+ dataSourceKey?: string;
32
+ collectionName?: string;
33
+ field?: string;
34
+ documentCache?: boolean;
35
+ trustworthy?: boolean;
36
+ };
37
+ };
38
+ export declare function getFileRecordValue(file: unknown, key: string): any;
39
+ export declare function isPermanentFileAccessURL(value: unknown, file: AttachmentModel, appName: string): boolean;
13
40
  export declare function normalizeStorageSubPath(subPath?: unknown): string;
14
41
  export declare function resolveStoragePath(storagePath?: unknown, subPath?: unknown): string;
15
42
  export declare function ensureUrlEncoded(value: any): any;
@@ -40,11 +40,20 @@ __export(utils_exports, {
40
40
  diskFilenameGetter: () => diskFilenameGetter,
41
41
  encodeURL: () => encodeURL,
42
42
  ensureUrlEncoded: () => ensureUrlEncoded,
43
+ getFileAccessPathSegment: () => getFileAccessPathSegment,
43
44
  getFileKey: () => getFileKey,
45
+ getFilePlainObject: () => getFilePlainObject,
46
+ getFilePublicBasePath: () => getFilePublicBasePath,
47
+ getFileRecordValue: () => getFileRecordValue,
44
48
  getFilename: () => getFilename,
49
+ getRecordCollectionName: () => getRecordCollectionName,
50
+ hasStandardFileId: () => hasStandardFileId,
51
+ isPermanentFileAccessURL: () => isPermanentFileAccessURL,
45
52
  normalizeDocumentRoot: () => normalizeDocumentRoot,
53
+ normalizeFileAccessExtname: () => normalizeFileAccessExtname,
46
54
  normalizeStorageSubPath: () => normalizeStorageSubPath,
47
- resolveStoragePath: () => resolveStoragePath
55
+ resolveStoragePath: () => resolveStoragePath,
56
+ trimPublicPath: () => trimPublicPath
48
57
  });
49
58
  module.exports = __toCommonJS(utils_exports);
50
59
  var import_utils = require("@nocobase/utils");
@@ -131,6 +140,69 @@ const diskFilenameGetter = (storage) => (req, file, cb) => {
131
140
  function getFileKey(record) {
132
141
  return (0, import_url_join.default)(record.path || "", record.filename).replace(/^\//, "");
133
142
  }
143
+ function trimPublicPath(path2) {
144
+ const normalized = (path2 == null ? void 0 : path2.replace(/\/+$/g, "")) || "";
145
+ return normalized === "/" ? "" : normalized;
146
+ }
147
+ function getFilePublicBasePath() {
148
+ return trimPublicPath(process.env.APP_PUBLIC_PATH);
149
+ }
150
+ function normalizeFileAccessExtname(value) {
151
+ if (typeof value !== "string" || value.length < 2 || !value.startsWith(".") || value.slice(1).includes(".") || value.includes("/") || value.includes("\\")) {
152
+ return "";
153
+ }
154
+ return value;
155
+ }
156
+ function getFileAccessPathSegment(id, extname) {
157
+ return `${encodeURIComponent(String(id))}${encodeURIComponent(normalizeFileAccessExtname(extname))}`;
158
+ }
159
+ function hasStandardFileId(collection) {
160
+ var _a, _b, _c, _d, _e, _f;
161
+ return Boolean(
162
+ ((_a = collection.getField) == null ? void 0 : _a.call(collection, "id")) || ((_b = collection.model) == null ? void 0 : _b.primaryKeyAttribute) === "id" || ((_d = (_c = collection.model) == null ? void 0 : _c.rawAttributes) == null ? void 0 : _d.id) || ((_f = (_e = collection.model) == null ? void 0 : _e.getAttributes) == null ? void 0 : _f.call(_e).id)
163
+ );
164
+ }
165
+ function getRecordCollectionName(file) {
166
+ var _a;
167
+ const modelName = (_a = file == null ? void 0 : file.constructor) == null ? void 0 : _a.name;
168
+ return modelName && modelName !== "Object" ? modelName : "attachments";
169
+ }
170
+ function getFilePlainObject(file) {
171
+ if (typeof (file == null ? void 0 : file.get) === "function") {
172
+ return { ...file.get() };
173
+ }
174
+ return { ...file };
175
+ }
176
+ function getFileRecordValue(file, key) {
177
+ if (!file || typeof file !== "object") {
178
+ return void 0;
179
+ }
180
+ const model = file;
181
+ if (typeof model.get === "function") {
182
+ return model.get(key);
183
+ }
184
+ return file[key];
185
+ }
186
+ function isPermanentFileAccessURL(value, file, appName) {
187
+ if (typeof value !== "string" || !file.id) {
188
+ return false;
189
+ }
190
+ try {
191
+ const url = new URL(value, "http://localhost");
192
+ const segments = url.pathname.split("/").filter(Boolean);
193
+ const filesIndex = segments.indexOf("files");
194
+ const filePathSegments = segments.length - filesIndex;
195
+ if (filesIndex === -1 || filePathSegments !== 5) {
196
+ return false;
197
+ }
198
+ const fileIdSegment = decodeURIComponent(segments[filesIndex + 4]);
199
+ const extname = normalizeFileAccessExtname(file.extname);
200
+ const id = extname && fileIdSegment.endsWith(extname) ? fileIdSegment.slice(0, -extname.length) : fileIdSegment;
201
+ return decodeURIComponent(segments[filesIndex + 1]) === appName && id === String(file.id);
202
+ } catch (error) {
203
+ return false;
204
+ }
205
+ }
134
206
  function pathError(message) {
135
207
  const error = new Error(message);
136
208
  error.code = "PATH_TRAVERSAL";
@@ -211,9 +283,18 @@ function normalizeDocumentRoot(documentRoot) {
211
283
  diskFilenameGetter,
212
284
  encodeURL,
213
285
  ensureUrlEncoded,
286
+ getFileAccessPathSegment,
214
287
  getFileKey,
288
+ getFilePlainObject,
289
+ getFilePublicBasePath,
290
+ getFileRecordValue,
215
291
  getFilename,
292
+ getRecordCollectionName,
293
+ hasStandardFileId,
294
+ isPermanentFileAccessURL,
216
295
  normalizeDocumentRoot,
296
+ normalizeFileAccessExtname,
217
297
  normalizeStorageSubPath,
218
- resolveStoragePath
298
+ resolveStoragePath,
299
+ trimPublicPath
219
300
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-file-manager",
3
- "version": "2.2.0-beta.13",
3
+ "version": "2.2.0-beta.14",
4
4
  "displayName": "File manager",
5
5
  "displayName.ru-RU": "Менеджер файлов",
6
6
  "displayName.zh-CN": "文件管理器",
@@ -15,6 +15,7 @@
15
15
  "devDependencies": {
16
16
  "@aws-sdk/client-s3": "3.750.0",
17
17
  "@aws-sdk/lib-storage": "3.750.0",
18
+ "@aws-sdk/s3-request-presigner": "3.750.0",
18
19
  "@formily/antd-v5": "1.x",
19
20
  "@formily/core": "2.x",
20
21
  "@formily/react": "2.x",
@@ -41,7 +42,8 @@
41
42
  "url-join": "4.0.1"
42
43
  },
43
44
  "dependencies": {
44
- "file-type": "^21.0.0"
45
+ "file-type": "^21.0.0",
46
+ "jsonwebtoken": "^9.0.2"
45
47
  },
46
48
  "peerDependencies": {
47
49
  "@nocobase/actions": "2.x",
@@ -60,5 +62,5 @@
60
62
  "Collections",
61
63
  "Collection fields"
62
64
  ],
63
- "gitHead": "8fff12b34f41f4336075cdafcc700ec694f9b78a"
65
+ "gitHead": "1ef021f3ce0a84469e40f181a19551a50b6f850c"
64
66
  }
@@ -1,10 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- "use strict";(self.webpackChunk_nocobase_plugin_file_manager_client_v2=self.webpackChunk_nocobase_plugin_file_manager_client_v2||[]).push([["125"],{212:function(e,t,r){r.r(t),r.d(t,{DisplayPreviewFieldModel:function(){return P}});var n=r(477),o=r(485),l=r(694),a=r(59),i=r(773),c=r(155),u=r.n(c),s=r(953),f=r(23);function p(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function b(e,t,r,n,o,l,a){try{var i=e[l](a),c=i.value}catch(e){r(e);return}i.done?t(c):Promise.resolve(c).then(n,o)}function y(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function d(e){return(d=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function h(e,t){return null!=t&&"u">typeof Symbol&&t[Symbol.hasInstance]?!!t[Symbol.hasInstance](e):e instanceof t}function m(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},n=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(r).filter(function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable}))),n.forEach(function(t){y(e,t,r[t])})}return e}function v(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t.push.apply(t,r)}return t})(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}),e}function w(e,t){return(w=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function g(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r,n,o=null==e?null:"u">typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=o){var l=[],a=!0,i=!1;try{for(o=o.call(e);!(a=(r=o.next()).done)&&(l.push(r.value),!t||l.length!==t);a=!0);}catch(e){i=!0,n=e}finally{try{a||null==o.return||o.return()}finally{if(i)throw n}}return l}}(e,t)||function(e,t){if(e){if("string"==typeof e)return p(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if("Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r)return Array.from(r);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return p(e,t)}}(e,t)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function O(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(O=function(){return!!e})()}function j(){var e,t,r=(e=["\n .ant-image-img {\n border: 1px solid #d9d9d9;\n padding: 2px;\n }\n "],t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}})));return j=function(){return r},r}var k=function(e){var t=e.file,r=e.size,o=e.showFileName,l=e.onClick,i=(0,f._H)(t),c=(0,f.q)(i);if(!c)return null;var s=(0,f.WP)(i,c),p=(0,f._Y)(i,c),b=(0,f.qk)(i)||p,y=u().createElement("div",{className:(0,n.css)(j())},u().createElement(a.Image,{src:b,fallback:p,width:r,height:r,preview:!1,style:{borderRadius:4,objectFit:"cover",boxShadow:"0 0 0 2px #fff"}}));return u().createElement("div",{onClick:l,style:{textAlign:"center",width:r,wordBreak:"break-all",cursor:l?"pointer":"default"}},y,o&&u().createElement(a.Tooltip,{title:s},u().createElement("div",{style:{fontSize:12,marginTop:4,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",width:"100%"}},s)))},S=function(e){var t=e.value,r=void 0===t?[]:t,n=e.size,o=void 0===n?28:n,l=e.showFileName,c=(0,s.useTranslation)().t,p=g(u().useState(0),2),y=p[0],d=p[1],h=g(u().useState(!1),2),m=h[0],v=h[1],w=u().useMemo(function(){return(0,i.castArray)(r).filter(Boolean).map(f._H).filter(function(e){return(0,f.q)(e)})},[r]);u().useEffect(function(){y>=w.length&&w.length&&d(0)},[y,w.length]),u().useEffect(function(){!w.length&&m&&v(!1)},[w.length,m]);var O=u().useCallback(function(e){var t;return(t=function(){var t,r,n,o,l,i,u;return function(e,t){var r,n,o,l={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},a=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),i=Object.defineProperty;return i(a,"next",{value:c(0)}),i(a,"throw",{value:c(1)}),i(a,"return",{value:c(2)}),"function"==typeof Symbol&&i(a,Symbol.iterator,{value:function(){return this}}),a;function c(i){return function(c){var u=[i,c];if(r)throw TypeError("Generator is already executing.");for(;a&&(a=0,u[0]&&(l=0)),l;)try{if(r=1,n&&(o=2&u[0]?n.return:u[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,u[1])).done)return o;switch(n=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return l.label++,{value:u[1],done:!1};case 5:l.label++,n=u[1],u=[0];continue;case 7:u=l.ops.pop(),l.trys.pop();continue;default:if(!(o=(o=l.trys).length>0&&o[o.length-1])&&(6===u[0]||2===u[0])){l=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){l.label=u[1];break}if(6===u[0]&&l.label<o[1]){l.label=o[1],o=u;break}if(o&&l.label<o[2]){l.label=o[2],l.ops.push(u);break}o[2]&&l.ops.pop(),l.trys.pop();continue}u=t.call(e,l)}catch(e){u=[6,e],n=0}finally{r=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}}}(this,function(s){switch(s.label){case 0:if(!(t=e||w[y])||!(r=t.url||t.preview))return[2];n=(0,f.ub)(t,r),s.label=1;case 1:return s.trys.push([1,4,5,6]),[4,fetch(r)];case 2:if(!(i=s.sent()).ok)throw Error("Download failed with status ".concat(i.status));return[4,i.blob()];case 3:return u=s.sent(),o=URL.createObjectURL(u),(l=document.createElement("a")).href=o,l.download=n,document.body.appendChild(l),l.click(),[3,6];case 4:return console.error("File download failed:",s.sent()),a.message.error(c("file-manager:File download failed")),[3,6];case 5:return l&&l.remove(),o&&setTimeout(function(){URL.revokeObjectURL(o)},1e3),[7];case 6:return[2]}})},function(){var e=this,r=arguments;return new Promise(function(n,o){var l=t.apply(e,r);function a(e){b(l,n,o,a,i,"next",e)}function i(e){b(l,n,o,a,i,"throw",e)}a(void 0)})})()},[y,w,c]),j=u().useCallback(function(e){d(e),v(!0)},[]),S=u().useCallback(function(e){e<0||e>=w.length||d(e)},[w.length]);return u().createElement(u().Fragment,null,u().createElement(a.Space,{wrap:!0},w.map(function(e,t){return u().createElement(k,{file:e,size:o,key:t,showFileName:l,onClick:function(){return j(t)}})})),w[y]?u().createElement(f.Mo,{open:m,file:w[y],index:y,list:w,onOpenChange:v,onClose:function(){return v(!1)},onSwitchIndex:S,onDownload:O}):null)},P=function(e){var t;if("function"!=typeof e&&null!==e)throw TypeError("Super expression must either be null or a function");function r(){var e,t,n;if(!(this instanceof r))throw TypeError("Cannot call a class as a function");return t=r,n=arguments,t=d(t),y(e=function(e,t){var r;if(t&&("object"==((r=t)&&"u">typeof Symbol&&r.constructor===Symbol?"symbol":typeof r)||"function"==typeof t))return t;if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(this,O()?Reflect.construct(t,n||[],d(this).constructor):t.apply(this,n)),"disableTitleField",!0),e}return r.prototype=Object.create(e&&e.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),e&&w(r,e),t=[{key:"render",value:function(){var e=this,t=this.props,r=t.value,n=t.titleField,o=t.template,l=t.target;return n&&"file"!==o&&"attachments"!==l?(0,i.castArray)(r).flatMap(function(t,r){var o=null==t?void 0:t[n],l=o?u().createElement(S,v(m({key:r},e.props),{value:(0,i.castArray)(o).filter(Boolean)})):u().createElement("span",{key:r},"N/A");return 0===r?[l]:[u().createElement("span",{key:"sep-".concat(r)},", "),l]}):u().createElement(S,v(m({},this.props),{value:(0,i.castArray)(r).filter(Boolean)}))}}],function(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}(r.prototype,t),r}(o.FieldModel);P.registerFlow({key:"previewReadPrettySetting",sort:500,title:(0,l.tExpr)("Preview Settings"),steps:{size:{title:(0,l.tExpr)("Size"),uiMode:function(e){var t=e.t;return{type:"select",key:"size",props:{options:[{value:300,label:t("Large")},{value:100,label:t("Middle")},{value:28,label:t("Small")}]}}},hideInSettings:function(e){return h(e.model.parent,o.TableColumnModel)},defaultParams:function(e){return{size:h(e.model.parent,o.DetailsItemModel)?100:28}},handler:function(e,t){e.model.setProps("size",t.size)}},showFileName:{title:(0,l.tExpr)("Show file name"),uiMode:{type:"switch",key:"showFileName"},hideInSettings:function(e){return h(e.model.parent,o.TableColumnModel)},defaultParams:{showFileName:!1},handler:function(e,t){e.model.setProps("showFileName",t.showFileName)}}}}),P.define({label:(0,l.tExpr)("Preview")}),l.DisplayItemModel.bindModelToInterface("DisplayPreviewFieldModel",["url","attachment","attachmentURL","m2m","m2o","o2o","o2m","oho","obo","mbm"],{isDefault:!0,when:function(e,t){return!t.targetCollection||"file"===t.targetCollection.template}})}}]);
@@ -1,10 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- "use strict";(self.webpackChunk_nocobase_plugin_file_manager_client_v2=self.webpackChunk_nocobase_plugin_file_manager_client_v2||[]).push([["450"],{177:function(e,t,n){n.r(t),n.d(t,{UploadActionModel:function(){return F},useBeforeUpload:function(){return U},useStorageCfg:function(){return M},useStorageUploadProps:function(){return _},useStorage:function(){return B},validate:function(){return A}});var r=n(375),o=n(485),i=n(694),l=n(625),a=n(59);let u="bits",c="bytes",s="jedec",p={iec:{bits:["bit","Kibit","Mibit","Gibit","Tibit","Pibit","Eibit","Zibit","Yibit"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["bit","Kbit","Mbit","Gbit","Tbit","Pbit","Ebit","Zbit","Ybit"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},f={iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]};var d=n(484),b=n.n(d),y=n(155),v=n.n(y),m=n(953);function g(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function h(e,t,n,r,o,i,l){try{var a=e[i](l),u=a.value}catch(e){n(e);return}a.done?t(u):Promise.resolve(u).then(r,o)}function w(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function O(e,t,n){return(O="u">typeof Reflect&&Reflect.get?Reflect.get:function(e,t,n){var r=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=S(e)););return e}(e,t);if(r){var o=Object.getOwnPropertyDescriptor(r,t);return o.get?o.get.call(n||e):o.value}})(e,t,n||e)}function S(e){return(S=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function k(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),r.forEach(function(t){w(e,t,n[t])})}return e}function x(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t.push.apply(t,n)}return t})(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}),e}function E(e,t){return(E=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function j(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n,r,o=null==e?null:"u">typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=o){var i=[],l=!0,a=!1;try{for(o=o.call(e);!(l=(n=o.next()).done)&&(i.push(n.value),!t||i.length!==t);l=!0);}catch(e){a=!0,r=e}finally{try{l||null==o.return||o.return()}finally{if(a)throw r}}return i}}(e,t)||function(e,t){if(e){if("string"==typeof e)return g(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return g(e,t)}}(e,t)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function P(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(P=function(){return!!e})()}function T(e,t){if(!t||"main"===t)return e;var n=e.includes("?")?"&":"?";return"".concat(e).concat(n,"uploadDataSourceKey=").concat(encodeURIComponent(t))}var C=function(e){var t,n,r,o=(0,i.useFlowContext)(),l=(0,y.useMemo)(function(){var t="".concat(e.context.collection.name,":create"),n=null==(r=e.context.blockModel.association)?void 0:r.resourceName;if((null==(l=o.view)||null==(i=l.inputArgs)?void 0:i.sourceId)&&n){var r,i,l,a,u=j(n.split("."),2),c=u[0],s=u[1];t="".concat(c,"/").concat(null==(a=o.view)?void 0:a.inputArgs.sourceId,"/").concat(s,":create")}return t},[null==(t=e.context.blockModel.association)?void 0:t.resourceName,e.context.collection.name,null==(r=o.view)||null==(n=r.inputArgs)?void 0:n.sourceId]),a={},u=0,c={action:l,onChange:function(t){var n=t.fileList;n.forEach(function(t){if("uploading"!==t.status||a[t.uid]||(u++,a[t.uid]=!0),"uploading"!==t.status&&a[t.uid]&&(delete a[t.uid],0==--u)){var n,r;null==(n=(r=e.context.blockModel.resource).refresh)||n.call(r)}}),n.every(function(e){return"done"===e.status})&&o.view.close()}},s=_(c,e);return k({},c,s)};function B(e,t){var n=null!=e?e:"",r=T("storages:getBasicInfo/".concat(n),t),o=(0,i.useFlowContext)(),a=(0,l.useRequest)(function(){var e;return(e=function(){var e;return function(e,t){var n,r,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},l=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),a=Object.defineProperty;return a(l,"next",{value:u(0)}),a(l,"throw",{value:u(1)}),a(l,"return",{value:u(2)}),"function"==typeof Symbol&&a(l,Symbol.iterator,{value:function(){return this}}),l;function u(a){return function(u){var c=[a,u];if(n)throw TypeError("Generator is already executing.");for(;l&&(l=0,c[0]&&(i=0)),i;)try{if(n=1,r&&(o=2&c[0]?r.return:c[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,c[1])).done)return o;switch(r=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return i.label++,{value:c[1],done:!1};case 5:i.label++,r=c[1],c=[0];continue;case 7:c=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===c[0]||2===c[0])){i=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){i.label=c[1];break}if(6===c[0]&&i.label<o[1]){i.label=o[1],o=c;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(c);break}o[2]&&i.ops.pop(),i.trys.pop();continue}c=t.call(e,i)}catch(e){c=[6,e],r=0}finally{n=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}}}(this,function(t){switch(t.label){case 0:return[4,o.api.request({url:r,skipNotify:!0})];case 1:return[2,null==(e=t.sent())?void 0:e.data]}})},function(){var t=this,n=arguments;return new Promise(function(r,o){var i=e.apply(t,n);function l(e){h(i,r,o,l,a,"next",e)}function a(e){h(i,r,o,l,a,"throw",e)}l(void 0)})})()},{manual:!0,refreshDeps:[n,t],cacheKey:"".concat(t||"main",":").concat(r)}),u=a.loading,c=a.data,s=a.run;return(0,y.useEffect)(function(){s()},[s]),!u&&(null==c?void 0:c.data)||null}function M(e){var t,n,r,o,l=(0,i.useFlowContext)(),a=l.collectionField,u=null==(r=l.collectionField)?void 0:r.targetCollection,c=l.app.pm.get("@nocobase/plugin-file-manager"),s=e.context.blockModel.collection,p=(null==(t=e.context.collection)?void 0:t.dataSourceKey)||(null==(n=e.context.blockModel.collection)?void 0:n.dataSourceKey)||(null==(o=l.collection)?void 0:o.dataSourceKey),f=B((null==a?void 0:a.storage)||s.storage||u.storage,p),d=c.getStorageType(null==f?void 0:f.type);return{storage:f,storageType:d,dataSourceKey:p}}function _(e,t){var n=M(t),r=n.storage,o=n.storageType,i=n.dataSourceKey,l=null==o?void 0:o.useUploadProps,a=(null==l?void 0:l(k({storage:r,rules:r.rules},e)))||{},u=k({},a.headers);return x(k({action:T(e.action,i),rules:null==r?void 0:r.rules},a),{headers:u})}var I={size:function(e,t){var n=null!=t?t:0x1400000;return 0===n||e.size<=n?null:"File size exceeds the limit"},mimetype:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"*",n=t.toString().trim();return n&&"*"!==n?n.split(",").filter(Boolean).some(b()(e.type))?null:"File type is not allowed":null}};function A(e,t){if(!t)return null;var n=Object.keys(t);if(!n.length)return null;var r=!0,o=!1,i=void 0;try{for(var l,a=n[Symbol.iterator]();!(r=(l=a.next()).done);r=!0){var u=l.value,c=I[u](e,t[u]);if(c)return c}}catch(e){o=!0,i=e}finally{try{r||null==a.return||a.return()}finally{if(o)throw i}}return null}function U(e){var t=(0,m.useTranslation)().t;return(0,y.useCallback)(function(n,r){var o=A(n,e);return o?(n.status="error",n.response=t(o)):"error"===n.status&&(delete n.status,delete n.response),!o&&Promise.resolve(n)},[e,t])}function z(e){var t,n,o,l,d,b,g=e.model,h=(0,i.useFlowContext)(),w=C(g),O=w.rules,S=null!=O?O:{},E=S.size;S.mimetype;var P=(t=null!=E?E:0x1400000,o=(n=(0,m.useTranslation)()).t,l=function(e,{bits:t=!1,pad:n=!1,base:r=-1,round:o=2,locale:i="",localeOptions:l={},separator:a="",spacer:d=" ",symbols:b={},standard:y="",output:v="string",fullform:m=!1,fullforms:g=[],exponent:h=-1,roundingMethod:w="round",precision:O=0}={}){let S=h,k=Number(e),x=[],E=0,j="";"si"===y?(r=10,y=s):"iec"===y||y===s?r=2:2===r?y="iec":(r=10,y=s);let P=10===r?1e3:1024,T=k<0,C=Math[w];if("bigint"!=typeof e&&isNaN(e))throw TypeError("Invalid number");if("function"!=typeof C)throw TypeError("Invalid rounding method");if(T&&(k=-k),(-1===S||isNaN(S))&&(S=Math.floor(Math.log(k)/Math.log(P)))<0&&(S=0),S>8&&(O>0&&(O+=8-S),S=8),"exponent"===v)return S;if(0===k)x[0]=0,j=x[1]=p[y][t?u:c][S];else{E=k/(2===r?Math.pow(2,10*S):Math.pow(1e3,S)),t&&(E*=8)>=P&&S<8&&(E/=P,S++);let e=Math.pow(10,S>0?o:0);x[0]=C(E*e)/e,x[0]===P&&S<8&&-1===h&&(x[0]=1,S++),j=x[1]=10===r&&1===S?t?"kbit":"kB":p[y][t?u:c][S]}if(T&&(x[0]=-x[0]),O>0&&(x[0]=x[0].toPrecision(O)),x[1]=b[x[1]]||x[1],!0===i?x[0]=x[0].toLocaleString():i.length>0?x[0]=x[0].toLocaleString(i,l):a.length>0&&(x[0]=x[0].toString().replace(".",a)),n&&o>0){let e=x[0].toString(),t=a||(e.match(/(\D)/g)||[]).pop()||".",n=e.toString().split(t),r=n[1]||"",i=r.length;x[0]=`${n[0]}${t}${r.padEnd(i+(o-i),"0")}`}return!0===m&&(x[1]=g[S]?g[S]:f[y][S]+(t?"bit":"byte")+(1===x[0]?"":"s")),"array"===v?x:"object"===v?{value:x[0],symbol:x[1],exponent:S,unit:j}:x.join(d)}(t,{base:2,standard:"jedec",locale:n.i18n.language}),0!==t?o("File size should not exceed {{size}}.",{size:l}):""),T=j((0,y.useState)(!1),2),B=T[0],M=T[1],_=(0,y.useCallback)(function(e){e.fileList.some(function(e){return"uploading"===e.status})?M(!0):M(!1)},[]),I=h.view.Header,A=U(O);return v().createElement("div",null,v().createElement(I,{title:h.t("Upload file")}),v().createElement("div",{style:{height:"50vh"},onClick:function(e){return e.stopPropagation()}},v().createElement(a.Upload.Dragger,k({multiple:!0,listType:"picture"},(d=x(k({},w),{handleChange:_,beforeUpload:A}),b=(0,i.useFlowContext)(),k({customRequest:function(e){var t=e.action,n=e.data,r=e.file,o=e.filename,i=e.headers,l=e.onError,a=e.onProgress,u=e.onSuccess,c=e.withCredentials,s=new FormData;return n&&Object.keys(n).forEach(function(e){s.append(e,n[e])}),s.append(o,r),b.api.axios.post(t,s,{withCredentials:c,headers:i,onUploadProgress:function(e){var t=e.total;a({percent:Math.round(e.loaded/t*100).toFixed(2)},r)}}).then(function(e){u(e.data,r)}).catch(l).finally(function(){}),{abort:function(){console.log("upload progress is aborted.")}}}},d))),v().createElement("p",{className:"ant-upload-drag-icon"},B?v().createElement(r.LoadingOutlined,{style:{fontSize:36},spin:!0}):v().createElement(r.InboxOutlined,null)),v().createElement("p",{className:"ant-upload-text"},h.t("Click or drag file to this area to upload")),v().createElement("ul",{style:{listStyleType:"none"}},v().createElement("li",{className:"ant-upload-hint"},h.t("Support for a single or bulk upload.")),v().createElement("li",{className:"ant-upload-hint"},P)))))}var F=function(e){var t;if("function"!=typeof e&&null!==e)throw TypeError("Super expression must either be null or a function");function n(){var e,t,r;if(!(this instanceof n))throw TypeError("Cannot call a class as a function");return t=n,r=arguments,t=S(t),w(e=function(e,t){var n;if(t&&("object"==((n=t)&&"u">typeof Symbol&&n.constructor===Symbol?"symbol":typeof n)||"function"==typeof t))return t;if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(this,P()?Reflect.construct(t,r||[],S(this).constructor):t.apply(this,r)),"defaultProps",{type:"primary",title:(0,i.escapeT)("Upload"),icon:"UploadOutlined"}),e}return n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,writable:!0,configurable:!0}}),e&&E(n,e),t=[{key:"getAclActionName",value:function(){return"create"}},{key:"onInit",value:function(e){var t=this;O(S(n.prototype),"onInit",this).call(this,e),this.onUploadClick=function(e){t.dispatchEvent("openView",{event:e})}}},{key:"onUploadClick",set:function(e){this.setProps({onUploadClick:e})}},{key:"render",value:function(){var e=this.props,t=e.icon?v().createElement(o.Icon,{type:e.icon}):void 0;return v().createElement(a.Button,x(k({},e),{onClick:this.props.onUploadClick,icon:t}),e.children||e.title)}}],function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}(n.prototype,t),n}(o.ActionModel);w(F,"scene",o.ActionSceneEnum.collection),F.define({label:(0,i.escapeT)("Upload"),hide:function(e){var t;return(null==(t=e.collection)?void 0:t.template)!=="file"}}),F.registerFlow({key:"selectExitRecordSettings",title:(0,i.escapeT)("Selector setting"),on:{eventName:"openView"},steps:{openView:{title:(0,i.escapeT)("Edit popup"),uiSchema:function(e){return{mode:{type:"string",title:(0,i.escapeT)("Open mode"),enum:[{label:(0,i.escapeT)("Drawer"),value:"drawer"},{label:(0,i.escapeT)("Dialog"),value:"dialog"}],"x-decorator":"FormItem","x-component":"Radio.Group"},size:{type:"string",title:(0,i.escapeT)("Popup size"),enum:[{label:(0,i.escapeT)("Small"),value:"small"},{label:(0,i.escapeT)("Medium"),value:"medium"},{label:(0,i.escapeT)("Large"),value:"large"}],"x-decorator":"FormItem","x-component":"Radio.Group"}}},defaultParams:{mode:"drawer",size:"medium"},handler:function(e,t){var n,r=e.inputArgs.mode||t.mode||"drawer",o=e.inputArgs.size||t.size||"medium";e.viewer.open({type:r,width:{drawer:{small:"30%",medium:"50%",large:"70%"},dialog:{small:"40%",medium:"50%",large:"80%"},embed:{}}[r][o],inheritContext:!1,target:e.layoutContentElement,inputArgs:{sourceId:null==(n=e.resource)?void 0:n.getSourceId()},content:function(){return v().createElement(z,{model:e.model})},styles:{content:k({padding:0,backgroundColor:e.model.flowEngine.context.themeToken.colorBgLayout},"embed"===r?{position:"absolute",top:0,left:0,right:0,bottom:0}:{})}})}}}})}}]);