Skip to content

Commit baf7246

Browse files
committed
Add upload file support
1 parent c2bfb21 commit baf7246

12 files changed

Lines changed: 523 additions & 169 deletions

OpenFlow/src/LoginProvider.ts

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ export class LoginProvider {
327327
res.end(JSON.stringify(res2));
328328
} catch (error) {
329329
span.recordException(error);
330+
return res.status(500).send({ message: error.message ? error.message : error });
330331
} finally {
331332
otel.endSpan(span);
332333
}
@@ -466,6 +467,7 @@ export class LoginProvider {
466467
LoginProvider.RegisterProviders(app, baseurl);
467468
} catch (error) {
468469
span.recordException(error);
470+
return res.status(500).send({ message: error.message ? error.message : error });
469471
} finally {
470472
otel.endSpan(span);
471473
}
@@ -536,17 +538,27 @@ export class LoginProvider {
536538
user = TokenUser.From(req.user);
537539
jwt = Crypt.createToken(user, Config.downloadtoken_expires_in);
538540
}
541+
const { query, headers } = req;
539542

540-
fileInfo.metadata.name = file.originalname;
541-
(fileInfo.metadata as any).filename = file.originalname;
543+
fileInfo.metadata.name = filename;
544+
(fileInfo.metadata as any).filename = filename;
542545
(fileInfo.metadata as any).path = "";
546+
(fileInfo.metadata as any).uniquename = query.uniquename;
547+
(fileInfo.metadata as any).form = query.form;
548+
(fileInfo.metadata as any).project = query.project;
549+
(fileInfo.metadata as any).baseurl = query.baseUrl;
543550
fileInfo.metadata._acl = [];
544551
fileInfo.metadata._createdby = user.name;
545552
fileInfo.metadata._createdbyid = user._id;
546553
fileInfo.metadata._created = new Date(new Date().toISOString());
547554
fileInfo.metadata._modifiedby = user.name;
548555
fileInfo.metadata._modifiedbyid = user._id;
549556
fileInfo.metadata._modified = fileInfo.metadata._created;
557+
558+
const keys = Object.keys(query);
559+
for (let i = 0; i < keys.length; i++) {
560+
fileInfo.metadata[keys[i]] = query[keys[i]];
561+
}
550562
Base.addRight(fileInfo.metadata, user._id, user.name, [Rights.full_control]);
551563
Base.addRight(fileInfo.metadata, WellknownIds.filestore_admins, "filestore admins", [Rights.full_control]);
552564
Base.addRight(fileInfo.metadata, WellknownIds.filestore_users, "filestore users", [Rights.read]);
@@ -556,8 +568,6 @@ export class LoginProvider {
556568
fileInfo.metadata._acl[index].rights = (new Binary(Buffer.from(a.rights, "base64"), 0) as any);
557569
}
558570
});
559-
560-
561571
resolve(fileInfo);
562572
});
563573
});
@@ -567,6 +577,112 @@ export class LoginProvider {
567577
storage: storage
568578
}).any();
569579

580+
// app.get("/upload", async (req: any, res: any, next: any): Promise<void> => {
581+
// const query = req.query;
582+
// });
583+
app.delete("/upload", async (req: any, res: any, next: any): Promise<void> => {
584+
const span: Span = otel.startSpan("LoginProvider.upload");
585+
try {
586+
let user: TokenUser = null;
587+
let jwt: string = null;
588+
const authHeader = req.headers.authorization;
589+
if (authHeader) {
590+
user = Crypt.verityToken(authHeader);
591+
jwt = Crypt.createToken(user, Config.downloadtoken_expires_in);
592+
}
593+
else if (req.user) {
594+
user = TokenUser.From(req.user as any);
595+
jwt = Crypt.createToken(user, Config.downloadtoken_expires_in);
596+
}
597+
if (user == null) {
598+
return res.status(404).send({ message: 'Route ' + req.url + ' Not found.' });
599+
}
600+
const query = req.query;
601+
console.log("baseUrl: " + query.baseUrl);
602+
console.log("form: " + query.form);
603+
console.log("project: " + query.project);
604+
console.log("uniquename: " + query.uniquename);
605+
let uniquename: string = query.uniquename;
606+
if (uniquename.indexOf('/') > -1) uniquename = uniquename.substr(0, uniquename.indexOf('/'));
607+
let q: any = {};
608+
if (!NoderedUtil.IsNullEmpty(uniquename)) {
609+
q = { "metadata.uniquename": uniquename };
610+
}
611+
612+
const arr = await Config.db.query(q, undefined, 1, 0, { "uploadDate": -1 }, "files", jwt, undefined, undefined, span);
613+
if (arr.length > 0) {
614+
await Config.db.DeleteOne(arr[0]._id, "files", jwt);
615+
}
616+
res.send({
617+
status: "success",
618+
display_status: "Success",
619+
message: uniquename + " deleted"
620+
});
621+
} catch (error) {
622+
span.recordException(error);
623+
console.error(error);
624+
return res.status(500).send({ message: error.message ? error.message : error });
625+
} finally {
626+
otel.endSpan(span);
627+
}
628+
629+
});
630+
// app.get("/upload/:fileId", async (req: any, res: any, next: any): Promise<void> => {
631+
app.get("/upload", async (req: any, res: any, next: any): Promise<void> => {
632+
const span: Span = otel.startSpan("LoginProvider.upload");
633+
try {
634+
let user: TokenUser = null;
635+
let jwt: string = null;
636+
const authHeader = req.headers.authorization;
637+
if (authHeader) {
638+
user = Crypt.verityToken(authHeader);
639+
jwt = Crypt.createToken(user, Config.downloadtoken_expires_in);
640+
}
641+
else if (req.user) {
642+
user = TokenUser.From(req.user as any);
643+
jwt = Crypt.createToken(user, Config.downloadtoken_expires_in);
644+
}
645+
if (user == null) {
646+
return res.status(404).send({ message: 'Route ' + req.url + ' Not found.' });
647+
}
648+
const query = req.query;
649+
console.log("baseUrl: " + query.baseUrl);
650+
console.log("form: " + query.form);
651+
console.log("project: " + query.project);
652+
console.log("uniquename: " + query.uniquename);
653+
let uniquename: string = query.uniquename;
654+
if (uniquename.indexOf('/') > -1) uniquename = uniquename.substr(0, uniquename.indexOf('/'));
655+
let q: any = {};
656+
if (!NoderedUtil.IsNullEmpty(uniquename)) {
657+
q = { "metadata.uniquename": uniquename };
658+
}
659+
660+
const arr = await Config.db.query(q, undefined, 1, 0, { "uploadDate": -1 }, "files", jwt, undefined, undefined, span);
661+
662+
const id = arr[0]._id;
663+
const rows = await Config.db.query({ _id: safeObjectID(id) }, null, 1, 0, null, "files", jwt, undefined, undefined, span);
664+
if (rows == null || rows.length != 1) { return res.status(404).send({ message: 'id ' + id + ' Not found.' }); }
665+
const file = rows[0] as any;
666+
667+
console.log("id: " + id);
668+
669+
const bucket = new GridFSBucket(Config.db.db);
670+
let downloadStream = bucket.openDownloadStream(safeObjectID(id));
671+
res.set('Content-Type', file.contentType);
672+
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
673+
res.set('Content-Length', file.length);
674+
downloadStream.on("error", function (err) {
675+
res.end();
676+
});
677+
downloadStream.pipe(res);
678+
return;
679+
} catch (error) {
680+
span.recordException(error);
681+
return res.status(500).send({ message: error.message ? error.message : error });
682+
} finally {
683+
otel.endSpan(span);
684+
}
685+
});
570686
app.post("/upload", async (req, res) => {
571687
let user: TokenUser = null;
572688
let jwt: string = null;

OpenFlow/src/WebServer.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,23 @@ export class WebServer {
6565
// if (!NoderedUtil.IsNullUndefinded(register)) register.registerMetric(webserver_rate_limit);
6666
// }
6767

68+
// this.app.get("/form", async (req: any, res: any, next: any): Promise<void> => {
69+
// res.send({
70+
// status: "success",
71+
// display_status: "Success",
72+
// message: "All system are go"
73+
// });
74+
// return;
75+
// });
76+
// this.app.get("/formio", async (req: any, res: any, next: any): Promise<void> => {
77+
// res.send({
78+
// status: "success",
79+
// display_status: "Success",
80+
// message: "All system are go"
81+
// });
82+
// return;
83+
// });
84+
6885
this.app.get("/metrics", async (req: any, res: any, next: any): Promise<void> => {
6986
let result: string = ""
7087
// if (!NoderedUtil.IsNullUndefinded(register)) {

OpenFlow/src/public/Controllers.ts

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { TokenUser, QueueMessage, SigninMessage, Ace, NoderedUser, Billing, stri
33
import { RPAWorkflow, Provider, Form, WorkflowInstance, Workflow, unattendedclient } from "./Entities";
44
import { WebSocketClientService } from "./WebSocketClientService";
55
import * as jsondiffpatch from "jsondiffpatch";
6+
import * as ofurl from "./formsio_of_provider";
67

78
function treatAsUTC(date): number {
89
const result = new Date(date);
@@ -1709,6 +1710,18 @@ export class EditFormCtrl extends entityCtrl<Form> {
17091710
} catch (error) {
17101711
await jsutil.loadScript("formio.full.min.js");
17111712
}
1713+
try {
1714+
const storage = "url";
1715+
const Providers = Formio.Providers
1716+
const p = Providers.getProviders('storage');
1717+
Providers.providers['storage'] = { "url": ofurl.default };
1718+
1719+
const Provider = Providers.getProvider('storage', storage);
1720+
const provider = new Provider(this);
1721+
// console.log(provider);
1722+
} catch (error) {
1723+
console.error(error);
1724+
}
17121725
if (this.model.formData == null || this.model.formData == undefined) { this.model.formData = {}; }
17131726
// "https://examples.form.io/wizard"
17141727
if (this.model.wizard == true) {
@@ -1722,11 +1735,48 @@ export class EditFormCtrl extends entityCtrl<Form> {
17221735
breadcrumbSettings: { clickable: false },
17231736
buttonSettings: { showCancel: false },
17241737
builder: {
1725-
data: false,
1726-
premium: false
1738+
resource: false,
1739+
// data: false,
1740+
// premium: false
1741+
premium: false,
1742+
basic: false,
1743+
customBasic: {
1744+
title: 'Basic',
1745+
default: true,
1746+
weight: 0,
1747+
components: {
1748+
file: true,
1749+
textfield: true,
1750+
textarea: true,
1751+
number: true,
1752+
password: true,
1753+
checkbox: true,
1754+
selectboxes: true,
1755+
select: true,
1756+
radio: true,
1757+
button: true,
1758+
}
1759+
1760+
}
1761+
},
1762+
hooks: {
1763+
customValidation: function (submission, next) {
1764+
console.log("customValidation");
1765+
console.log(submission);
1766+
}
17271767
}
1768+
17281769
});
1770+
// this.Formiobuilder.hook('customValidation', { ...submission, component: options.component }, (err) => {
1771+
this.Formiobuilder.options.hooks.beforeSubmit = (submission, callback) => {
1772+
console.log("beforeSubmit");
1773+
console.log(submission);
1774+
1775+
};
1776+
1777+
this.Formiobuilder.url = "/formio";
17291778
this.Formiobuilder.on('change', form => {
1779+
console.log("change");
17301780
this.model.schema = form;
17311781
})
17321782
this.Formiobuilder.on('submit', submission => {
@@ -1948,7 +1998,7 @@ export class FormCtrl extends entityCtrl<WorkflowInstance> {
19481998
if (!this.$scope.$$phase) { this.$scope.$apply(); }
19491999
console.error(this.errormessage);
19502000
}
1951-
this.loadData();
2001+
// this.loadData();
19522002
}
19532003
traversecomponentsPostProcess(components: any[], data: any) {
19542004
for (let i = 0; i < components.length; i++) {
@@ -2065,8 +2115,15 @@ export class FormCtrl extends entityCtrl<WorkflowInstance> {
20652115
}
20662116
}
20672117
}
2068-
2069-
// rows
2118+
}
2119+
traversecomponentsAddCustomValidate(components: any[]) {
2120+
for (let y = 0; y < components.length; y++) {
2121+
const item = components[y];
2122+
// if (item.validate == null) item.validate = {};
2123+
// item.validateOn = "blur";
2124+
// item.validate.custom = "console.log(arguments)";
2125+
// console.log(item);
2126+
}
20702127
}
20712128
sleep(ms) {
20722129
return new Promise(resolve => setTimeout(resolve, ms));
@@ -2075,6 +2132,7 @@ export class FormCtrl extends entityCtrl<WorkflowInstance> {
20752132
next();
20762133
}
20772134
async renderform() {
2135+
console.log('renderform');
20782136
if (this.form.fbeditor == null || this.form.fbeditor == undefined) this.form.fbeditor = true;
20792137
if ((this.form.fbeditor as any) == "true") this.form.fbeditor = true;
20802138
if ((this.form.fbeditor as any) == "false") this.form.fbeditor = false;
@@ -2165,7 +2223,21 @@ export class FormCtrl extends entityCtrl<WorkflowInstance> {
21652223
} catch (error) {
21662224
await jsutil.loadScript("formio.full.min.js");
21672225
}
2226+
try {
2227+
const storage = "url";
2228+
const Providers = Formio.Providers
2229+
const p = Providers.getProviders('storage');
2230+
Providers.providers['storage'] = { "url": ofurl.default };
2231+
2232+
const Provider = Providers.getProvider('storage', storage);
2233+
const provider = new Provider(this);
2234+
// console.log(provider);
2235+
} catch (error) {
2236+
console.error(error);
2237+
}
2238+
21682239
this.traversecomponentsMakeDefaults(this.form.schema.components);
2240+
this.traversecomponentsAddCustomValidate(this.form.schema.components);
21692241

21702242
if (this.form.wizard == true) {
21712243
this.form.schema.display = "wizard";
@@ -2178,37 +2250,33 @@ export class FormCtrl extends entityCtrl<WorkflowInstance> {
21782250
breadcrumbSettings: { clickable: true },
21792251
buttonSettings: { showCancel: false },
21802252
hooks: {
2181-
beforeSubmit: this.beforeSubmit.bind(this)
2253+
beforeSubmit: this.beforeSubmit.bind(this),
2254+
customValidation: async (submission, next) => {
2255+
console.log("customValidation");
2256+
console.log(submission);
2257+
$(".alert-success").hide();
2258+
setTimeout(() => {
2259+
// just to be safe
2260+
$(".alert-success").hide();
2261+
}, 200);
2262+
this.model.submission = submission;
2263+
this.model.userData = submission;
2264+
this.model.payload = submission.data;
2265+
this.traversecomponentsPostProcess(this.form.schema.components, submission.data);
2266+
next();
2267+
}
21822268
}
21832269
});
2270+
this.formioRender.on('submit', async submission => {
2271+
this.Save();
2272+
});
2273+
this.formioRender.url = "/formio";
21842274
// wizard
2185-
this.formioRender.on('change', form => {
2186-
//console.debug('change', form);
2187-
// setTimeout(() => {
2188-
// this.formioRender.submit();
2189-
// }, 200);
2190-
2191-
// this.model.schema = form;
2192-
// if (!this.$scope.$$phase) { this.$scope.$apply(); }
2193-
})
21942275
// https://formio.github.io/formio.js/app/examples/datagrid.html
21952276

21962277
if (this.model.payload != null && this.model.payload != undefined) {
21972278
this.formioRender.submission = { data: this.model.payload };
21982279
}
2199-
this.formioRender.on('submit', async submission => {
2200-
console.debug('onsubmit', submission);
2201-
$(".alert-success").hide();
2202-
setTimeout(() => {
2203-
// just to be safe
2204-
$(".alert-success").hide();
2205-
}, 200);
2206-
this.model.submission = submission;
2207-
this.model.userData = submission;
2208-
this.model.payload = submission.data;
2209-
this.traversecomponentsPostProcess(this.form.schema.components, submission.data);
2210-
this.Save();
2211-
})
22122280
this.formioRender.on('error', (errors) => {
22132281
this.errormessage = errors;
22142282
if (!this.$scope.$$phase) { this.$scope.$apply(); }

OpenFlow/src/public/formio.full.min.css

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)