prostgles-server 2.0.189 → 2.0.192
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/DboBuilder/insertDataParse.d.ts.map +1 -1
- package/dist/DboBuilder/insertDataParse.js +12 -3
- package/dist/DboBuilder/insertDataParse.js.map +1 -1
- package/dist/DboBuilder.d.ts +5 -4
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +54 -153
- package/dist/DboBuilder.js.map +1 -1
- package/dist/FileManager.d.ts +20 -72
- package/dist/FileManager.d.ts.map +1 -1
- package/dist/FileManager.js +233 -164
- package/dist/FileManager.js.map +1 -1
- package/dist/PostgresNotifListenManager.d.ts.map +1 -1
- package/dist/PostgresNotifListenManager.js +3 -1
- package/dist/PostgresNotifListenManager.js.map +1 -1
- package/dist/Prostgles.d.ts +13 -2
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +8 -4
- package/dist/Prostgles.js.map +1 -1
- package/dist/TableConfig.d.ts +1 -2
- package/dist/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig.js.map +1 -1
- package/lib/DboBuilder/insertDataParse.d.ts.map +1 -1
- package/lib/DboBuilder/insertDataParse.js +12 -3
- package/lib/DboBuilder/insertDataParse.ts +12 -3
- package/lib/DboBuilder.d.ts +5 -4
- package/lib/DboBuilder.d.ts.map +1 -1
- package/lib/DboBuilder.js +54 -153
- package/lib/DboBuilder.ts +67 -181
- package/lib/FileManager.d.ts +19 -71
- package/lib/FileManager.d.ts.map +1 -1
- package/lib/FileManager.js +233 -164
- package/lib/FileManager.ts +274 -191
- package/lib/PostgresNotifListenManager.d.ts.map +1 -1
- package/lib/PostgresNotifListenManager.js +3 -1
- package/lib/PostgresNotifListenManager.ts +4 -1
- package/lib/Prostgles.d.ts +13 -2
- package/lib/Prostgles.d.ts.map +1 -1
- package/lib/Prostgles.js +8 -4
- package/lib/Prostgles.ts +9 -5
- package/lib/TableConfig.d.ts +1 -2
- package/lib/TableConfig.d.ts.map +1 -1
- package/lib/TableConfig.ts +2 -4
- package/lib/fileType/core.js +1527 -0
- package/lib/fileType/supported.js +278 -0
- package/package.json +3 -3
- package/tests/client/PID.txt +1 -1
- package/tests/server/DBoGenerated.d.ts +1 -1
- package/tests/server/package-lock.json +5 -5
package/dist/FileManager.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { S3 } from 'aws-sdk';
|
|
3
3
|
import { DB, DBHandlerServer, Prostgles } from './Prostgles';
|
|
4
|
+
import { ALLOWED_CONTENT_TYPE, ALLOWED_EXTENSION, ValidatedColumnInfo } from 'prostgles-types';
|
|
4
5
|
export declare const asSQLIdentifier: (name: string, db: DB) => Promise<string>;
|
|
5
6
|
export declare type ImageOptions = {
|
|
6
7
|
keepMetadata?: boolean;
|
|
@@ -60,10 +61,14 @@ export default class FileManager {
|
|
|
60
61
|
tableName?: string;
|
|
61
62
|
private fileRoute?;
|
|
62
63
|
constructor(config: FileManager["config"], imageOptions?: ImageOptions);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
ext: string | ALLOWED_EXTENSION;
|
|
64
|
+
parseFile(args: {
|
|
65
|
+
file: Buffer | string;
|
|
66
66
|
fileName: string;
|
|
67
|
+
colName?: string;
|
|
68
|
+
tableName?: string;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
mime: string | ALLOWED_CONTENT_TYPE;
|
|
71
|
+
ext: string | ALLOWED_EXTENSION;
|
|
67
72
|
}>;
|
|
68
73
|
private upload;
|
|
69
74
|
uploadAsMedia: (params: {
|
|
@@ -74,77 +79,20 @@ export default class FileManager {
|
|
|
74
79
|
}) => Promise<UploadedItem>;
|
|
75
80
|
private getFileURL;
|
|
76
81
|
private parseSQLIdentifier;
|
|
82
|
+
getColInfo: (args: {
|
|
83
|
+
tableName: string;
|
|
84
|
+
colName: string;
|
|
85
|
+
}) => ValidatedColumnInfo["file"] | undefined;
|
|
77
86
|
init: (prg: Prostgles) => Promise<void>;
|
|
78
87
|
}
|
|
79
|
-
declare const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
readonly "text/x-component": readonly ["htc"];
|
|
88
|
-
readonly "image/gif": readonly ["gif"];
|
|
89
|
-
readonly "image/jpeg": readonly ["jpeg", "jpg"];
|
|
90
|
-
readonly "image/png": readonly ["png"];
|
|
91
|
-
readonly "image/tiff": readonly ["tif", "tiff"];
|
|
92
|
-
readonly "image/vnd.wap.wbmp": readonly ["wbmp"];
|
|
93
|
-
readonly "image/x-icon": readonly ["ico"];
|
|
94
|
-
readonly "image/x-jng": readonly ["jng"];
|
|
95
|
-
readonly "image/x-ms-bmp": readonly ["bmp"];
|
|
96
|
-
readonly "image/svg+xml": readonly ["svg"];
|
|
97
|
-
readonly "image/webp": readonly ["webp"];
|
|
98
|
-
readonly "application/x-javascript": readonly ["js"];
|
|
99
|
-
readonly "application/atom+xml": readonly ["atom"];
|
|
100
|
-
readonly "application/rss+xml": readonly ["rss"];
|
|
101
|
-
readonly "application/java-archive": readonly ["jar", "war", "ear"];
|
|
102
|
-
readonly "application/mac-binhex40": readonly ["hqx"];
|
|
103
|
-
readonly "application/msword": readonly ["doc", "docx"];
|
|
104
|
-
readonly "application/pdf": readonly ["pdf"];
|
|
105
|
-
readonly "application/postscript": readonly ["ps", "eps", "ai"];
|
|
106
|
-
readonly "application/rtf": readonly ["rtf"];
|
|
107
|
-
readonly "application/vnd.ms-excel": readonly ["xls", "xlsx"];
|
|
108
|
-
readonly "application/vnd.ms-powerpoint": readonly ["ppt", "pptx"];
|
|
109
|
-
readonly "application/vnd.wap.wmlc": readonly ["wmlc"];
|
|
110
|
-
readonly "application/vnd.google-earth.kml+xml": readonly ["kml"];
|
|
111
|
-
readonly "application/vnd.google-earth.kmz": readonly ["kmz"];
|
|
112
|
-
readonly "application/x-7z-compressed": readonly ["7z"];
|
|
113
|
-
readonly "application/x-cocoa": readonly ["cco"];
|
|
114
|
-
readonly "application/x-java-archive-diff": readonly ["jardiff"];
|
|
115
|
-
readonly "application/x-java-jnlp-file": readonly ["jnlp"];
|
|
116
|
-
readonly "application/x-makeself": readonly ["run"];
|
|
117
|
-
readonly "application/x-perl": readonly ["pl", "pm"];
|
|
118
|
-
readonly "application/x-pilot": readonly ["prc", "pdb"];
|
|
119
|
-
readonly "application/x-rar-compressed": readonly ["rar"];
|
|
120
|
-
readonly "application/x-redhat-package-manager": readonly ["rpm"];
|
|
121
|
-
readonly "application/x-sea": readonly ["sea"];
|
|
122
|
-
readonly "application/x-shockwave-flash": readonly ["swf"];
|
|
123
|
-
readonly "application/x-stuffit": readonly ["sit"];
|
|
124
|
-
readonly "application/x-tcl": readonly ["tcl", "tk"];
|
|
125
|
-
readonly "application/x-x509-ca-cert": readonly ["der", "pem", "crt"];
|
|
126
|
-
readonly "application/x-xpinstall": readonly ["xpi"];
|
|
127
|
-
readonly "application/xhtml+xml": readonly ["xhtml"];
|
|
128
|
-
readonly "application/zip": readonly ["zip"];
|
|
129
|
-
readonly "application/octet-stream": readonly ["bin", "exe", "dll", "deb", "dmg", "eot", "iso", "img", "msi", "msp", "msm"];
|
|
130
|
-
readonly "audio/midi": readonly ["mid", "midi", "kar"];
|
|
131
|
-
readonly "audio/mpeg": readonly ["mp3"];
|
|
132
|
-
readonly "audio/ogg": readonly ["ogg"];
|
|
133
|
-
readonly "audio/x-realaudio": readonly ["ra"];
|
|
134
|
-
readonly "video/3gpp": readonly ["3gpp", "3gp"];
|
|
135
|
-
readonly "video/mpeg": readonly ["mpeg", "mpg"];
|
|
136
|
-
readonly "video/quicktime": readonly ["mov"];
|
|
137
|
-
readonly "video/x-flv": readonly ["flv"];
|
|
138
|
-
readonly "video/x-mng": readonly ["mng"];
|
|
139
|
-
readonly "video/x-ms-asf": readonly ["asx", "asf"];
|
|
140
|
-
readonly "video/x-ms-wmv": readonly ["wmv"];
|
|
141
|
-
readonly "video/x-msvideo": readonly ["avi"];
|
|
142
|
-
readonly "video/mp4": readonly ["m4v", "mp4"];
|
|
143
|
-
readonly "video/webm": readonly ["webm"];
|
|
144
|
-
};
|
|
145
|
-
export declare type ALLOWED_CONTENT_TYPE = keyof typeof CONTENT_TYPE_TO_EXT;
|
|
146
|
-
export declare type ALLOWED_EXTENSION = (typeof CONTENT_TYPE_TO_EXT)[ALLOWED_CONTENT_TYPE][number];
|
|
147
|
-
export {};
|
|
88
|
+
export declare const getFileTypeFromFilename: (fileName: string) => {
|
|
89
|
+
mime: ALLOWED_CONTENT_TYPE;
|
|
90
|
+
ext: ALLOWED_EXTENSION;
|
|
91
|
+
} | undefined;
|
|
92
|
+
export declare const getFileType: (file: Buffer | string, fileName: string) => Promise<{
|
|
93
|
+
mime: ALLOWED_CONTENT_TYPE;
|
|
94
|
+
ext: ALLOWED_EXTENSION;
|
|
95
|
+
}>;
|
|
148
96
|
/**
|
|
149
97
|
*
|
|
150
98
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileManager.d.ts","sourceRoot":"","sources":["../lib/FileManager.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"FileManager.d.ts","sourceRoot":"","sources":["../lib/FileManager.ts"],"names":[],"mappings":"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"}
|
package/dist/FileManager.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.asSQLIdentifier = void 0;
|
|
3
|
+
exports.getFileType = exports.getFileTypeFromFilename = exports.asSQLIdentifier = void 0;
|
|
4
4
|
const aws_sdk_1 = require("aws-sdk");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
-
const FileType = require("file-type");
|
|
7
6
|
const sharp = require("sharp");
|
|
8
7
|
const prostgles_types_1 = require("prostgles-types");
|
|
8
|
+
const DboBuilder_1 = require("./DboBuilder");
|
|
9
9
|
const HOUR = 3600 * 1000;
|
|
10
10
|
const asSQLIdentifier = async (name, db) => {
|
|
11
11
|
return (await db.one("select format('%I', $1) as name", [name]))?.name;
|
|
@@ -58,6 +58,18 @@ class FileManager {
|
|
|
58
58
|
return res;
|
|
59
59
|
};
|
|
60
60
|
this.parseSQLIdentifier = async (name) => (0, exports.asSQLIdentifier)(name, this.prostgles.db); // this.prostgles.dbo.sql<"value">("select format('%I', $1)", [name], { returnType: "value" } )
|
|
61
|
+
this.getColInfo = (args) => {
|
|
62
|
+
const { colName, tableName } = args;
|
|
63
|
+
const tableConfig = this.prostgles?.opts.fileTable?.referencedTables?.[tableName];
|
|
64
|
+
const isReferencingFileTable = this.dbo[tableName]?.columns?.some(c => c.name === colName && c.references && c.references?.ftable === this.tableName);
|
|
65
|
+
if (isReferencingFileTable) {
|
|
66
|
+
if (tableConfig && typeof tableConfig !== "string") {
|
|
67
|
+
return tableConfig.referenceColumns[colName];
|
|
68
|
+
}
|
|
69
|
+
return { acceptedContent: "*" };
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
};
|
|
61
73
|
this.init = async (prg) => {
|
|
62
74
|
this.prostgles = prg;
|
|
63
75
|
// const { dbo, db, opts } = prg;
|
|
@@ -68,6 +80,7 @@ class FileManager {
|
|
|
68
80
|
this.tableName = tableName;
|
|
69
81
|
const maxBfSizeMB = (prg.opts.io?.engine?.opts?.maxHttpBufferSize || 1e6) / 1e6;
|
|
70
82
|
console.log(`Prostgles: Initiated file manager. Max allowed file size: ${maxBfSizeMB}MB (maxHttpBufferSize = 1e6). To increase this set maxHttpBufferSize in socket.io server init options`);
|
|
83
|
+
// throw `this.db.tx(d => do everything in a transaction pls!!!!`;
|
|
71
84
|
// throw "Why are constraints dissapearing?"
|
|
72
85
|
/**
|
|
73
86
|
* 1. Create media table
|
|
@@ -98,56 +111,96 @@ class FileManager {
|
|
|
98
111
|
/**
|
|
99
112
|
* 2. Create media lookup tables
|
|
100
113
|
*/
|
|
101
|
-
await Promise.all(
|
|
114
|
+
await Promise.all((0, prostgles_types_1.getKeys)(referencedTables).map(async (refTable) => {
|
|
102
115
|
if (!this.dbo[refTable])
|
|
103
|
-
throw `Referenced table (${refTable}) from fileTable.referencedTables
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
` This may have been caused by a DROP TABLE ... CASCADE.`);
|
|
130
|
-
let q = `
|
|
131
|
-
ALTER TABLE ${(0, prostgles_types_1.asName)(lookupTableName)}
|
|
132
|
-
ADD CONSTRAINT ${(lookupTableName + "_" + badCol.name + "_r")} FOREIGN KEY (${badCol.name})
|
|
133
|
-
`;
|
|
134
|
-
console.log("Trying to add the missing constraint back");
|
|
135
|
-
if (badCol.name === "foreign_id") {
|
|
136
|
-
q += `REFERENCES ${(0, prostgles_types_1.asName)(refTable)}(${(0, prostgles_types_1.asName)(pkField.name)}) `;
|
|
137
|
-
}
|
|
138
|
-
else if (badCol.name === "media_id") {
|
|
139
|
-
q += `REFERENCES ${(0, prostgles_types_1.asName)(tableName)}(id) `;
|
|
116
|
+
throw `Referenced table (${refTable}) from fileTable.referencedTables prostgles init config is missing`;
|
|
117
|
+
const cols = await this.dbo[refTable].getColumns();
|
|
118
|
+
const tableConfig = referencedTables[refTable];
|
|
119
|
+
if (typeof tableConfig !== "string") {
|
|
120
|
+
for await (const colName of (0, prostgles_types_1.getKeys)(tableConfig.referenceColumns)) {
|
|
121
|
+
const existingCol = cols.find(c => c.name === colName);
|
|
122
|
+
if (existingCol) {
|
|
123
|
+
if (existingCol.references?.ftable === tableName) {
|
|
124
|
+
// All ok
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (existingCol.udt_name === "uuid") {
|
|
128
|
+
try {
|
|
129
|
+
const query = `ALTER TABLE ${(0, prostgles_types_1.asName)(tableName)} ADD CONSTRAINT FOREIGN KEY (${(0, prostgles_types_1.asName)(colName)}) REFERENCES ${(0, prostgles_types_1.asName)(tableName)} (id);`;
|
|
130
|
+
console.log(`Referenced file column ${refTable} (${colName}) exists but is not referencing file table. Trying to add REFERENCE constraing...\n${query}`);
|
|
131
|
+
await this.db.any(query);
|
|
132
|
+
console.log("SUCCESS: " + query);
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
throw new Error(`Could not add constraing. Err: ${e instanceof Error ? e.message : JSON.stringify(e)}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
throw new Error(`Referenced file column ${refTable} (${colName}) exists but is not of required type (UUID). Choose a different column name or ALTER the existing column to match the type and the data found in file table ${tableName}(id)`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
140
142
|
}
|
|
141
|
-
|
|
143
|
+
else {
|
|
142
144
|
try {
|
|
143
|
-
|
|
144
|
-
console.log(
|
|
145
|
+
const query = `ALTER TABLE ${(0, prostgles_types_1.asName)(tableName)} ADD COLUMN ${(0, prostgles_types_1.asName)(colName)} UUID REFERENCES ${(0, prostgles_types_1.asName)(tableName)} (id);`;
|
|
146
|
+
console.log(`Creating referenced file column ${refTable} (${colName})...\n${query}`);
|
|
147
|
+
await this.db.any(query);
|
|
148
|
+
console.log("SUCCESS: " + query);
|
|
145
149
|
}
|
|
146
150
|
catch (e) {
|
|
147
|
-
|
|
151
|
+
throw new Error(`FAILED. Err: ${e instanceof Error ? e.message : JSON.stringify(e)}`);
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
|
-
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const lookupTableName = await this.parseSQLIdentifier(`prostgles_lookup_${tableName}_${refTable}`);
|
|
158
|
+
const pKeyFields = cols.filter(f => f.is_pkey);
|
|
159
|
+
if (pKeyFields.length !== 1)
|
|
160
|
+
throw `Could not make link table for ${refTable}. ${pKeyFields} must have exactly one primary key column. Current pkeys: ${pKeyFields.map(f => f.name)}`;
|
|
161
|
+
const pkField = pKeyFields[0];
|
|
162
|
+
const refType = referencedTables[refTable];
|
|
163
|
+
if (!this.dbo[lookupTableName]) {
|
|
164
|
+
// if(!(await dbo[lookupTableName].count())) await db.any(`DROP TABLE IF EXISTS ${lookupTableName};`);
|
|
165
|
+
const action = ` (${tableName} <-> ${refTable}) join table ${lookupTableName}`; // PRIMARY KEY
|
|
166
|
+
const query = `
|
|
167
|
+
CREATE TABLE ${lookupTableName} (
|
|
168
|
+
foreign_id ${pkField.udt_name} ${refType === "one" ? " PRIMARY KEY " : ""} REFERENCES ${(0, prostgles_types_1.asName)(refTable)}(${(0, prostgles_types_1.asName)(pkField.name)}),
|
|
169
|
+
media_id UUID NOT NULL REFERENCES ${(0, prostgles_types_1.asName)(tableName)}(id)
|
|
170
|
+
)
|
|
171
|
+
`;
|
|
172
|
+
console.log(`Creating ${action} ...`, lookupTableName);
|
|
173
|
+
await this.db.any(query);
|
|
174
|
+
console.log(`Created ${action}`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const cols = await this.dbo[lookupTableName].getColumns();
|
|
178
|
+
const badCols = cols.filter(c => !c.references);
|
|
179
|
+
await Promise.all(badCols.map(async (badCol) => {
|
|
180
|
+
console.error(`Prostgles: media ${lookupTableName} joining table has lost a reference constraint for column ${badCol.name}.` +
|
|
181
|
+
` This may have been caused by a DROP TABLE ... CASCADE.`);
|
|
182
|
+
let q = `
|
|
183
|
+
ALTER TABLE ${(0, prostgles_types_1.asName)(lookupTableName)}
|
|
184
|
+
ADD CONSTRAINT ${(lookupTableName + "_" + badCol.name + "_r")} FOREIGN KEY (${badCol.name})
|
|
185
|
+
`;
|
|
186
|
+
console.log("Trying to add the missing constraint back");
|
|
187
|
+
if (badCol.name === "foreign_id") {
|
|
188
|
+
q += `REFERENCES ${(0, prostgles_types_1.asName)(refTable)}(${(0, prostgles_types_1.asName)(pkField.name)}) `;
|
|
189
|
+
}
|
|
190
|
+
else if (badCol.name === "media_id") {
|
|
191
|
+
q += `REFERENCES ${(0, prostgles_types_1.asName)(tableName)}(id) `;
|
|
192
|
+
}
|
|
193
|
+
if (q) {
|
|
194
|
+
try {
|
|
195
|
+
await this.db.any(q);
|
|
196
|
+
console.log("Added missing constraint back");
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
console.error("Failed to add missing constraint", e);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
151
204
|
}
|
|
152
205
|
await prg.refreshDBO();
|
|
153
206
|
return true;
|
|
@@ -228,63 +281,108 @@ class FileManager {
|
|
|
228
281
|
return this.prostgles.db;
|
|
229
282
|
}
|
|
230
283
|
;
|
|
231
|
-
async
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
async parseFile(args) {
|
|
285
|
+
const { file, fileName, tableName, colName } = args;
|
|
286
|
+
const config = this.prostgles?.opts.fileTable;
|
|
287
|
+
if (!config)
|
|
288
|
+
throw new Error("File table config missing");
|
|
289
|
+
const buffer = typeof file === "string" ? Buffer.from(file, 'utf8') : file;
|
|
290
|
+
const mime = await (0, exports.getFileType)(buffer, fileName);
|
|
291
|
+
if (tableName && colName) {
|
|
292
|
+
const tableConfig = config.referencedTables?.[tableName];
|
|
293
|
+
if (tableConfig && (0, prostgles_types_1.isObject)(tableConfig) && tableConfig.referenceColumns[colName]) {
|
|
294
|
+
const colConfig = tableConfig.referenceColumns[colName];
|
|
295
|
+
if (colConfig.maxFileSizeMB) {
|
|
296
|
+
const actualBufferSize = Buffer.byteLength(buffer);
|
|
297
|
+
if ((actualBufferSize / 1e6) > colConfig.maxFileSizeMB) {
|
|
298
|
+
throw new Error(`Provided file is larger than the ${colConfig.maxFileSizeMB}MB limit`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if ("acceptedContent" in colConfig && colConfig.acceptedContent) {
|
|
302
|
+
const CONTENTS = [
|
|
303
|
+
"image",
|
|
304
|
+
"audio",
|
|
305
|
+
"video",
|
|
306
|
+
"text",
|
|
307
|
+
"application",
|
|
308
|
+
];
|
|
309
|
+
const allowedContent = DboBuilder_1.ViewHandler._parseFieldFilter(colConfig.acceptedContent, false, CONTENTS);
|
|
310
|
+
if (!allowedContent.some(c => mime.mime.startsWith(c))) {
|
|
311
|
+
throw new Error(`Dissallowed content type provided: ${mime.mime.split("/")[0]}. Allowed content types: ${allowedContent} `);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else if ("acceptedContentType" in colConfig && colConfig.acceptedContentType) {
|
|
315
|
+
const allowedContentTypes = DboBuilder_1.ViewHandler._parseFieldFilter(colConfig.acceptedContentType, false, (0, prostgles_types_1.getKeys)(prostgles_types_1.CONTENT_TYPE_TO_EXT));
|
|
316
|
+
if (!allowedContentTypes.some(c => c === mime.mime)) {
|
|
317
|
+
throw new Error(`Dissallowed MIME provided: ${mime.mime}. Allowed MIME values: ${allowedContentTypes} `);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else if ("acceptedFileTypes" in colConfig && colConfig.acceptedFileTypes) {
|
|
321
|
+
const allowedExtensions = DboBuilder_1.ViewHandler._parseFieldFilter(colConfig.acceptedFileTypes, false, Object.values(prostgles_types_1.CONTENT_TYPE_TO_EXT).flat());
|
|
322
|
+
if (!allowedExtensions.some(c => c === mime.ext)) {
|
|
323
|
+
throw new Error(`Dissallowed extension provided: ${mime.ext}. Allowed extension values: ${allowedExtensions} `);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
265
326
|
}
|
|
266
327
|
}
|
|
267
|
-
|
|
268
|
-
!allowedExtensions.map(v => v.toLowerCase())?.includes(type.ext)) {
|
|
269
|
-
throw fileName + " -> File type ( " + type.ext + " ) not allowed. Expecting one of: " + allowedExtensions.map(v => v.toLowerCase()).join(", ");
|
|
270
|
-
}
|
|
271
|
-
else if (dissallowedExtensions &&
|
|
272
|
-
dissallowedExtensions.map(v => v.toLowerCase())?.includes(type.ext)) {
|
|
273
|
-
throw fileName + " -> File type ( " + type.ext + " ) not allowed";
|
|
274
|
-
}
|
|
275
|
-
if (!onlyFromName) {
|
|
276
|
-
let { ext } = type;
|
|
277
|
-
if (nameExt !== ext)
|
|
278
|
-
fileName = nameParts.slice(0, -1).join('') + "." + ext;
|
|
279
|
-
}
|
|
280
|
-
const res = {
|
|
281
|
-
...type,
|
|
282
|
-
fileName
|
|
283
|
-
};
|
|
284
|
-
if (!res.mime)
|
|
285
|
-
throw "Could not find mime";
|
|
286
|
-
return res;
|
|
328
|
+
return mime;
|
|
287
329
|
}
|
|
330
|
+
// private async getMIME(
|
|
331
|
+
// file: Buffer | string,
|
|
332
|
+
// fileName: string,
|
|
333
|
+
// allowedExtensions?: Array<ALLOWED_EXTENSION>,
|
|
334
|
+
// dissallowedExtensions?: Array<ALLOWED_EXTENSION>,
|
|
335
|
+
// onlyFromName = true
|
|
336
|
+
// ): Promise<{
|
|
337
|
+
// mime: string;
|
|
338
|
+
// ext: string | ALLOWED_EXTENSION;
|
|
339
|
+
// fileName: string;
|
|
340
|
+
// }> {
|
|
341
|
+
// const nameParts = fileName.split(".");
|
|
342
|
+
// const nameExt = nameParts[nameParts.length - 1].toLowerCase(),
|
|
343
|
+
// mime = getKeys(CONTENT_TYPE_TO_EXT).find(k => (CONTENT_TYPE_TO_EXT[k] as readonly string[]).includes(nameExt));
|
|
344
|
+
// let type = {
|
|
345
|
+
// fileName,
|
|
346
|
+
// mime,
|
|
347
|
+
// ext: nameExt,
|
|
348
|
+
// }
|
|
349
|
+
// if(onlyFromName && !mime) throw `Invalid file extension: content_type could not be found for extension(${nameExt})`;
|
|
350
|
+
// if(!mime){
|
|
351
|
+
// /* Set correct/missing extension */
|
|
352
|
+
// if(["xml", "txt", "csv", "tsv"].includes(nameExt)){
|
|
353
|
+
// type = { ...type, mime: ("text/" + nameExt) as any, ext: nameExt };
|
|
354
|
+
// } else if(["svg"].includes(nameExt)){
|
|
355
|
+
// type = { ...type, mime: "image/svg+xml", ext: nameExt };
|
|
356
|
+
// } else {
|
|
357
|
+
// const res = await getFileTypeFromBuffer(file);
|
|
358
|
+
// type = {
|
|
359
|
+
// ...(res as any),
|
|
360
|
+
// fileName,
|
|
361
|
+
// }
|
|
362
|
+
// }
|
|
363
|
+
// }
|
|
364
|
+
// if(
|
|
365
|
+
// allowedExtensions &&
|
|
366
|
+
// !allowedExtensions.map(v => v.toLowerCase())?.includes(type.ext)
|
|
367
|
+
// ){
|
|
368
|
+
// throw fileName + " -> File type ( " + type.ext + " ) not allowed. Expecting one of: " + allowedExtensions.map(v => v.toLowerCase()).join(", ");
|
|
369
|
+
// } else if(
|
|
370
|
+
// dissallowedExtensions &&
|
|
371
|
+
// dissallowedExtensions.map(v => v.toLowerCase())?.includes(type.ext)
|
|
372
|
+
// ){
|
|
373
|
+
// throw fileName + " -> File type ( " + type.ext + " ) not allowed";
|
|
374
|
+
// }
|
|
375
|
+
// if(!onlyFromName){
|
|
376
|
+
// let { ext } = type;
|
|
377
|
+
// if(nameExt !== ext) fileName = nameParts.slice(0, -1).join('') + "." + ext;
|
|
378
|
+
// }
|
|
379
|
+
// const res = {
|
|
380
|
+
// ...type,
|
|
381
|
+
// fileName
|
|
382
|
+
// }
|
|
383
|
+
// if(!res.mime) throw "Could not find mime"
|
|
384
|
+
// return res as any;
|
|
385
|
+
// }
|
|
288
386
|
// async getUploadURL(fileName: string): Promise<string> {
|
|
289
387
|
// const thisHour = new Date();
|
|
290
388
|
// thisHour.setMilliseconds(0);
|
|
@@ -368,72 +466,43 @@ class FileManager {
|
|
|
368
466
|
}
|
|
369
467
|
}
|
|
370
468
|
exports.default = FileManager;
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
"
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
"
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
"application/x-java-archive-diff": ["jardiff"],
|
|
407
|
-
"application/x-java-jnlp-file": ["jnlp"],
|
|
408
|
-
"application/x-makeself": ["run"],
|
|
409
|
-
"application/x-perl": ["pl", "pm"],
|
|
410
|
-
"application/x-pilot": ["prc", "pdb"],
|
|
411
|
-
"application/x-rar-compressed": ["rar"],
|
|
412
|
-
"application/x-redhat-package-manager": ["rpm"],
|
|
413
|
-
"application/x-sea": ["sea"],
|
|
414
|
-
"application/x-shockwave-flash": ["swf"],
|
|
415
|
-
"application/x-stuffit": ["sit"],
|
|
416
|
-
"application/x-tcl": ["tcl", "tk"],
|
|
417
|
-
"application/x-x509-ca-cert": ["der", "pem", "crt"],
|
|
418
|
-
"application/x-xpinstall": ["xpi"],
|
|
419
|
-
"application/xhtml+xml": ["xhtml"],
|
|
420
|
-
"application/zip": ["zip"],
|
|
421
|
-
"application/octet-stream": ["bin", "exe", "dll", "deb", "dmg", "eot", "iso", "img", "msi", "msp", "msm"],
|
|
422
|
-
"audio/midi": ["mid", "midi", "kar"],
|
|
423
|
-
"audio/mpeg": ["mp3"],
|
|
424
|
-
"audio/ogg": ["ogg"],
|
|
425
|
-
"audio/x-realaudio": ["ra"],
|
|
426
|
-
"video/3gpp": ["3gpp", "3gp"],
|
|
427
|
-
"video/mpeg": ["mpeg", "mpg"],
|
|
428
|
-
"video/quicktime": ["mov"],
|
|
429
|
-
"video/x-flv": ["flv"],
|
|
430
|
-
"video/x-mng": ["mng"],
|
|
431
|
-
"video/x-ms-asf": ["asx", "asf"],
|
|
432
|
-
"video/x-ms-wmv": ["wmv"],
|
|
433
|
-
"video/x-msvideo": ["avi"],
|
|
434
|
-
"video/mp4": ["m4v", "mp4"],
|
|
435
|
-
"video/webm": ["webm"],
|
|
469
|
+
const getFileTypeFromFilename = (fileName) => {
|
|
470
|
+
const nameParts = fileName.split(".");
|
|
471
|
+
if (!nameParts.length)
|
|
472
|
+
return undefined;
|
|
473
|
+
const nameExt = nameParts[nameParts.length - 1].toLowerCase(), mime = (0, prostgles_types_1.getKeys)(prostgles_types_1.CONTENT_TYPE_TO_EXT).find(k => prostgles_types_1.CONTENT_TYPE_TO_EXT[k].includes(nameExt));
|
|
474
|
+
if (!mime)
|
|
475
|
+
return undefined;
|
|
476
|
+
return {
|
|
477
|
+
mime,
|
|
478
|
+
ext: nameExt,
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
exports.getFileTypeFromFilename = getFileTypeFromFilename;
|
|
482
|
+
// const fileType = require("file-type");
|
|
483
|
+
// const res = await fileType.fromBuffer(typeof file === "string"? Buffer.from(file, 'utf8') : file);
|
|
484
|
+
const getFileType = async (file, fileName) => {
|
|
485
|
+
const { fileTypeFromBuffer } = await eval('import("file-type")');
|
|
486
|
+
const fileNameMime = (0, exports.getFileTypeFromFilename)(fileName);
|
|
487
|
+
if (!fileNameMime?.ext)
|
|
488
|
+
throw new Error("File name must contain extenions");
|
|
489
|
+
const res = await fileTypeFromBuffer(typeof file === "string" ? Buffer.from(file, 'utf8') : file);
|
|
490
|
+
if (!res) {
|
|
491
|
+
/* Set correct/missing extension */
|
|
492
|
+
const nameExt = fileNameMime?.ext;
|
|
493
|
+
if (["xml", "txt", "csv", "tsv", "svg"].includes(nameExt)) {
|
|
494
|
+
return fileNameMime;
|
|
495
|
+
}
|
|
496
|
+
throw new Error("Could not get the file type from file buffer");
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
if (!res.ext || fileNameMime?.ext.toLowerCase() !== res.ext.toLowerCase()) {
|
|
500
|
+
throw new Error(`There is a mismatch between file name extension and actual buffer extension: ${fileNameMime?.ext} vs ${res.ext}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return res;
|
|
436
504
|
};
|
|
505
|
+
exports.getFileType = getFileType;
|
|
437
506
|
/**
|
|
438
507
|
*
|
|
439
508
|
|