diff --git a/README.md b/README.md index 3f3fea4b7..a1b979476 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ You can use the following [environment variables](https://docs.docker.com/refere `ME_CONFIG_OPTIONS_FULLWIDTH_LAYOUT` | `false` | if set to true an alternative page layout is used utilizing full window width. `ME_CONFIG_OPTIONS_PERSIST_EDIT_MODE` | `false` | if set to true, remain on same page after clicked on Save button `ME_CONFIG_OPTIONS_NO_DELETE` | `false` | if noDelete is true, components of deleting are not visible. + `ME_CONFIG_OPTIONS_NO_RAW_COMMAND`| `false` | if noRawCommand is true, the Raw tab in collection view is not visible. `ME_CONFIG_SITE_SSL_ENABLED` | `false` | Enable SSL. `ME_CONFIG_MONGODB_SSLVALIDATE` | `true` | Validate mongod server certificate against CA `ME_CONFIG_SITE_SSL_CRT_PATH` | ` ` | SSL certificate file. diff --git a/config.default.js b/config.default.js index 0ef3d6e0c..18052b996 100644 --- a/config.default.js +++ b/config.default.js @@ -195,6 +195,8 @@ export default { // noDelete: if noDelete is set to true, we won't show delete buttons noDelete: getBoolean(process.env.ME_CONFIG_OPTIONS_NO_DELETE, false), + + noRawCommand: getBoolean(process.env.ME_CONFIG_OPTIONS_NO_RAW_COMMAND, false), }, // Specify the default keyname that should be picked from a document to display in collections list. diff --git a/lib/middleware.js b/lib/middleware.js index 2d6a13c6b..bf330d6fa 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -43,6 +43,7 @@ const middleware = async function (config) { app.set('me_no_export', config.options.noExport || false); app.set('gridFSEnabled', config.options.gridFSEnabled || false); app.set('no_delete', config.options.noDelete || false); + app.set('no_raw_command', config.options.noRawCommand || false); return app; }; diff --git a/lib/routes/collection.js b/lib/routes/collection.js index 515f69a7a..06d1a301e 100644 --- a/lib/routes/collection.js +++ b/lib/routes/collection.js @@ -130,6 +130,43 @@ const routes = function (config) { // view all entries in a collection exp.viewCollection = async function (req, res) { + if (req.query.command) { + try { + const match = /^(.*?)\s*\((.*)\)\s*$/.exec(req.query.command); + if (!match || !match.length >= 3) { + req.session.error = 'Invalid command. Example: updateOne({myproperty:"someValue"}, {$set:{myproperty:"someOtherValue"}})'; + return res.redirect('back'); + } + + const fun = match[1]; + if (typeof req.collection[fun] === 'function') { + const args = match[2].split(',').map((s) => eval(`(${s})`)); + return req.collection[fun](...args, async function (err, result) { + if (err) { + req.session.error = err.message; + return res.redirect('back'); + } + try { + if (result.toArray) { + result = await result.toArray(); + } + req.session.success = JSON.stringify(result, null, 2); + } catch (e) { + console.error(e); + req.session.success = 'Command succeeded, but unable to parse the result'; + } + return res.redirect('back'); + }); + } + req.session.error = `Invalid function: ${fun}`; + return res.redirect('back'); + } catch (err) { + console.error(err); + req.session.error = 'Invalid command\nExample command: updateOne({myproperty:"someValue"}, {$set:{myproperty:"someOtherValue"}})'; + return res.redirect('back'); + } + } + let query; let queryOptions; try { diff --git a/lib/views/collection.html b/lib/views/collection.html index a9984aa67..effd9a907 100644 --- a/lib/views/collection.html +++ b/lib/views/collection.html @@ -81,6 +81,9 @@
@@ -140,6 +143,24 @@
+
+
+ {% for column in columns %} + + {% endfor %} +
+
+ +
+
+ +
+
+
+
{% if !settings.read_only && !settings.no_delete && count > 0 %}

diff --git a/lib/views/layout.html b/lib/views/layout.html index 175eef083..a6ed42da8 100644 --- a/lib/views/layout.html +++ b/lib/views/layout.html @@ -104,6 +104,7 @@

{{ title }}

window.ME_SETTINGS = { readOnly: '{{ !!settings.read_only }}' === 'true', noDelete: '{{ !!settings.no_delete }}' === 'true', + noRawCommand: '{{ !!settings.no_raw_command }}' === 'true', codeMirrorEditorTheme: '{{ editorTheme }}', baseHref: '{{ baseHref }}', collapsibleJSON: '{{ !!settings.me_collapsible_json }}' === 'true',