mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	Default Site customisation and new Settings space (#91)
This commit is contained in:
		| @@ -22,10 +22,10 @@ server { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| # Default 80 Host, which shows a "You are not configured" page | # "You are not configured" page, which is the default if another default doesn't exist | ||||||
| server { | server { | ||||||
|   listen 80 default; |   listen 80; | ||||||
|   server_name localhost; |   server_name localhost-nginx-proxy-manager; | ||||||
|  |  | ||||||
|   access_log /data/logs/default.log proxy; |   access_log /data/logs/default.log proxy; | ||||||
|  |  | ||||||
| @@ -38,9 +38,9 @@ server { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| # Default 443 Host | # First 443 Host, which is the default if another default doesn't exist | ||||||
| server { | server { | ||||||
|   listen 443 ssl default; |   listen 443 ssl; | ||||||
|   server_name localhost; |   server_name localhost; | ||||||
|  |  | ||||||
|   access_log /data/logs/default.log proxy; |   access_log /data/logs/default.log proxy; | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ http { | |||||||
|  |  | ||||||
|   # Files generated by NPM |   # Files generated by NPM | ||||||
|   include /etc/nginx/conf.d/*.conf; |   include /etc/nginx/conf.d/*.conf; | ||||||
|  |   include /data/nginx/default_host/*.conf; | ||||||
|   include /data/nginx/proxy_host/*.conf; |   include /data/nginx/proxy_host/*.conf; | ||||||
|   include /data/nginx/redirection_host/*.conf; |   include /data/nginx/redirection_host/*.conf; | ||||||
|   include /data/nginx/dead_host/*.conf; |   include /data/nginx/dead_host/*.conf; | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ mkdir -p /tmp/nginx/body \ | |||||||
|   /data/custom_ssl \ |   /data/custom_ssl \ | ||||||
|   /data/logs \ |   /data/logs \ | ||||||
|   /data/access \ |   /data/access \ | ||||||
|  |   /data/nginx/default_host \ | ||||||
|  |   /data/nginx/default_www \ | ||||||
|   /data/nginx/proxy_host \ |   /data/nginx/proxy_host \ | ||||||
|   /data/nginx/redirection_host \ |   /data/nginx/redirection_host \ | ||||||
|   /data/nginx/stream \ |   /data/nginx/stream \ | ||||||
|   | |||||||
| @@ -17,9 +17,9 @@ const internalNginx = { | |||||||
|      * - IF BAD: update the meta with offline status and remove the config entirely |      * - IF BAD: update the meta with offline status and remove the config entirely | ||||||
|      * - then reload nginx |      * - then reload nginx | ||||||
|      * |      * | ||||||
|      * @param   {Object}  model |      * @param   {Object|String}  model | ||||||
|      * @param   {String}  host_type |      * @param   {String}         host_type | ||||||
|      * @param   {Object}  host |      * @param   {Object}         host | ||||||
|      * @returns {Promise} |      * @returns {Promise} | ||||||
|      */ |      */ | ||||||
|     configure: (model, host_type, host) => { |     configure: (model, host_type, host) => { | ||||||
| @@ -122,6 +122,11 @@ const internalNginx = { | |||||||
|      */ |      */ | ||||||
|     getConfigName: (host_type, host_id) => { |     getConfigName: (host_type, host_id) => { | ||||||
|         host_type = host_type.replace(new RegExp('-', 'g'), '_'); |         host_type = host_type.replace(new RegExp('-', 'g'), '_'); | ||||||
|  |  | ||||||
|  |         if (host_type === 'default') { | ||||||
|  |             return '/data/nginx/default_host/site.conf'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return '/data/nginx/' + host_type + '/' + host_id + '.conf'; |         return '/data/nginx/' + host_type + '/' + host_id + '.conf'; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
| @@ -153,9 +158,11 @@ const internalNginx = { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Manipulate the data a bit before sending it to the template |             // Manipulate the data a bit before sending it to the template | ||||||
|             host.use_default_location = true; |             if (host_type !== 'default') { | ||||||
|             if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { |                 host.use_default_location = true; | ||||||
|                 host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); |                 if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { | ||||||
|  |                     host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             renderEngine |             renderEngine | ||||||
| @@ -260,7 +267,7 @@ const internalNginx = { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param   {String}  host_type |      * @param   {String}  host_type | ||||||
|      * @param   {Object}  host |      * @param   {Object}  [host] | ||||||
|      * @param   {Boolean} [throw_errors] |      * @param   {Boolean} [throw_errors] | ||||||
|      * @returns {Promise} |      * @returns {Promise} | ||||||
|      */ |      */ | ||||||
| @@ -269,7 +276,7 @@ const internalNginx = { | |||||||
|  |  | ||||||
|         return new Promise((resolve, reject) => { |         return new Promise((resolve, reject) => { | ||||||
|             try { |             try { | ||||||
|                 let config_file = internalNginx.getConfigName(host_type, host.id); |                 let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id); | ||||||
|  |  | ||||||
|                 if (debug_mode) { |                 if (debug_mode) { | ||||||
|                     logger.warn('Deleting nginx config: ' + config_file); |                     logger.warn('Deleting nginx config: ' + config_file); | ||||||
|   | |||||||
| @@ -108,7 +108,7 @@ const internalProxyHost = { | |||||||
|      */ |      */ | ||||||
|     update: (access, data) => { |     update: (access, data) => { | ||||||
|         let create_certificate = data.certificate_id === 'new'; |         let create_certificate = data.certificate_id === 'new'; | ||||||
| console.log('PH UPDATE:', data); |  | ||||||
|         if (create_certificate) { |         if (create_certificate) { | ||||||
|             delete data.certificate_id; |             delete data.certificate_id; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										133
									
								
								src/backend/internal/setting.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/backend/internal/setting.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | const fs            = require('fs'); | ||||||
|  | const error         = require('../lib/error'); | ||||||
|  | const settingModel  = require('../models/setting'); | ||||||
|  | const internalNginx = require('./nginx'); | ||||||
|  |  | ||||||
|  | const internalSetting = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param  {Access}  access | ||||||
|  |      * @param  {Object}  data | ||||||
|  |      * @param  {String}  data.id | ||||||
|  |      * @return {Promise} | ||||||
|  |      */ | ||||||
|  |     update: (access, data) => { | ||||||
|  |         return access.can('settings:update', data.id) | ||||||
|  |             .then(access_data => { | ||||||
|  |                 return internalSetting.get(access, {id: data.id}); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 if (row.id !== data.id) { | ||||||
|  |                     // Sanity check that something crazy hasn't happened | ||||||
|  |                     throw new error.InternalValidationError('Setting could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return settingModel | ||||||
|  |                     .query() | ||||||
|  |                     .where({id: data.id}) | ||||||
|  |                     .patch(data); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 return internalSetting.get(access, { | ||||||
|  |                     id: data.id | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 if (row.id === 'default-site') { | ||||||
|  |                     // write the html if we need to | ||||||
|  |                     if (row.value === 'html') { | ||||||
|  |                         fs.writeFileSync('/data/nginx/default_www/index.html', row.meta.html, {encoding: 'utf8'}); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     // Configure nginx | ||||||
|  |                     return internalNginx.deleteConfig('default') | ||||||
|  |                         .then(() => { | ||||||
|  |                             return internalNginx.generateConfig('default', row); | ||||||
|  |                         }) | ||||||
|  |                         .then(() => { | ||||||
|  |                             return internalNginx.test(); | ||||||
|  |                         }) | ||||||
|  |                         .then(() => { | ||||||
|  |                             return internalNginx.reload(); | ||||||
|  |                         }) | ||||||
|  |                         .then(() => { | ||||||
|  |                             return row; | ||||||
|  |                         }) | ||||||
|  |                         .catch((err) => { | ||||||
|  |                             internalNginx.deleteConfig('default') | ||||||
|  |                                 .then(() => { | ||||||
|  |                                     return internalNginx.test(); | ||||||
|  |                                 }) | ||||||
|  |                                 .then(() => { | ||||||
|  |                                     return internalNginx.reload(); | ||||||
|  |                                 }) | ||||||
|  |                                 .then(() => { | ||||||
|  |                                     // I'm being slack here I know.. | ||||||
|  |                                     throw new error.ValidationError('Could not reconfigure Nginx. Please check logs.'); | ||||||
|  |                                 }) | ||||||
|  |                         }); | ||||||
|  |                 } else { | ||||||
|  |                     return row; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param  {Access}   access | ||||||
|  |      * @param  {Object}   data | ||||||
|  |      * @param  {String}   data.id | ||||||
|  |      * @return {Promise} | ||||||
|  |      */ | ||||||
|  |     get: (access, data) => { | ||||||
|  |         return access.can('settings:get', data.id) | ||||||
|  |             .then(() => { | ||||||
|  |                 return settingModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('id', data.id) | ||||||
|  |                     .first(); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 if (row) { | ||||||
|  |                     return row; | ||||||
|  |                 } else { | ||||||
|  |                     throw new error.ItemNotFoundError(data.id); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * This will only count the settings | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @returns {*} | ||||||
|  |      */ | ||||||
|  |     getCount: (access) => { | ||||||
|  |         return access.can('settings:list') | ||||||
|  |             .then(() => { | ||||||
|  |                 return settingModel | ||||||
|  |                     .query() | ||||||
|  |                     .count('id as count') | ||||||
|  |                     .first(); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 return parseInt(row.count, 10); | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All settings | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getAll: (access) => { | ||||||
|  |         return access.can('settings:list') | ||||||
|  |             .then(() => { | ||||||
|  |                 return settingModel | ||||||
|  |                     .query() | ||||||
|  |                     .orderBy('description', 'ASC'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalSetting; | ||||||
							
								
								
									
										7
									
								
								src/backend/lib/access/settings-get.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/backend/lib/access/settings-get.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								src/backend/lib/access/settings-list.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/backend/lib/access/settings-list.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								src/backend/lib/access/settings-update.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/backend/lib/access/settings-update.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										54
									
								
								src/backend/migrations/20190227065017_settings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/backend/migrations/20190227065017_settings.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | const migrate_name = 'settings'; | ||||||
|  | const logger       = require('../logger').migrate; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Migrate | ||||||
|  |  * | ||||||
|  |  * @see http://knexjs.org/#Schema | ||||||
|  |  * | ||||||
|  |  * @param   {Object}  knex | ||||||
|  |  * @param   {Promise} Promise | ||||||
|  |  * @returns {Promise} | ||||||
|  |  */ | ||||||
|  | exports.up = function (knex/*, Promise*/) { | ||||||
|  |     logger.info('[' + migrate_name + '] Migrating Up...'); | ||||||
|  |  | ||||||
|  |     return knex.schema.createTable('setting', table => { | ||||||
|  |             table.string('id').notNull().primary(); | ||||||
|  |             table.string('name', 100).notNull(); | ||||||
|  |             table.string('description', 255).notNull(); | ||||||
|  |             table.string('value', 255).notNull(); | ||||||
|  |             table.json('meta').notNull(); | ||||||
|  |         }) | ||||||
|  |         .then(() => { | ||||||
|  |             logger.info('[' + migrate_name + '] setting Table created'); | ||||||
|  |  | ||||||
|  |             // TODO: add settings | ||||||
|  |             let settingModel = require('../models/setting'); | ||||||
|  |  | ||||||
|  |             return settingModel | ||||||
|  |                 .query() | ||||||
|  |                 .insert({ | ||||||
|  |                     id:          'default-site', | ||||||
|  |                     name:        'Default Site', | ||||||
|  |                     description: 'What to show when Nginx is hit with an unknown Host', | ||||||
|  |                     value:       'congratulations', | ||||||
|  |                     meta:        {} | ||||||
|  |                 }); | ||||||
|  |         }) | ||||||
|  |         .then(() => { | ||||||
|  |             logger.info('[' + migrate_name + '] Default settings added'); | ||||||
|  |         }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Undo Migrate | ||||||
|  |  * | ||||||
|  |  * @param   {Object}  knex | ||||||
|  |  * @param   {Promise} Promise | ||||||
|  |  * @returns {Promise} | ||||||
|  |  */ | ||||||
|  | exports.down = function (knex, Promise) { | ||||||
|  |     logger.warn('[' + migrate_name + '] You can\'t migrate down the initial data.'); | ||||||
|  |     return Promise.resolve(true); | ||||||
|  | }; | ||||||
							
								
								
									
										30
									
								
								src/backend/models/setting.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/backend/models/setting.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // Objection Docs: | ||||||
|  | // http://vincit.github.io/objection.js/ | ||||||
|  |  | ||||||
|  | const db    = require('../db'); | ||||||
|  | const Model = require('objection').Model; | ||||||
|  |  | ||||||
|  | Model.knex(db); | ||||||
|  |  | ||||||
|  | class Setting extends Model { | ||||||
|  |     $beforeInsert () { | ||||||
|  |         // Default for meta | ||||||
|  |         if (typeof this.meta === 'undefined') { | ||||||
|  |             this.meta = {}; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get name () { | ||||||
|  |         return 'Setting'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get tableName () { | ||||||
|  |         return 'setting'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get jsonAttributes () { | ||||||
|  |         return ['meta']; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = Setting; | ||||||
| @@ -31,6 +31,7 @@ router.use('/tokens', require('./tokens')); | |||||||
| router.use('/users', require('./users')); | router.use('/users', require('./users')); | ||||||
| router.use('/audit-log', require('./audit-log')); | router.use('/audit-log', require('./audit-log')); | ||||||
| router.use('/reports', require('./reports')); | router.use('/reports', require('./reports')); | ||||||
|  | router.use('/settings', require('./settings')); | ||||||
| router.use('/nginx/proxy-hosts', require('./nginx/proxy_hosts')); | router.use('/nginx/proxy-hosts', require('./nginx/proxy_hosts')); | ||||||
| router.use('/nginx/redirection-hosts', require('./nginx/redirection_hosts')); | router.use('/nginx/redirection-hosts', require('./nginx/redirection_hosts')); | ||||||
| router.use('/nginx/dead-hosts', require('./nginx/dead_hosts')); | router.use('/nginx/dead-hosts', require('./nginx/dead_hosts')); | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								src/backend/routes/api/settings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/backend/routes/api/settings.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | |||||||
|  | const express         = require('express'); | ||||||
|  | const validator       = require('../../lib/validator'); | ||||||
|  | const jwtdecode       = require('../../lib/express/jwt-decode'); | ||||||
|  | const internalSetting = require('../../internal/setting'); | ||||||
|  | const apiValidator    = require('../../lib/validator/api'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * /api/settings | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/settings | ||||||
|  |      * | ||||||
|  |      * Retrieve all settings | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         internalSetting.getAll(res.locals.access) | ||||||
|  |             .then(rows => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(rows); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Specific setting | ||||||
|  |  * | ||||||
|  |  * /api/settings/something | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/:setting_id') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /settings/something | ||||||
|  |      * | ||||||
|  |      * Retrieve a specific setting | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             required:             ['setting_id'], | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 setting_id: { | ||||||
|  |                     $ref: 'definitions#/definitions/setting_id' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             setting_id: req.params.setting_id | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalSetting.get(res.locals.access, { | ||||||
|  |                     id: data.setting_id | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(row); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PUT /api/settings/something | ||||||
|  |      * | ||||||
|  |      * Update and existing setting | ||||||
|  |      */ | ||||||
|  |     .put((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/settings#/links/1/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 payload.id = req.params.setting_id; | ||||||
|  |                 return internalSetting.update(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
| @@ -9,6 +9,13 @@ | |||||||
|       "type": "integer", |       "type": "integer", | ||||||
|       "minimum": 1 |       "minimum": 1 | ||||||
|     }, |     }, | ||||||
|  |     "setting_id": { | ||||||
|  |       "description": "Unique identifier for a Setting", | ||||||
|  |       "example": "default-site", | ||||||
|  |       "readOnly": true, | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2 | ||||||
|  |     }, | ||||||
|     "token": { |     "token": { | ||||||
|       "type": "string", |       "type": "string", | ||||||
|       "minLength": 10 |       "minLength": 10 | ||||||
|   | |||||||
							
								
								
									
										99
									
								
								src/backend/schema/endpoints/settings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/backend/schema/endpoints/settings.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "endpoints/settings", | ||||||
|  |   "title": "Settings", | ||||||
|  |   "description": "Endpoints relating to Settings", | ||||||
|  |   "stability": "stable", | ||||||
|  |   "type": "object", | ||||||
|  |   "definitions": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/setting_id" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "description": "Name", | ||||||
|  |       "example": "Default Site", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 100 | ||||||
|  |     }, | ||||||
|  |     "description": { | ||||||
|  |       "description": "Description", | ||||||
|  |       "example": "Default Site", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 255 | ||||||
|  |     }, | ||||||
|  |     "value": { | ||||||
|  |       "description": "Value", | ||||||
|  |       "example": "404", | ||||||
|  |       "type": "string", | ||||||
|  |       "maxLength": 255 | ||||||
|  |     }, | ||||||
|  |     "meta": { | ||||||
|  |       "type": "object" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "title": "List", | ||||||
|  |       "description": "Returns a list of Settings", | ||||||
|  |       "href": "/settings", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "GET", | ||||||
|  |       "rel": "self", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Update", | ||||||
|  |       "description": "Updates a existing Setting", | ||||||
|  |       "href": "/settings/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "PUT", | ||||||
|  |       "rel": "update", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "properties": { | ||||||
|  |           "value": { | ||||||
|  |             "$ref": "#/definitions/value" | ||||||
|  |           }, | ||||||
|  |           "meta": { | ||||||
|  |             "$ref": "#/definitions/meta" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "$ref": "#/definitions/description" | ||||||
|  |     }, | ||||||
|  |     "description": { | ||||||
|  |       "$ref": "#/definitions/description" | ||||||
|  |     }, | ||||||
|  |     "value": { | ||||||
|  |       "$ref": "#/definitions/value" | ||||||
|  |     }, | ||||||
|  |     "meta": { | ||||||
|  |       "$ref": "#/definitions/meta" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -34,6 +34,9 @@ | |||||||
|     }, |     }, | ||||||
|     "access-lists": { |     "access-lists": { | ||||||
|       "$ref": "endpoints/access-lists.json" |       "$ref": "endpoints/access-lists.json" | ||||||
|  |     }, | ||||||
|  |     "settings": { | ||||||
|  |       "$ref": "endpoints/settings.json" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/backend/templates/default.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/backend/templates/default.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | # ------------------------------------------------------------ | ||||||
|  | # Default Site | ||||||
|  | # ------------------------------------------------------------ | ||||||
|  | {% if value == "congratulations" %} | ||||||
|  | # Skipping output, congratulations page configration is baked in. | ||||||
|  | {%- else %} | ||||||
|  | server { | ||||||
|  |   listen 80 default; | ||||||
|  |   server_name default-host.localhost; | ||||||
|  |   access_log /data/logs/default_host.log combined; | ||||||
|  | {% include "_exploits.conf" %} | ||||||
|  |  | ||||||
|  | {%- if value == "404" %} | ||||||
|  |   location / { | ||||||
|  |     return 404; | ||||||
|  |   } | ||||||
|  | {% endif %} | ||||||
|  |  | ||||||
|  | {%- if value == "redirect" %} | ||||||
|  |   location / { | ||||||
|  |     return 301 {{ meta.redirect }}; | ||||||
|  |   } | ||||||
|  | {%- endif %} | ||||||
|  |  | ||||||
|  | {%- if value == "html" %} | ||||||
|  |   root /data/nginx/default_www; | ||||||
|  |   location / { | ||||||
|  |     try_files $uri /index.html ={{ meta.http_code }}; | ||||||
|  |   } | ||||||
|  | {%- endif %} | ||||||
|  | } | ||||||
|  | {% endif %} | ||||||
| @@ -662,5 +662,34 @@ module.exports = { | |||||||
|         getHostStats: function () { |         getHostStats: function () { | ||||||
|             return fetch('get', 'reports/hosts'); |             return fetch('get', 'reports/hosts'); | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     Settings: { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @param   {String}  setting_id | ||||||
|  |          * @returns {Promise} | ||||||
|  |          */ | ||||||
|  |         getById: function (setting_id) { | ||||||
|  |             return fetch('get', 'settings/' + setting_id); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @returns {Promise} | ||||||
|  |          */ | ||||||
|  |         getAll: function () { | ||||||
|  |             return getAllObjects('settings'); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @param   {Object}   data | ||||||
|  |          * @param   {Number}   data.id | ||||||
|  |          * @returns {Promise} | ||||||
|  |          */ | ||||||
|  |         update: function (data) { | ||||||
|  |             let id = data.id; | ||||||
|  |             delete data.id; | ||||||
|  |             return fetch('put', 'settings/' + id, data); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -383,6 +383,36 @@ module.exports = { | |||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Settings | ||||||
|  |      */ | ||||||
|  |     showSettings: function () { | ||||||
|  |         let controller = this; | ||||||
|  |         if (Cache.User.isAdmin()) { | ||||||
|  |             require(['./main', './settings/main'], (App, View) => { | ||||||
|  |                 controller.navigate('/settings'); | ||||||
|  |                 App.UI.showAppContent(new View()); | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             this.showDashboard(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Settings Item Form | ||||||
|  |      * | ||||||
|  |      * @param model | ||||||
|  |      */ | ||||||
|  |     showSettingForm: function (model) { | ||||||
|  |         if (Cache.User.isAdmin()) { | ||||||
|  |             if (model.get('id') === 'default-site') { | ||||||
|  |                 require(['./main', './settings/default-site/main'], function (App, View) { | ||||||
|  |                     App.UI.showModalDialog(new View({model: model})); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Logout |      * Logout | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ module.exports = AppRouter.default.extend({ | |||||||
|         'nginx/access':       'showNginxAccess', |         'nginx/access':       'showNginxAccess', | ||||||
|         'nginx/certificates': 'showNginxCertificates', |         'nginx/certificates': 'showNginxCertificates', | ||||||
|         'audit-log':          'showAuditLog', |         'audit-log':          'showAuditLog', | ||||||
|  |         'settings':           'showSettings', | ||||||
|         '*default':           'showDashboard' |         '*default':           'showDashboard' | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										77
									
								
								src/frontend/js/app/settings/default-site/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/frontend/js/app/settings/default-site/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | <div class="modal-content"> | ||||||
|  |     <div class="modal-header"> | ||||||
|  |         <h5 class="modal-title"><%- i18n('settings', id) %></h5> | ||||||
|  |         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button> | ||||||
|  |     </div> | ||||||
|  |     <div class="modal-body"> | ||||||
|  |         <form> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <div class="col-sm-12 col-md-12"> | ||||||
|  |                     <div class="form-group"> | ||||||
|  |                         <div class="form-label"><%- description %></div> | ||||||
|  |                         <div class="custom-controls-stacked"> | ||||||
|  |                             <label class="custom-control custom-radio"> | ||||||
|  |                                 <input class="custom-control-input" name="value" value="congratulations" type="radio" required <%- value === 'congratulations' ? 'checked' : '' %>> | ||||||
|  |                                 <div class="custom-control-label"><%- i18n('settings', 'default-site-congratulations') %></div> | ||||||
|  |                             </label> | ||||||
|  |                             <label class="custom-control custom-radio"> | ||||||
|  |                                 <input class="custom-control-input" name="value" value="404" type="radio" required <%- value === '404' ? 'checked' : '' %>> | ||||||
|  |                                 <div class="custom-control-label"><%- i18n('settings', 'default-site-404') %></div> | ||||||
|  |                             </label> | ||||||
|  |                             <label class="custom-control custom-radio"> | ||||||
|  |                                 <input class="custom-control-input" name="value" value="redirect" type="radio" required <%- value === 'redirect' ? 'checked' : '' %>> | ||||||
|  |                                 <div class="custom-control-label"><%- i18n('settings', 'default-site-redirect') %></div> | ||||||
|  |                             </label> | ||||||
|  |                             <label class="custom-control custom-radio"> | ||||||
|  |                                 <input class="custom-control-input" name="value" value="html" type="radio" required <%- value === 'html' ? 'checked' : '' %>> | ||||||
|  |                                 <div class="custom-control-label"><%- i18n('settings', 'default-site-html') %></div> | ||||||
|  |                             </label> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 <div class="col-sm-12 col-md-12 option-item option-redirect"> | ||||||
|  |                     <div class="form-group"> | ||||||
|  |                         <div class="form-label">Redirect to</div> | ||||||
|  |                         <input class="form-control redirect-input" name="meta[redirect]" placeholder="https://" type="url" value="<%- meta && typeof meta.redirect !== 'undefined' ? meta.redirect : '' %>"> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 <div class="col-sm-12 col-md-12 option-item option-html"> | ||||||
|  |                     <div class="form-group"> | ||||||
|  |                         <label class="form-label">HTTP Status Code</label> | ||||||
|  |                         <% | ||||||
|  |                         var code = meta && typeof meta.http_code !== 'undefined' ? parseInt(meta.http_code, 10) : 200; | ||||||
|  |                         var codes = [ | ||||||
|  |                             [200, 'OK'], | ||||||
|  |                             [204, 'No Content'], | ||||||
|  |                             [400, 'Bad Request'], | ||||||
|  |                             [401, 'Unauthorized'], | ||||||
|  |                             [403, 'Forbidden'], | ||||||
|  |                             [404, 'Not Found'], | ||||||
|  |                             [418, 'I\'m a Teapot'], | ||||||
|  |                             [500, 'Internal Server Error'], | ||||||
|  |                             [501, 'Not Implemented'], | ||||||
|  |                             [502, 'Bad Gateway'], | ||||||
|  |                             [503, 'Service Unavailable'] | ||||||
|  |                         ]; | ||||||
|  |                         %> | ||||||
|  |                         <select class="custom-select" name="meta[http_code]"> | ||||||
|  |                             <% codes.map(function(item) { %> | ||||||
|  |                             <option value="<%- item[0] %>"<%- code === item[0] ? ' selected' : '' %>><%- item[0] %> - <%- item[1] %></option> | ||||||
|  |                             <% }); %> | ||||||
|  |                         </select> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="form-group"> | ||||||
|  |                         <div class="form-label">HTML Content</div> | ||||||
|  |                         <textarea class="form-control text-monospace html-content" name="meta[html]" rows="6" placeholder="<!-- Enter your HTML here -->"><%- meta && typeof meta.html !== 'undefined' ? meta.html : '' %></textarea> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </form> | ||||||
|  |     </div> | ||||||
|  |     <div class="modal-footer"> | ||||||
|  |         <button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button> | ||||||
|  |         <button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
							
								
								
									
										71
									
								
								src/frontend/js/app/settings/default-site/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/frontend/js/app/settings/default-site/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const App      = require('../../main'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | require('jquery-serializejson'); | ||||||
|  | require('selectize'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template:  template, | ||||||
|  |     className: 'modal-dialog', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         form:     'form', | ||||||
|  |         buttons:  '.modal-footer button', | ||||||
|  |         cancel:   'button.cancel', | ||||||
|  |         save:     'button.save', | ||||||
|  |         options:  '.option-item', | ||||||
|  |         value:    'input[name="value"]', | ||||||
|  |         redirect: '.redirect-input', | ||||||
|  |         html:     '.html-content' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'change @ui.value': function (e) { | ||||||
|  |             let val = this.ui.value.filter(':checked').val(); | ||||||
|  |             this.ui.options.hide(); | ||||||
|  |             this.ui.options.filter('.option-' + val).show(); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.save': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |  | ||||||
|  |             let val = this.ui.value.filter(':checked').val(); | ||||||
|  |  | ||||||
|  |             // Clear redirect field before validation | ||||||
|  |             if (val !== 'redirect') { | ||||||
|  |                 this.ui.redirect.val('').attr('required', false); | ||||||
|  |             } else { | ||||||
|  |                 this.ui.redirect.attr('required', true); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this.ui.html.attr('required', val === 'html'); | ||||||
|  |  | ||||||
|  |             if (!this.ui.form[0].checkValidity()) { | ||||||
|  |                 $('<input type="submit">').hide().appendTo(this.ui.form).click().remove(); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             let view = this; | ||||||
|  |             let data = this.ui.form.serializeJSON(); | ||||||
|  |             data.id  = this.model.get('id'); | ||||||
|  |  | ||||||
|  |             this.ui.buttons.prop('disabled', true).addClass('btn-disabled'); | ||||||
|  |             App.Api.Settings.update(data) | ||||||
|  |                 .then(result => { | ||||||
|  |                     view.model.set(result); | ||||||
|  |                     App.UI.closeModal(); | ||||||
|  |                 }) | ||||||
|  |                 .catch(err => { | ||||||
|  |                     alert(err.message); | ||||||
|  |                     this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         this.ui.value.trigger('change'); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										21
									
								
								src/frontend/js/app/settings/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/frontend/js/app/settings/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <td> | ||||||
|  |     <div><%- name %></div> | ||||||
|  |     <div class="small text-muted"> | ||||||
|  |         <%- description %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div> | ||||||
|  |         <% if (id === 'default-site') { %> | ||||||
|  |             <%- i18n('settings', 'default-site-' + value) %> | ||||||
|  |         <% } %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td class="text-right"> | ||||||
|  |     <div class="item-action dropdown"> | ||||||
|  |         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a> | ||||||
|  |         <div class="dropdown-menu dropdown-menu-right"> | ||||||
|  |             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
							
								
								
									
										25
									
								
								src/frontend/js/app/settings/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/frontend/js/app/settings/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const App      = require('../../main'); | ||||||
|  | const template = require('./item.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     tagName:  'tr', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         edit: 'a.edit' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.edit': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             App.Controller.showSettingForm(this.model); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(this.model, 'change', this.render); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										8
									
								
								src/frontend/js/app/settings/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/frontend/js/app/settings/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | <thead> | ||||||
|  |     <th><%- i18n('str', 'name') %></th> | ||||||
|  |     <th><%- i18n('str', 'value') %></th> | ||||||
|  |     <th> </th> | ||||||
|  | </thead> | ||||||
|  | <tbody> | ||||||
|  |     <!-- items --> | ||||||
|  | </tbody> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/settings/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/settings/list/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const ItemView = require('./item'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | const TableBody = Mn.CollectionView.extend({ | ||||||
|  |     tagName:   'tbody', | ||||||
|  |     childView: ItemView | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     tagName:   'table', | ||||||
|  |     className: 'table table-hover table-outline table-vcenter text-nowrap card-table', | ||||||
|  |     template:  template, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         body: { | ||||||
|  |             el:             'tbody', | ||||||
|  |             replaceElement: true | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         this.showChildView('body', new TableBody({ | ||||||
|  |             collection: this.collection | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										14
									
								
								src/frontend/js/app/settings/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/frontend/js/app/settings/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | <div class="card"> | ||||||
|  |     <div class="card-status bg-teal"></div> | ||||||
|  |     <div class="card-header"> | ||||||
|  |         <h3 class="card-title"><%- i18n('settings', 'title') %></h3> | ||||||
|  |     </div> | ||||||
|  |     <div class="card-body no-padding min-100"> | ||||||
|  |         <div class="dimmer active"> | ||||||
|  |             <div class="loader"></div> | ||||||
|  |             <div class="dimmer-content list-region"> | ||||||
|  |                 <!-- List Region --> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
							
								
								
									
										50
									
								
								src/frontend/js/app/settings/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/frontend/js/app/settings/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn           = require('backbone.marionette'); | ||||||
|  | const App          = require('../main'); | ||||||
|  | const SettingModel = require('../../models/setting'); | ||||||
|  | const ListView     = require('./list/main'); | ||||||
|  | const ErrorView    = require('../error/main'); | ||||||
|  | const template     = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     id:       'settings', | ||||||
|  |     template: template, | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         list_region: '.list-region', | ||||||
|  |         add:         '.add-item', | ||||||
|  |         dimmer:      '.dimmer' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         list_region: '@ui.list_region' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         App.Api.Settings.getAll() | ||||||
|  |             .then(response => { | ||||||
|  |                 if (!view.isDestroyed() && response && response.length) { | ||||||
|  |                     view.showChildView('list_region', new ListView({ | ||||||
|  |                         collection: new SettingModel.Collection(response) | ||||||
|  |                     })); | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(err => { | ||||||
|  |                 view.showChildView('list_region', new ErrorView({ | ||||||
|  |                     code:    err.code, | ||||||
|  |                     message: err.message, | ||||||
|  |                     retry:   function () { | ||||||
|  |                         App.Controller.showSettings(); | ||||||
|  |                     } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }); | ||||||
| @@ -42,6 +42,9 @@ | |||||||
|                 <li class="nav-item"> |                 <li class="nav-item"> | ||||||
|                     <a href="/audit-log" class="nav-link"><i class="fe fe-book-open"></i> <%- i18n('audit-log', 'title') %></a> |                     <a href="/audit-log" class="nav-link"><i class="fe fe-book-open"></i> <%- i18n('audit-log', 'title') %></a> | ||||||
|                 </li> |                 </li> | ||||||
|  |                 <li class="nav-item"> | ||||||
|  |                     <a href="/settings" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('settings', 'title') %></a> | ||||||
|  |                 </li> | ||||||
|                 <% } %> |                 <% } %> | ||||||
|             </ul> |             </ul> | ||||||
|         </div> |         </div> | ||||||
|   | |||||||
| @@ -31,7 +31,8 @@ | |||||||
|       "online": "Online", |       "online": "Online", | ||||||
|       "offline": "Offline", |       "offline": "Offline", | ||||||
|       "unknown": "Unknown", |       "unknown": "Unknown", | ||||||
|       "expires": "Expires" |       "expires": "Expires", | ||||||
|  |       "value": "Value" | ||||||
|     }, |     }, | ||||||
|     "login": { |     "login": { | ||||||
|       "title": "Login to your account" |       "title": "Login to your account" | ||||||
| @@ -222,6 +223,14 @@ | |||||||
|       "meta-title": "Details for Event", |       "meta-title": "Details for Event", | ||||||
|       "view-meta": "View Details", |       "view-meta": "View Details", | ||||||
|       "date": "Date" |       "date": "Date" | ||||||
|  |     }, | ||||||
|  |     "settings": { | ||||||
|  |       "title": "Settings", | ||||||
|  |       "default-site": "Default Site", | ||||||
|  |       "default-site-congratulations": "Congratulations Page", | ||||||
|  |       "default-site-404": "404 Page", | ||||||
|  |       "default-site-html": "Custom Page", | ||||||
|  |       "default-site-redirect": "Redirect" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								src/frontend/js/models/setting.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/frontend/js/models/setting.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _        = require('underscore'); | ||||||
|  | const Backbone = require('backbone'); | ||||||
|  |  | ||||||
|  | const model = Backbone.Model.extend({ | ||||||
|  |     idAttribute: 'id', | ||||||
|  |  | ||||||
|  |     defaults: function () { | ||||||
|  |         return { | ||||||
|  |             id:          undefined, | ||||||
|  |             name:        '', | ||||||
|  |             description: '', | ||||||
|  |             value:       null, | ||||||
|  |             meta:        [] | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     Model:      model, | ||||||
|  |     Collection: Backbone.Collection.extend({ | ||||||
|  |         model: model | ||||||
|  |     }) | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user