@saltcorn/server 0.6.1-beta.3 → 0.6.2-beta.2

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/s3storage.js ADDED
@@ -0,0 +1,167 @@
1
+ var aws = require("aws-sdk");
2
+ var express = require("express");
3
+ var multer = require("multer");
4
+ var multerS3 = require("multer-s3");
5
+ const { getState } = require("@saltcorn/data/db/state");
6
+ const fileUpload = require("express-fileupload");
7
+ const { v4: uuidv4 } = require("uuid");
8
+ const { create } = require("@saltcorn/data/models/file");
9
+ var contentDisposition = require("content-disposition");
10
+
11
+ function createS3Client() {
12
+ return new aws.S3({
13
+ secretAccessKey: getState().getConfig("storage_s3_access_secret"),
14
+ accessKeyId: getState().getConfig("storage_s3_access_key"),
15
+ region: getState().getConfig("storage_s3_region"),
16
+ endpoint: getState().getConfig("storage_s3_endpoint"),
17
+ });
18
+ }
19
+
20
+ module.exports = {
21
+ /**
22
+ * Selector for file upload handler middleware. It will dispatch the
23
+ * file upload handler to the engine specified in the configuration.
24
+ *
25
+ * @param {*} req
26
+ * @param {*} res
27
+ * @param {*} next
28
+ */
29
+ middlewareSelect: async function (req, res, next) {
30
+ const useS3 = getState().getConfig("storage_s3_enabled");
31
+ if (useS3 === true) {
32
+ // Create S3 object
33
+
34
+ // Create multer function
35
+ const s3upload = multer({
36
+ storage: multerS3({
37
+ s3: createS3Client(),
38
+ bucket: getState().getConfig("storage_s3_bucket"),
39
+ metadata: function (req, file, cb) {
40
+ cb(null, { fieldName: file.fieldname });
41
+ },
42
+ key: function (req, file, cb) {
43
+ cb(null, "tmp/" + Date.now().toString() + uuidv4());
44
+ },
45
+ }),
46
+ }).any();
47
+
48
+ s3upload(req, res, next);
49
+ } else {
50
+ // Use regular file upload
51
+ fileUpload({
52
+ useTempFiles: true,
53
+ createParentPath: true,
54
+ tempFileDir: "/tmp/",
55
+ })(req, res, next);
56
+ }
57
+ },
58
+
59
+ /**
60
+ * Transform the processed req.files into that is suitable with
61
+ * Saltcorn File interface. It must be run after the middlewareSelect
62
+ *
63
+ * @param {*} req
64
+ * @param {*} res
65
+ * @param {*} next
66
+ */
67
+ middlewareTransform: async function (req, res, next) {
68
+ // If nothing to process or S3 is not enabled
69
+ const useS3 = getState().getConfig("storage_s3_enabled");
70
+ if (!req.files || !useS3) {
71
+ next();
72
+ return;
73
+ }
74
+
75
+ // Create S3 object
76
+ var s3 = createS3Client();
77
+ const bucket = getState().getConfig("storage_s3_bucket");
78
+
79
+ let newFileObject = {};
80
+ for (const file of req.files) {
81
+ file.mv = (newpath) => {
82
+ return new Promise((resolve, reject) => {
83
+ s3.copyObject(
84
+ {
85
+ Bucket: bucket,
86
+ CopySource: bucket + "/" + file.key,
87
+ Key: newpath,
88
+ },
89
+ function (err, data) {
90
+ if (err) reject(err);
91
+ else {
92
+ // Then delete
93
+ s3.deleteObject(
94
+ {
95
+ Bucket: bucket,
96
+ Key: file.key,
97
+ },
98
+ (err, data) => {
99
+ if (err) reject(err);
100
+ else resolve(data);
101
+ }
102
+ );
103
+ }
104
+ }
105
+ );
106
+ });
107
+ };
108
+ file.s3object = true;
109
+ file.name = file.originalname;
110
+ newFileObject[file.fieldname] = file;
111
+ }
112
+ req.files = newFileObject;
113
+ next();
114
+ },
115
+
116
+ /**
117
+ * Selector to serve object based on S3 state
118
+ *
119
+ * @param {*} file
120
+ * @param {*} res
121
+ * @param {*} download
122
+ */
123
+ serveObject: function (file, res, download) {
124
+ if (file.s3_store) {
125
+ var s3 = createS3Client();
126
+ const bucket = getState().getConfig("storage_s3_bucket");
127
+
128
+ var params = {
129
+ Bucket: bucket,
130
+ Key: file.location,
131
+ };
132
+
133
+ // Forward the object
134
+ s3.getObject(params)
135
+ .on("httpHeaders", function (statusCode, headers) {
136
+ if (!!download)
137
+ res.set("Content-Disposition", contentDisposition(file.filename));
138
+ res.set("Content-Length", headers["content-length"]);
139
+ this.response.httpResponse.createUnbufferedStream().pipe(res);
140
+ })
141
+ .send();
142
+ } else {
143
+ // Use legacy file download
144
+ res.download(file.location, file.filename);
145
+ }
146
+ },
147
+
148
+ unlinkObject: function (file) {
149
+ if (file.s3_store) {
150
+ var s3 = createS3Client();
151
+ return new Promise((resolve, reject) => {
152
+ s3.deleteObject(
153
+ {
154
+ Bucket: getState().getConfig("storage_s3_bucket"),
155
+ Key: file.location,
156
+ },
157
+ (err, data) => {
158
+ if (err) reject(err);
159
+ else resolve(data);
160
+ }
161
+ );
162
+ });
163
+ } else {
164
+ return fs.unlink(file.location);
165
+ }
166
+ },
167
+ };
package/serve.js CHANGED
@@ -33,11 +33,14 @@ const { setTenant, getSessionStore } = require("./routes/utils");
33
33
  const passport = require("passport");
34
34
  const { authenticate } = require("passport");
35
35
  const View = require("@saltcorn/data/models/view");
36
+ const {
37
+ listenForChanges,
38
+ getRelevantPackages,
39
+ getPluginDirectories,
40
+ } = require("./restart_watcher");
36
41
 
37
42
  // helpful https://gist.github.com/jpoehls/2232358
38
-
39
43
  /**
40
- * @param {object} opts
41
44
  * @param {object} opts
42
45
  * @param {boolean} opts.disableMigrate
43
46
  * @param {boolean} [useClusterAdaptor = true]
@@ -146,6 +149,7 @@ module.exports =
146
149
  * @param {boolean} opts.watchReaper
147
150
  * @param {boolean} opts.disableScheduler
148
151
  * @param {number} opts.defaultNCPUs
152
+ * @param {boolean} opts.dev
149
153
  * @param {...*} opts.appargs
150
154
  * @returns {Promise<void>}
151
155
  */
@@ -154,8 +158,12 @@ module.exports =
154
158
  watchReaper,
155
159
  disableScheduler,
156
160
  defaultNCPUs,
161
+ dev,
157
162
  ...appargs
158
163
  } = {}) => {
164
+ if (dev && cluster.isMaster) {
165
+ listenForChanges(getRelevantPackages(), await getPluginDirectories());
166
+ }
159
167
  const useNCpus = process.env.SALTCORN_NWORKERS
160
168
  ? +process.env.SALTCORN_NWORKERS
161
169
  : defaultNCPUs;
package/wrapper.js CHANGED
@@ -240,12 +240,14 @@ module.exports = (version_tag) =>
240
240
  headers: get_headers(req, version_tag),
241
241
  role,
242
242
  req,
243
+ bodyClass: "auth",
243
244
  })
244
245
  );
245
246
  }
246
247
  };
247
248
  res.sendWrap = function (opts, ...html) {
248
249
  const title = typeof opts === "string" ? opts : opts.title;
250
+ const bodyClass = opts.bodyClass || "";
249
251
  const alerts = getFlashes(req);
250
252
  const state = getState();
251
253
  const layout = state.getLayout(req.user);
@@ -282,6 +284,7 @@ module.exports = (version_tag) =>
282
284
  headers: get_headers(req, version_tag, opts.description, pageHeaders),
283
285
  role,
284
286
  req,
287
+ bodyClass,
285
288
  })
286
289
  );
287
290
  };