mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 07:43:33 +00:00 
			
		
		
		
	Ongoing rewrite work
This commit is contained in:
		
							
								
								
									
										74
									
								
								src/backend/internal/dead-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/backend/internal/dead-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _             = require('lodash'); | ||||||
|  | const error         = require('../lib/error'); | ||||||
|  | const deadHostModel = require('../models/dead_host'); | ||||||
|  |  | ||||||
|  | function omissions () { | ||||||
|  |     return ['is_deleted']; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const internalDeadHost = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All Hosts | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @param   {Array}   [expand] | ||||||
|  |      * @param   {String}  [search_query] | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getAll: (access, expand, search_query) => { | ||||||
|  |         return access.can('dead_hosts:list') | ||||||
|  |             .then(access_data => { | ||||||
|  |                 let query = deadHostModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('is_deleted', 0) | ||||||
|  |                     .groupBy('id') | ||||||
|  |                     .omit(['is_deleted']) | ||||||
|  |                     .orderBy('domain_name', 'ASC'); | ||||||
|  |  | ||||||
|  |                 if (access_data.permission_visibility !== 'all') { | ||||||
|  |                     query.andWhere('owner_user_id', access.token.get('attrs').id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Query is used for searching | ||||||
|  |                 if (typeof search_query === 'string') { | ||||||
|  |                     query.where(function () { | ||||||
|  |                         this.where('domain_name', 'like', '%' + search_query + '%'); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (typeof expand !== 'undefined' && expand !== null) { | ||||||
|  |                     query.eager('[' + expand.join(', ') + ']'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return query; | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Report use | ||||||
|  |      * | ||||||
|  |      * @param   {Integer} user_id | ||||||
|  |      * @param   {String}  visibility | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getCount: (user_id, visibility) => { | ||||||
|  |         let query = deadHostModel | ||||||
|  |             .query() | ||||||
|  |             .count('id as count') | ||||||
|  |             .where('is_deleted', 0); | ||||||
|  |  | ||||||
|  |         if (visibility !== 'all') { | ||||||
|  |             query.andWhere('owner_user_id', user_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return query.first() | ||||||
|  |             .then(row => { | ||||||
|  |                 return parseInt(row.count, 10); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalDeadHost; | ||||||
							
								
								
									
										279
									
								
								src/backend/internal/proxy-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								src/backend/internal/proxy-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _              = require('lodash'); | ||||||
|  | const error          = require('../lib/error'); | ||||||
|  | const proxyHostModel = require('../models/proxy_host'); | ||||||
|  |  | ||||||
|  | function omissions () { | ||||||
|  |     return ['is_deleted']; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const internalProxyHost = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @param   {Object}  data | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     create: (access, data) => { | ||||||
|  |         let auth = data.auth || null; | ||||||
|  |         delete data.auth; | ||||||
|  |  | ||||||
|  |         data.avatar = data.avatar || ''; | ||||||
|  |         data.roles  = data.roles || []; | ||||||
|  |  | ||||||
|  |         if (typeof data.is_disabled !== 'undefined') { | ||||||
|  |             data.is_disabled = data.is_disabled ? 1 : 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return access.can('proxy_hosts:create', data) | ||||||
|  |             .then(() => { | ||||||
|  |                 data.avatar = gravatar.url(data.email, {default: 'mm'}); | ||||||
|  |  | ||||||
|  |                 return userModel | ||||||
|  |                     .query() | ||||||
|  |                     .omit(omissions()) | ||||||
|  |                     .insertAndFetch(data); | ||||||
|  |             }) | ||||||
|  |             .then(user => { | ||||||
|  |                 if (auth) { | ||||||
|  |                     return authModel | ||||||
|  |                         .query() | ||||||
|  |                         .insert({ | ||||||
|  |                             user_id: user.id, | ||||||
|  |                             type:    auth.type, | ||||||
|  |                             secret:  auth.secret, | ||||||
|  |                             meta:    {} | ||||||
|  |                         }) | ||||||
|  |                         .then(() => { | ||||||
|  |                             return user; | ||||||
|  |                         }); | ||||||
|  |                 } else { | ||||||
|  |                     return user; | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .then(user => { | ||||||
|  |                 // Create permissions row as well | ||||||
|  |                 let is_admin = data.roles.indexOf('admin') !== -1; | ||||||
|  |  | ||||||
|  |                 return userPermissionModel | ||||||
|  |                     .query() | ||||||
|  |                     .insert({ | ||||||
|  |                         user_id:           user.id, | ||||||
|  |                         visibility:        is_admin ? 'all' : 'user', | ||||||
|  |                         proxy_hosts:       'manage', | ||||||
|  |                         redirection_hosts: 'manage', | ||||||
|  |                         dead_hosts:        'manage', | ||||||
|  |                         streams:           'manage', | ||||||
|  |                         access_lists:      'manage' | ||||||
|  |                     }) | ||||||
|  |                     .then(() => { | ||||||
|  |                         return internalProxyHost.get(access, {id: user.id, expand: ['permissions']}); | ||||||
|  |                     }); | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param  {Access}  access | ||||||
|  |      * @param  {Object}  data | ||||||
|  |      * @param  {Integer} data.id | ||||||
|  |      * @param  {String}  [data.email] | ||||||
|  |      * @param  {String}  [data.name] | ||||||
|  |      * @return {Promise} | ||||||
|  |      */ | ||||||
|  |     update: (access, data) => { | ||||||
|  |         if (typeof data.is_disabled !== 'undefined') { | ||||||
|  |             data.is_disabled = data.is_disabled ? 1 : 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return access.can('proxy_hosts:update', data.id) | ||||||
|  |             .then(() => { | ||||||
|  |  | ||||||
|  |                 // Make sure that the user being updated doesn't change their email to another user that is already using it | ||||||
|  |                 // 1. get user we want to update | ||||||
|  |                 return internalProxyHost.get(access, {id: data.id}) | ||||||
|  |                     .then(user => { | ||||||
|  |  | ||||||
|  |                         // 2. if email is to be changed, find other users with that email | ||||||
|  |                         if (typeof data.email !== 'undefined') { | ||||||
|  |                             data.email = data.email.toLowerCase().trim(); | ||||||
|  |  | ||||||
|  |                             if (user.email !== data.email) { | ||||||
|  |                                 return internalProxyHost.isEmailAvailable(data.email, data.id) | ||||||
|  |                                     .then(available => { | ||||||
|  |                                         if (!available) { | ||||||
|  |                                             throw new error.ValidationError('Email address already in use - ' + data.email); | ||||||
|  |                                         } | ||||||
|  |  | ||||||
|  |                                         return user; | ||||||
|  |                                     }); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         // No change to email: | ||||||
|  |                         return user; | ||||||
|  |                     }); | ||||||
|  |             }) | ||||||
|  |             .then(user => { | ||||||
|  |                 if (user.id !== data.id) { | ||||||
|  |                     // Sanity check that something crazy hasn't happened | ||||||
|  |                     throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 data.avatar = gravatar.url(data.email || user.email, {default: 'mm'}); | ||||||
|  |  | ||||||
|  |                 return userModel | ||||||
|  |                     .query() | ||||||
|  |                     .omit(omissions()) | ||||||
|  |                     .patchAndFetchById(user.id, data) | ||||||
|  |                     .then(saved_user => { | ||||||
|  |                         return _.omit(saved_user, omissions()); | ||||||
|  |                     }); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 return internalProxyHost.get(access, {id: data.id}); | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param  {Access}   access | ||||||
|  |      * @param  {Object}   [data] | ||||||
|  |      * @param  {Integer}  [data.id]          Defaults to the token user | ||||||
|  |      * @param  {Array}    [data.expand] | ||||||
|  |      * @param  {Array}    [data.omit] | ||||||
|  |      * @return {Promise} | ||||||
|  |      */ | ||||||
|  |     get: (access, data) => { | ||||||
|  |         if (typeof data === 'undefined') { | ||||||
|  |             data = {}; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (typeof data.id === 'undefined' || !data.id) { | ||||||
|  |             data.id = access.token.get('attrs').id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return access.can('proxy_hosts:get', data.id) | ||||||
|  |             .then(() => { | ||||||
|  |                 let query = userModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('is_deleted', 0) | ||||||
|  |                     .andWhere('id', data.id) | ||||||
|  |                     .allowEager('[permissions]') | ||||||
|  |                     .first(); | ||||||
|  |  | ||||||
|  |                 // Custom omissions | ||||||
|  |                 if (typeof data.omit !== 'undefined' && data.omit !== null) { | ||||||
|  |                     query.omit(data.omit); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (typeof data.expand !== 'undefined' && data.expand !== null) { | ||||||
|  |                     query.eager('[' + data.expand.join(', ') + ']'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return query; | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 if (row) { | ||||||
|  |                     return _.omit(row, omissions()); | ||||||
|  |                 } else { | ||||||
|  |                     throw new error.ItemNotFoundError(data.id); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param {Access}  access | ||||||
|  |      * @param {Object}  data | ||||||
|  |      * @param {Integer} data.id | ||||||
|  |      * @param {String}  [data.reason] | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     delete: (access, data) => { | ||||||
|  |         return access.can('proxy_hosts:delete', data.id) | ||||||
|  |             .then(() => { | ||||||
|  |                 return internalProxyHost.get(access, {id: data.id}); | ||||||
|  |             }) | ||||||
|  |             .then(user => { | ||||||
|  |                 if (!user) { | ||||||
|  |                     throw new error.ItemNotFoundError(data.id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Make sure user can't delete themselves | ||||||
|  |                 if (user.id === access.token.get('attrs').id) { | ||||||
|  |                     throw new error.PermissionError('You cannot delete yourself.'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return userModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('id', user.id) | ||||||
|  |                     .patch({ | ||||||
|  |                         is_deleted: 1 | ||||||
|  |                     }); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All Hosts | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @param   {Array}   [expand] | ||||||
|  |      * @param   {String}  [search_query] | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getAll: (access, expand, search_query) => { | ||||||
|  |         return access.can('proxy_hosts:list') | ||||||
|  |             .then(access_data => { | ||||||
|  |                 let query = proxyHostModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('is_deleted', 0) | ||||||
|  |                     .groupBy('id') | ||||||
|  |                     .omit(['is_deleted']) | ||||||
|  |                     .orderBy('domain_name', 'ASC'); | ||||||
|  |  | ||||||
|  |                 if (access_data.permission_visibility !== 'all') { | ||||||
|  |                     query.andWhere('owner_user_id', access.token.get('attrs').id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Query is used for searching | ||||||
|  |                 if (typeof search_query === 'string') { | ||||||
|  |                     query.where(function () { | ||||||
|  |                         this.where('domain_name', 'like', '%' + search_query + '%'); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (typeof expand !== 'undefined' && expand !== null) { | ||||||
|  |                     query.eager('[' + expand.join(', ') + ']'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return query; | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Report use | ||||||
|  |      * | ||||||
|  |      * @param   {Integer} user_id | ||||||
|  |      * @param   {String}  visibility | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getCount: (user_id, visibility) => { | ||||||
|  |         let query = proxyHostModel | ||||||
|  |             .query() | ||||||
|  |             .count('id as count') | ||||||
|  |             .where('is_deleted', 0); | ||||||
|  |  | ||||||
|  |         if (visibility !== 'all') { | ||||||
|  |             query.andWhere('owner_user_id', user_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return query.first() | ||||||
|  |             .then(row => { | ||||||
|  |                 return parseInt(row.count, 10); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalProxyHost; | ||||||
							
								
								
									
										74
									
								
								src/backend/internal/redirection-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/backend/internal/redirection-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _                    = require('lodash'); | ||||||
|  | const error                = require('../lib/error'); | ||||||
|  | const redirectionHostModel = require('../models/redirection_host'); | ||||||
|  |  | ||||||
|  | function omissions () { | ||||||
|  |     return ['is_deleted']; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const internalProxyHost = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All Hosts | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @param   {Array}   [expand] | ||||||
|  |      * @param   {String}  [search_query] | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getAll: (access, expand, search_query) => { | ||||||
|  |         return access.can('redirection_hosts:list') | ||||||
|  |             .then(access_data => { | ||||||
|  |                 let query = redirectionHostModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('is_deleted', 0) | ||||||
|  |                     .groupBy('id') | ||||||
|  |                     .omit(['is_deleted']) | ||||||
|  |                     .orderBy('domain_name', 'ASC'); | ||||||
|  |  | ||||||
|  |                 if (access_data.permission_visibility !== 'all') { | ||||||
|  |                     query.andWhere('owner_user_id', access.token.get('attrs').id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Query is used for searching | ||||||
|  |                 if (typeof search_query === 'string') { | ||||||
|  |                     query.where(function () { | ||||||
|  |                         this.where('domain_name', 'like', '%' + search_query + '%'); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (typeof expand !== 'undefined' && expand !== null) { | ||||||
|  |                     query.eager('[' + expand.join(', ') + ']'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return query; | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Report use | ||||||
|  |      * | ||||||
|  |      * @param   {Integer} user_id | ||||||
|  |      * @param   {String}  visibility | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getCount: (user_id, visibility) => { | ||||||
|  |         let query = redirectionHostModel | ||||||
|  |             .query() | ||||||
|  |             .count('id as count') | ||||||
|  |             .where('is_deleted', 0); | ||||||
|  |  | ||||||
|  |         if (visibility !== 'all') { | ||||||
|  |             query.andWhere('owner_user_id', user_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return query.first() | ||||||
|  |             .then(row => { | ||||||
|  |                 return parseInt(row.count, 10); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalProxyHost; | ||||||
| @@ -2,6 +2,10 @@ | |||||||
|  |  | ||||||
| const _                       = require('lodash'); | const _                       = require('lodash'); | ||||||
| const error                   = require('../lib/error'); | const error                   = require('../lib/error'); | ||||||
|  | const internalProxyHost       = require('./proxy-host'); | ||||||
|  | const internalRedirectionHost = require('./redirection-host'); | ||||||
|  | const internalDeadHost        = require('./dead-host'); | ||||||
|  | const internalStream          = require('./stream'); | ||||||
|  |  | ||||||
| const internalReport = { | const internalReport = { | ||||||
|  |  | ||||||
| @@ -11,14 +15,27 @@ const internalReport = { | |||||||
|      */ |      */ | ||||||
|     getHostsReport: access => { |     getHostsReport: access => { | ||||||
|         return access.can('reports:hosts', 1) |         return access.can('reports:hosts', 1) | ||||||
|             .then(() => { |             .then(access_data => { | ||||||
|  |                 let user_id = access.token.get('attrs').id; | ||||||
|  |  | ||||||
|  |                 let promises = [ | ||||||
|  |                     internalProxyHost.getCount(user_id, access_data.visibility), | ||||||
|  |                     internalRedirectionHost.getCount(user_id, access_data.visibility), | ||||||
|  |                     internalStream.getCount(user_id, access_data.visibility), | ||||||
|  |                     internalDeadHost.getCount(user_id, access_data.visibility) | ||||||
|  |                 ]; | ||||||
|  |  | ||||||
|  |                 return Promise.all(promises); | ||||||
|  |             }) | ||||||
|  |             .then(counts => { | ||||||
|                 return { |                 return { | ||||||
|                     proxy:       12, |                     proxy:       counts.shift(), | ||||||
|                     redirection: 2, |                     redirection: counts.shift(), | ||||||
|                     stream:      1, |                     stream:      counts.shift(), | ||||||
|                     '404':       0 |                     dead:        counts.shift() | ||||||
|                 }; |                 }; | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										74
									
								
								src/backend/internal/stream.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/backend/internal/stream.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _           = require('lodash'); | ||||||
|  | const error       = require('../lib/error'); | ||||||
|  | const streamModel = require('../models/stream'); | ||||||
|  |  | ||||||
|  | function omissions () { | ||||||
|  |     return ['is_deleted']; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const internalStream = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All Hosts | ||||||
|  |      * | ||||||
|  |      * @param   {Access}  access | ||||||
|  |      * @param   {Array}   [expand] | ||||||
|  |      * @param   {String}  [search_query] | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getAll: (access, expand, search_query) => { | ||||||
|  |         return access.can('streams:list') | ||||||
|  |             .then(access_data => { | ||||||
|  |                 let query = streamModel | ||||||
|  |                     .query() | ||||||
|  |                     .where('is_deleted', 0) | ||||||
|  |                     .groupBy('id') | ||||||
|  |                     .omit(['is_deleted']) | ||||||
|  |                     .orderBy('incoming_port', 'ASC'); | ||||||
|  |  | ||||||
|  |                 if (access_data.permission_visibility !== 'all') { | ||||||
|  |                     query.andWhere('owner_user_id', access.token.get('attrs').id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Query is used for searching | ||||||
|  |                 if (typeof search_query === 'string') { | ||||||
|  |                     query.where(function () { | ||||||
|  |                         this.where('incoming_port', 'like', '%' + search_query + '%'); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (typeof expand !== 'undefined' && expand !== null) { | ||||||
|  |                     query.eager('[' + expand.join(', ') + ']'); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return query; | ||||||
|  |             }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Report use | ||||||
|  |      * | ||||||
|  |      * @param   {Integer} user_id | ||||||
|  |      * @param   {String}  visibility | ||||||
|  |      * @returns {Promise} | ||||||
|  |      */ | ||||||
|  |     getCount: (user_id, visibility) => { | ||||||
|  |         let query = streamModel | ||||||
|  |             .query() | ||||||
|  |             .count('id as count') | ||||||
|  |             .where('is_deleted', 0); | ||||||
|  |  | ||||||
|  |         if (visibility !== 'all') { | ||||||
|  |             query.andWhere('owner_user_id', user_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return query.first() | ||||||
|  |             .then(row => { | ||||||
|  |                 return parseInt(row.count, 10); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalStream; | ||||||
| @@ -1,11 +1,24 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Some Notes: This is a friggin complicated piece of code. | ||||||
|  |  * | ||||||
|  |  * "scope" in this file means "where did this token come from and what is using it", so 99% of the time | ||||||
|  |  * the "scope" is going to be "user" because it would be a user token. This is not to be confused with | ||||||
|  |  * the "role" which could be "user" or "admin". The scope in fact, could be "worker" or anything else. | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
| const _              = require('lodash'); | const _              = require('lodash'); | ||||||
|  | const logger         = require('../logger').access; | ||||||
| const validator      = require('ajv'); | const validator      = require('ajv'); | ||||||
| const error          = require('./error'); | const error          = require('./error'); | ||||||
| const userModel      = require('../models/user'); | const userModel      = require('../models/user'); | ||||||
|  | const proxyHostModel = require('../models/proxy_host'); | ||||||
| const TokenModel     = require('../models/token'); | const TokenModel     = require('../models/token'); | ||||||
| const roleSchema     = require('./access/roles.json'); | const roleSchema     = require('./access/roles.json'); | ||||||
|  | const permsSchema    = require('./access/permissions.json'); | ||||||
|  |  | ||||||
| module.exports = function (token_string) { | module.exports = function (token_string) { | ||||||
|     let Token                 = new TokenModel(); |     let Token                 = new TokenModel(); | ||||||
| @@ -14,6 +27,7 @@ module.exports = function (token_string) { | |||||||
|     let object_cache          = {}; |     let object_cache          = {}; | ||||||
|     let allow_internal_access = false; |     let allow_internal_access = false; | ||||||
|     let user_roles            = []; |     let user_roles            = []; | ||||||
|  |     let permissions           = {}; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Loads the Token object from the token string |      * Loads the Token object from the token string | ||||||
| @@ -28,7 +42,7 @@ module.exports = function (token_string) { | |||||||
|                 reject(new error.PermissionError('Permission Denied')); |                 reject(new error.PermissionError('Permission Denied')); | ||||||
|             } else { |             } else { | ||||||
|                 resolve(Token.load(token_string) |                 resolve(Token.load(token_string) | ||||||
|                     .then((data) => { |                     .then(data => { | ||||||
|                         token_data = data; |                         token_data = data; | ||||||
|  |  | ||||||
|                         // At this point we need to load the user from the DB and make sure they: |                         // At this point we need to load the user from the DB and make sure they: | ||||||
| @@ -43,8 +57,10 @@ module.exports = function (token_string) { | |||||||
|                                 .where('id', token_data.attrs.id) |                                 .where('id', token_data.attrs.id) | ||||||
|                                 .andWhere('is_deleted', 0) |                                 .andWhere('is_deleted', 0) | ||||||
|                                 .andWhere('is_disabled', 0) |                                 .andWhere('is_disabled', 0) | ||||||
|                                 .first('id') |                                 .allowEager('[permissions]') | ||||||
|                                 .then((user) => { |                                 .eager('[permissions]') | ||||||
|  |                                 .first() | ||||||
|  |                                 .then(user => { | ||||||
|                                     if (user) { |                                     if (user) { | ||||||
|                                         // make sure user has all scopes of the token |                                         // make sure user has all scopes of the token | ||||||
|                                         // The `user` role is not added against the user row, so we have to just add it here to get past this check. |                                         // The `user` role is not added against the user row, so we have to just add it here to get past this check. | ||||||
| @@ -62,7 +78,9 @@ module.exports = function (token_string) { | |||||||
|                                         } else { |                                         } else { | ||||||
|                                             initialised = true; |                                             initialised = true; | ||||||
|                                             user_roles  = user.roles; |                                             user_roles  = user.roles; | ||||||
|  |                                             permissions = user.permissions; | ||||||
|                                         } |                                         } | ||||||
|  |  | ||||||
|                                     } else { |                                     } else { | ||||||
|                                         throw new error.AuthError('User cannot be loaded for Token'); |                                         throw new error.AuthError('User cannot be loaded for Token'); | ||||||
|                                     } |                                     } | ||||||
| @@ -99,6 +117,34 @@ module.exports = function (token_string) { | |||||||
|                                 resolve(token_user_id ? [token_user_id] : []); |                                 resolve(token_user_id ? [token_user_id] : []); | ||||||
|                                 break; |                                 break; | ||||||
|  |  | ||||||
|  |                             // Proxy Hosts | ||||||
|  |                             case 'proxy_hosts': | ||||||
|  |                                 let query = proxyHostModel | ||||||
|  |                                     .query() | ||||||
|  |                                     .select('id') | ||||||
|  |                                     .andWhere('is_deleted', 0); | ||||||
|  |  | ||||||
|  |                                 if (permissions.visibility === 'user') { | ||||||
|  |                                     query.andWhere('owner_user_id', token_user_id); | ||||||
|  |                                 } | ||||||
|  |  | ||||||
|  |                                 resolve(query | ||||||
|  |                                     .then(rows => { | ||||||
|  |                                         let result = []; | ||||||
|  |                                         _.forEach(rows, (rule_row) => { | ||||||
|  |                                             result.push(rule_row.id); | ||||||
|  |                                         }); | ||||||
|  |  | ||||||
|  |                                         // enum should not have less than 1 item | ||||||
|  |                                         if (!result.length) { | ||||||
|  |                                             result.push(0); | ||||||
|  |                                         } | ||||||
|  |  | ||||||
|  |                                         return result; | ||||||
|  |                                     }) | ||||||
|  |                                 ); | ||||||
|  |                                 break; | ||||||
|  |  | ||||||
|                             // DEFAULT: null |                             // DEFAULT: null | ||||||
|                             default: |                             default: | ||||||
|                                 resolve(null); |                                 resolve(null); | ||||||
| @@ -209,7 +255,13 @@ module.exports = function (token_string) { | |||||||
|                                     [permission]: { |                                     [permission]: { | ||||||
|                                         data:                         data, |                                         data:                         data, | ||||||
|                                         scope:                        Token.get('scope'), |                                         scope:                        Token.get('scope'), | ||||||
|                                         roles: user_roles |                                         roles:                        user_roles, | ||||||
|  |                                         permission_visibility:        permissions.visibility, | ||||||
|  |                                         permission_proxy_hosts:       permissions.proxy_hosts, | ||||||
|  |                                         permission_redirection_hosts: permissions.redirection_hosts, | ||||||
|  |                                         permission_dead_hosts:        permissions.dead_hosts, | ||||||
|  |                                         permission_streams:           permissions.streams, | ||||||
|  |                                         permission_access_lists:      permissions.access_lists | ||||||
|                                     } |                                     } | ||||||
|                                 }; |                                 }; | ||||||
|  |  | ||||||
| @@ -223,9 +275,9 @@ module.exports = function (token_string) { | |||||||
|  |  | ||||||
|                                 permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json'); |                                 permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json'); | ||||||
|  |  | ||||||
|                                 //console.log('objectSchema:', JSON.stringify(objectSchema, null, 2)); |                                 //logger.debug('objectSchema:', JSON.stringify(objectSchema, null, 2)); | ||||||
|                                 //console.log('permissionSchema:', JSON.stringify(permissionSchema, null, 2)); |                                 //logger.debug('permissionSchema:', JSON.stringify(permissionSchema, null, 2)); | ||||||
|                                 //console.log('data_schema:', JSON.stringify(data_schema, null, 2)); |                                 //logger.debug('data_schema:', JSON.stringify(data_schema, null, 2)); | ||||||
|  |  | ||||||
|                                 let ajv = validator({ |                                 let ajv = validator({ | ||||||
|                                     verbose:      true, |                                     verbose:      true, | ||||||
| @@ -236,17 +288,21 @@ module.exports = function (token_string) { | |||||||
|                                     coerceTypes:  true, |                                     coerceTypes:  true, | ||||||
|                                     schemas:      [ |                                     schemas:      [ | ||||||
|                                         roleSchema, |                                         roleSchema, | ||||||
|  |                                         permsSchema, | ||||||
|                                         objectSchema, |                                         objectSchema, | ||||||
|                                         permissionSchema |                                         permissionSchema | ||||||
|                                     ] |                                     ] | ||||||
|                                 }); |                                 }); | ||||||
|  |  | ||||||
|                                 return ajv.validate('permissions', data_schema); |                                 return ajv.validate('permissions', data_schema) | ||||||
|  |                                     .then(() => { | ||||||
|  |                                         return data_schema[permission]; | ||||||
|  |                                     }); | ||||||
|                             }); |                             }); | ||||||
|                     }) |                     }) | ||||||
|                     .catch(err => { |                     .catch(err => { | ||||||
|                         //console.log(err.message); |                         //logger.error(err.message); | ||||||
|                         //console.log(err.errors); |                         //logger.error(err.errors); | ||||||
|  |  | ||||||
|                         throw new error.PermissionError('Permission Denied', err); |                         throw new error.PermissionError('Permission Denied', err); | ||||||
|                     }); |                     }); | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/backend/lib/access/dead_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/backend/lib/access/dead_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "type": "object", | ||||||
|  |       "required": ["permission_dead_hosts", "roles"], | ||||||
|  |       "properties": { | ||||||
|  |         "permission_dead_hosts": { | ||||||
|  |           "$ref": "perms#/definitions/view" | ||||||
|  |         }, | ||||||
|  |         "roles": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string", | ||||||
|  |             "enum": ["user"] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								src/backend/lib/access/permissions.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/backend/lib/access/permissions.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "perms", | ||||||
|  |   "definitions": { | ||||||
|  |     "view": { | ||||||
|  |       "type": "string", | ||||||
|  |       "pattern": "^(view|manage)$" | ||||||
|  |     }, | ||||||
|  |     "manage": { | ||||||
|  |       "type": "string", | ||||||
|  |       "pattern": "^(manage)$" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								src/backend/lib/access/proxy_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/backend/lib/access/proxy_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "type": "object", | ||||||
|  |       "required": ["permission_proxy_hosts", "roles"], | ||||||
|  |       "properties": { | ||||||
|  |         "permission_proxy_hosts": { | ||||||
|  |           "$ref": "perms#/definitions/view" | ||||||
|  |         }, | ||||||
|  |         "roles": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string", | ||||||
|  |             "enum": ["user"] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/backend/lib/access/redirection_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/backend/lib/access/redirection_hosts-list.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "type": "object", | ||||||
|  |       "required": ["permission_redirection_hosts", "roles"], | ||||||
|  |       "properties": { | ||||||
|  |         "permission_redirection_hosts": { | ||||||
|  |           "$ref": "perms#/definitions/view" | ||||||
|  |         }, | ||||||
|  |         "roles": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string", | ||||||
|  |             "enum": ["user"] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/backend/lib/access/streams-list.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/backend/lib/access/streams-list.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/admin" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "type": "object", | ||||||
|  |       "required": ["permission_streams", "roles"], | ||||||
|  |       "properties": { | ||||||
|  |         "permission_streams": { | ||||||
|  |           "$ref": "perms#/definitions/view" | ||||||
|  |         }, | ||||||
|  |         "roles": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string", | ||||||
|  |             "enum": ["user"] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @@ -3,5 +3,6 @@ const {Signale} = require('signale'); | |||||||
| module.exports = { | module.exports = { | ||||||
|     global:  new Signale({scope: 'Global    '}), |     global:  new Signale({scope: 'Global    '}), | ||||||
|     migrate: new Signale({scope: 'Migrate   '}), |     migrate: new Signale({scope: 'Migrate   '}), | ||||||
|     express: new Signale({scope: 'Express   '}) |     express: new Signale({scope: 'Express   '}), | ||||||
|  |     access:  new Signale({scope: 'Access    '}) | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -77,7 +77,6 @@ exports.up = function (knex/*, Promise*/) { | |||||||
|                 table.integer('caching_enabled').notNull().unsigned().defaultTo(0); |                 table.integer('caching_enabled').notNull().unsigned().defaultTo(0); | ||||||
|                 table.integer('block_exploits').notNull().unsigned().defaultTo(0); |                 table.integer('block_exploits').notNull().unsigned().defaultTo(0); | ||||||
|                 table.json('meta').notNull(); |                 table.json('meta').notNull(); | ||||||
|                 table.unique(['domain_name', 'is_deleted']); |  | ||||||
|             }); |             }); | ||||||
|         }) |         }) | ||||||
|         .then(() => { |         .then(() => { | ||||||
| @@ -96,7 +95,6 @@ exports.up = function (knex/*, Promise*/) { | |||||||
|                 table.string('ssl_provider').notNull().defaultTo(''); |                 table.string('ssl_provider').notNull().defaultTo(''); | ||||||
|                 table.integer('block_exploits').notNull().unsigned().defaultTo(0); |                 table.integer('block_exploits').notNull().unsigned().defaultTo(0); | ||||||
|                 table.json('meta').notNull(); |                 table.json('meta').notNull(); | ||||||
|                 table.unique(['domain_name', 'is_deleted']); |  | ||||||
|             }); |             }); | ||||||
|         }) |         }) | ||||||
|         .then(() => { |         .then(() => { | ||||||
| @@ -112,7 +110,6 @@ exports.up = function (knex/*, Promise*/) { | |||||||
|                     table.integer('ssl_enabled').notNull().unsigned().defaultTo(0); |                     table.integer('ssl_enabled').notNull().unsigned().defaultTo(0); | ||||||
|                     table.string('ssl_provider').notNull().defaultTo(''); |                     table.string('ssl_provider').notNull().defaultTo(''); | ||||||
|                     table.json('meta').notNull(); |                     table.json('meta').notNull(); | ||||||
|                     table.unique(['domain_name', 'is_deleted']); |  | ||||||
|                 }); |                 }); | ||||||
|         }) |         }) | ||||||
|         .then(() => { |         .then(() => { | ||||||
| @@ -130,7 +127,6 @@ exports.up = function (knex/*, Promise*/) { | |||||||
|                 table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0); |                 table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0); | ||||||
|                 table.integer('udp_forwarding').notNull().unsigned().defaultTo(0); |                 table.integer('udp_forwarding').notNull().unsigned().defaultTo(0); | ||||||
|                 table.json('meta').notNull(); |                 table.json('meta').notNull(); | ||||||
|                 table.unique(['incoming_port', 'is_deleted']); |  | ||||||
|             }); |             }); | ||||||
|         }) |         }) | ||||||
|         .then(() => { |         .then(() => { | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								src/backend/models/dead_host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/backend/models/dead_host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | // Objection Docs: | ||||||
|  | // http://vincit.github.io/objection.js/ | ||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const db    = require('../db'); | ||||||
|  | const Model = require('objection').Model; | ||||||
|  | const User  = require('./user'); | ||||||
|  |  | ||||||
|  | Model.knex(db); | ||||||
|  |  | ||||||
|  | class DeadHost extends Model { | ||||||
|  |     $beforeInsert () { | ||||||
|  |         this.created_on  = Model.raw('NOW()'); | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $beforeUpdate () { | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get name () { | ||||||
|  |         return 'DeadHost'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get tableName () { | ||||||
|  |         return 'dead_host'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get relationMappings () { | ||||||
|  |         return { | ||||||
|  |             owner: { | ||||||
|  |                 relation:   Model.HasOneRelation, | ||||||
|  |                 modelClass: User, | ||||||
|  |                 join:       { | ||||||
|  |                     from: 'dead_host.owner_user_id', | ||||||
|  |                     to:   'user.id' | ||||||
|  |                 }, | ||||||
|  |                 modify:     function (qb) { | ||||||
|  |                     qb.where('user.is_deleted', 0); | ||||||
|  |                     qb.omit(['created_on', 'modified_on', 'is_deleted', 'email', 'roles']); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = DeadHost; | ||||||
							
								
								
									
										48
									
								
								src/backend/models/proxy_host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/backend/models/proxy_host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | // Objection Docs: | ||||||
|  | // http://vincit.github.io/objection.js/ | ||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const db    = require('../db'); | ||||||
|  | const Model = require('objection').Model; | ||||||
|  | const User  = require('./user'); | ||||||
|  |  | ||||||
|  | Model.knex(db); | ||||||
|  |  | ||||||
|  | class ProxyHost extends Model { | ||||||
|  |     $beforeInsert () { | ||||||
|  |         this.created_on  = Model.raw('NOW()'); | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $beforeUpdate () { | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get name () { | ||||||
|  |         return 'ProxyHost'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get tableName () { | ||||||
|  |         return 'proxy_host'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get relationMappings () { | ||||||
|  |         return { | ||||||
|  |             owner: { | ||||||
|  |                 relation:   Model.HasOneRelation, | ||||||
|  |                 modelClass: User, | ||||||
|  |                 join:       { | ||||||
|  |                     from: 'proxy_host.owner_user_id', | ||||||
|  |                     to:   'user.id' | ||||||
|  |                 }, | ||||||
|  |                 modify:     function (qb) { | ||||||
|  |                     qb.where('user.is_deleted', 0); | ||||||
|  |                     qb.omit(['created_on', 'modified_on', 'is_deleted', 'email', 'roles']); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = ProxyHost; | ||||||
							
								
								
									
										48
									
								
								src/backend/models/redirection_host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/backend/models/redirection_host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | // Objection Docs: | ||||||
|  | // http://vincit.github.io/objection.js/ | ||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const db    = require('../db'); | ||||||
|  | const Model = require('objection').Model; | ||||||
|  | const User  = require('./user'); | ||||||
|  |  | ||||||
|  | Model.knex(db); | ||||||
|  |  | ||||||
|  | class RedirectionHost extends Model { | ||||||
|  |     $beforeInsert () { | ||||||
|  |         this.created_on  = Model.raw('NOW()'); | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $beforeUpdate () { | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get name () { | ||||||
|  |         return 'RedirectionHost'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get tableName () { | ||||||
|  |         return 'redirection_host'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get relationMappings () { | ||||||
|  |         return { | ||||||
|  |             owner: { | ||||||
|  |                 relation:   Model.HasOneRelation, | ||||||
|  |                 modelClass: User, | ||||||
|  |                 join:       { | ||||||
|  |                     from: 'redirection_host.owner_user_id', | ||||||
|  |                     to:   'user.id' | ||||||
|  |                 }, | ||||||
|  |                 modify:     function (qb) { | ||||||
|  |                     qb.where('user.is_deleted', 0); | ||||||
|  |                     qb.omit(['created_on', 'modified_on', 'is_deleted', 'email', 'roles']); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = RedirectionHost; | ||||||
							
								
								
									
										48
									
								
								src/backend/models/stream.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/backend/models/stream.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | // Objection Docs: | ||||||
|  | // http://vincit.github.io/objection.js/ | ||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const db    = require('../db'); | ||||||
|  | const Model = require('objection').Model; | ||||||
|  | const User  = require('./user'); | ||||||
|  |  | ||||||
|  | Model.knex(db); | ||||||
|  |  | ||||||
|  | class Stream extends Model { | ||||||
|  |     $beforeInsert () { | ||||||
|  |         this.created_on  = Model.raw('NOW()'); | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $beforeUpdate () { | ||||||
|  |         this.modified_on = Model.raw('NOW()'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get name () { | ||||||
|  |         return 'Stream'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get tableName () { | ||||||
|  |         return 'stream'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get relationMappings () { | ||||||
|  |         return { | ||||||
|  |             owner: { | ||||||
|  |                 relation:   Model.HasOneRelation, | ||||||
|  |                 modelClass: User, | ||||||
|  |                 join:       { | ||||||
|  |                     from: 'stream.owner_user_id', | ||||||
|  |                     to:   'user.id' | ||||||
|  |                 }, | ||||||
|  |                 modify:     function (qb) { | ||||||
|  |                     qb.where('user.is_deleted', 0); | ||||||
|  |                     qb.omit(['created_on', 'modified_on', 'is_deleted', 'email', 'roles']); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = Stream; | ||||||
| @@ -30,6 +30,10 @@ router.get('/', (req, res/*, next*/) => { | |||||||
| router.use('/tokens', require('./tokens')); | router.use('/tokens', require('./tokens')); | ||||||
| router.use('/users', require('./users')); | router.use('/users', require('./users')); | ||||||
| router.use('/reports', require('./reports')); | router.use('/reports', require('./reports')); | ||||||
|  | router.use('/nginx/proxy-hosts', require('./nginx/proxy_hosts')); | ||||||
|  | router.use('/nginx/redirection-hosts', require('./nginx/redirection_hosts')); | ||||||
|  | router.use('/nginx/dead-hosts', require('./nginx/dead_hosts')); | ||||||
|  | router.use('/nginx/streams', require('./nginx/streams')); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * API 404 for all other routes |  * API 404 for all other routes | ||||||
|   | |||||||
							
								
								
									
										150
									
								
								src/backend/routes/api/nginx/dead_hosts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/backend/routes/api/nginx/dead_hosts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const express          = require('express'); | ||||||
|  | const validator        = require('../../../lib/validator'); | ||||||
|  | const jwtdecode        = require('../../../lib/express/jwt-decode'); | ||||||
|  | const internalDeadHost = require('../../../internal/dead-host'); | ||||||
|  | const apiValidator     = require('../../../lib/validator/api'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * /api/nginx/dead-hosts | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/dead-hosts | ||||||
|  |      * | ||||||
|  |      * Retrieve all dead-hosts | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 expand: { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 }, | ||||||
|  |                 query:  { | ||||||
|  |                     $ref: 'definitions#/definitions/query' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null), | ||||||
|  |             query:  (typeof req.query.query === 'string' ? req.query.query : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalDeadHost.getAll(res.locals.access, data.expand, data.query); | ||||||
|  |             }) | ||||||
|  |             .then(rows => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(rows); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * POST /api/nginx/dead-hosts | ||||||
|  |      * | ||||||
|  |      * Create a new dead-host | ||||||
|  |      */ | ||||||
|  |     .post((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/dead-hosts#/links/1/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 return internalDeadHost.create(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(201) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Specific dead-host | ||||||
|  |  * | ||||||
|  |  * /api/nginx/dead-hosts/123 | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/:host_id') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/dead-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Retrieve a specific dead-host | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             required:             ['host_id'], | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 host_id: { | ||||||
|  |                     $ref: 'definitions#/definitions/id' | ||||||
|  |                 }, | ||||||
|  |                 expand:  { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             host_id: req.params.host_id, | ||||||
|  |             expand:  (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalDeadHost.get(res.locals.access, { | ||||||
|  |                     id:     data.host_id, | ||||||
|  |                     expand: data.expand | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(row); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PUT /api/nginx/dead-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing dead-host | ||||||
|  |      */ | ||||||
|  |     .put((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/dead-hosts#/links/2/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 payload.id = req.params.host_id; | ||||||
|  |                 return internalDeadHost.update(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DELETE /api/nginx/dead-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing dead-host | ||||||
|  |      */ | ||||||
|  |     .delete((req, res, next) => { | ||||||
|  |         internalDeadHost.delete(res.locals.access, {id: req.params.host_id}) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
							
								
								
									
										150
									
								
								src/backend/routes/api/nginx/proxy_hosts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/backend/routes/api/nginx/proxy_hosts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const express           = require('express'); | ||||||
|  | const validator         = require('../../../lib/validator'); | ||||||
|  | const jwtdecode         = require('../../../lib/express/jwt-decode'); | ||||||
|  | const internalProxyHost = require('../../../internal/proxy-host'); | ||||||
|  | const apiValidator      = require('../../../lib/validator/api'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * /api/nginx/proxy-hosts | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/proxy-hosts | ||||||
|  |      * | ||||||
|  |      * Retrieve all proxy-hosts | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 expand: { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 }, | ||||||
|  |                 query:  { | ||||||
|  |                     $ref: 'definitions#/definitions/query' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null), | ||||||
|  |             query:  (typeof req.query.query === 'string' ? req.query.query : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalProxyHost.getAll(res.locals.access, data.expand, data.query); | ||||||
|  |             }) | ||||||
|  |             .then(rows => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(rows); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * POST /api/nginx/proxy-hosts | ||||||
|  |      * | ||||||
|  |      * Create a new proxy-host | ||||||
|  |      */ | ||||||
|  |     .post((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/proxy-hosts#/links/1/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 return internalProxyHost.create(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(201) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Specific proxy-host | ||||||
|  |  * | ||||||
|  |  * /api/nginx/proxy-hosts/123 | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/:host_id') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/proxy-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Retrieve a specific proxy-host | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             required:             ['host_id'], | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 host_id: { | ||||||
|  |                     $ref: 'definitions#/definitions/id' | ||||||
|  |                 }, | ||||||
|  |                 expand:  { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             host_id: req.params.host_id, | ||||||
|  |             expand:  (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalProxyHost.get(res.locals.access, { | ||||||
|  |                     id:     data.host_id, | ||||||
|  |                     expand: data.expand | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(row); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PUT /api/nginx/proxy-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing proxy-host | ||||||
|  |      */ | ||||||
|  |     .put((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/proxy-hosts#/links/2/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 payload.id = req.params.host_id; | ||||||
|  |                 return internalProxyHost.update(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DELETE /api/nginx/proxy-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing proxy-host | ||||||
|  |      */ | ||||||
|  |     .delete((req, res, next) => { | ||||||
|  |         internalProxyHost.delete(res.locals.access, {id: req.params.host_id}) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
							
								
								
									
										150
									
								
								src/backend/routes/api/nginx/redirection_hosts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/backend/routes/api/nginx/redirection_hosts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const express                 = require('express'); | ||||||
|  | const validator               = require('../../../lib/validator'); | ||||||
|  | const jwtdecode               = require('../../../lib/express/jwt-decode'); | ||||||
|  | const internalRedirectionHost = require('../../../internal/redirection-host'); | ||||||
|  | const apiValidator            = require('../../../lib/validator/api'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * /api/nginx/redirection-hosts | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/redirection-hosts | ||||||
|  |      * | ||||||
|  |      * Retrieve all redirection-hosts | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 expand: { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 }, | ||||||
|  |                 query:  { | ||||||
|  |                     $ref: 'definitions#/definitions/query' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null), | ||||||
|  |             query:  (typeof req.query.query === 'string' ? req.query.query : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalRedirectionHost.getAll(res.locals.access, data.expand, data.query); | ||||||
|  |             }) | ||||||
|  |             .then(rows => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(rows); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * POST /api/nginx/redirection-hosts | ||||||
|  |      * | ||||||
|  |      * Create a new redirection-host | ||||||
|  |      */ | ||||||
|  |     .post((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/redirection-hosts#/links/1/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 return internalRedirectionHost.create(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(201) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Specific redirection-host | ||||||
|  |  * | ||||||
|  |  * /api/nginx/redirection-hosts/123 | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/:host_id') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/redirection-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Retrieve a specific redirection-host | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             required:             ['host_id'], | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 host_id: { | ||||||
|  |                     $ref: 'definitions#/definitions/id' | ||||||
|  |                 }, | ||||||
|  |                 expand:  { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             host_id: req.params.host_id, | ||||||
|  |             expand:  (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalRedirectionHost.get(res.locals.access, { | ||||||
|  |                     id:     data.host_id, | ||||||
|  |                     expand: data.expand | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(row); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PUT /api/nginx/redirection-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing redirection-host | ||||||
|  |      */ | ||||||
|  |     .put((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/redirection-hosts#/links/2/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 payload.id = req.params.host_id; | ||||||
|  |                 return internalRedirectionHost.update(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DELETE /api/nginx/redirection-hosts/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing redirection-host | ||||||
|  |      */ | ||||||
|  |     .delete((req, res, next) => { | ||||||
|  |         internalRedirectionHost.delete(res.locals.access, {id: req.params.host_id}) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
							
								
								
									
										150
									
								
								src/backend/routes/api/nginx/streams.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/backend/routes/api/nginx/streams.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const express        = require('express'); | ||||||
|  | const validator      = require('../../../lib/validator'); | ||||||
|  | const jwtdecode      = require('../../../lib/express/jwt-decode'); | ||||||
|  | const internalStream = require('../../../internal/stream'); | ||||||
|  | const apiValidator   = require('../../../lib/validator/api'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * /api/nginx/streams | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/streams | ||||||
|  |      * | ||||||
|  |      * Retrieve all streams | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 expand: { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 }, | ||||||
|  |                 query:  { | ||||||
|  |                     $ref: 'definitions#/definitions/query' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null), | ||||||
|  |             query:  (typeof req.query.query === 'string' ? req.query.query : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalStream.getAll(res.locals.access, data.expand, data.query); | ||||||
|  |             }) | ||||||
|  |             .then(rows => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(rows); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * POST /api/nginx/streams | ||||||
|  |      * | ||||||
|  |      * Create a new stream | ||||||
|  |      */ | ||||||
|  |     .post((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/streams#/links/1/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 return internalStream.create(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(201) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Specific stream | ||||||
|  |  * | ||||||
|  |  * /api/nginx/streams/123 | ||||||
|  |  */ | ||||||
|  | router | ||||||
|  |     .route('/:stream_id') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |     .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /api/nginx/streams/123 | ||||||
|  |      * | ||||||
|  |      * Retrieve a specific stream | ||||||
|  |      */ | ||||||
|  |     .get((req, res, next) => { | ||||||
|  |         validator({ | ||||||
|  |             required:             ['stream_id'], | ||||||
|  |             additionalProperties: false, | ||||||
|  |             properties:           { | ||||||
|  |                 stream_id: { | ||||||
|  |                     $ref: 'definitions#/definitions/id' | ||||||
|  |                 }, | ||||||
|  |                 expand:  { | ||||||
|  |                     $ref: 'definitions#/definitions/expand' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             stream_id: req.params.stream_id, | ||||||
|  |             expand:  (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null) | ||||||
|  |         }) | ||||||
|  |             .then(data => { | ||||||
|  |                 return internalStream.get(res.locals.access, { | ||||||
|  |                     id:     data.stream_id, | ||||||
|  |                     expand: data.expand | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             .then(row => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(row); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PUT /api/nginx/streams/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing stream | ||||||
|  |      */ | ||||||
|  |     .put((req, res, next) => { | ||||||
|  |         apiValidator({$ref: 'endpoints/streams#/links/2/schema'}, req.body) | ||||||
|  |             .then(payload => { | ||||||
|  |                 payload.id = req.params.stream_id; | ||||||
|  |                 return internalStream.update(res.locals.access, payload); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DELETE /api/nginx/streams/123 | ||||||
|  |      * | ||||||
|  |      * Update and existing stream | ||||||
|  |      */ | ||||||
|  |     .delete((req, res, next) => { | ||||||
|  |         internalStream.delete(res.locals.access, {id: req.params.stream_id}) | ||||||
|  |             .then(result => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(result); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
| @@ -3,7 +3,6 @@ | |||||||
| const express      = require('express'); | const express      = require('express'); | ||||||
| const validator    = require('../../lib/validator'); | const validator    = require('../../lib/validator'); | ||||||
| const jwtdecode    = require('../../lib/express/jwt-decode'); | const jwtdecode    = require('../../lib/express/jwt-decode'); | ||||||
| const pagination   = require('../../lib/express/pagination'); |  | ||||||
| const userIdFromMe = require('../../lib/express/user-id-from-me'); | const userIdFromMe = require('../../lib/express/user-id-from-me'); | ||||||
| const internalUser = require('../../internal/user'); | const internalUser = require('../../internal/user'); | ||||||
| const apiValidator = require('../../lib/validator/api'); | const apiValidator = require('../../lib/validator/api'); | ||||||
|   | |||||||
							
								
								
									
										203
									
								
								src/backend/schema/endpoints/dead-hosts.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/backend/schema/endpoints/dead-hosts.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "endpoints/dead-hosts", | ||||||
|  |   "title": "Users", | ||||||
|  |   "description": "Endpoints relating to Dead Hosts", | ||||||
|  |   "stability": "stable", | ||||||
|  |   "type": "object", | ||||||
|  |   "definitions": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "description": "Name", | ||||||
|  |       "example": "Jamie Curnow", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 100 | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "description": "Nickname", | ||||||
|  |       "example": "Jamie", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 50 | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "description": "Avatar", | ||||||
|  |       "example": "http://somewhere.jpg", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 150, | ||||||
|  |       "readOnly": true | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "description": "Roles", | ||||||
|  |       "example": [ | ||||||
|  |         "admin" | ||||||
|  |       ], | ||||||
|  |       "type": "array" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "description": "Is Disabled", | ||||||
|  |       "example": false, | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "title": "List", | ||||||
|  |       "description": "Returns a list of Users", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "GET", | ||||||
|  |       "rel": "self", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Create", | ||||||
|  |       "description": "Creates a new User", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "POST", | ||||||
|  |       "rel": "create", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "required": [ | ||||||
|  |           "name", | ||||||
|  |           "nickname", | ||||||
|  |           "email" | ||||||
|  |         ], | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           }, | ||||||
|  |           "auth": { | ||||||
|  |             "type": "object", | ||||||
|  |             "description": "Auth Credentials", | ||||||
|  |             "example": { | ||||||
|  |               "type": "password", | ||||||
|  |               "secret": "bigredhorsebanana" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Update", | ||||||
|  |       "description": "Updates a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "PUT", | ||||||
|  |       "rel": "update", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Delete", | ||||||
|  |       "description": "Deletes a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "DELETE", | ||||||
|  |       "rel": "delete", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "boolean" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "$ref": "#/definitions/name" | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "$ref": "#/definitions/nickname" | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "$ref": "#/definitions/avatar" | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "$ref": "#/definitions/roles" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "$ref": "#/definitions/is_disabled" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										203
									
								
								src/backend/schema/endpoints/proxy-hosts.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/backend/schema/endpoints/proxy-hosts.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "endpoints/proxy-hosts", | ||||||
|  |   "title": "Users", | ||||||
|  |   "description": "Endpoints relating to Proxy Hosts", | ||||||
|  |   "stability": "stable", | ||||||
|  |   "type": "object", | ||||||
|  |   "definitions": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "description": "Name", | ||||||
|  |       "example": "Jamie Curnow", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 100 | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "description": "Nickname", | ||||||
|  |       "example": "Jamie", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 50 | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "description": "Avatar", | ||||||
|  |       "example": "http://somewhere.jpg", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 150, | ||||||
|  |       "readOnly": true | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "description": "Roles", | ||||||
|  |       "example": [ | ||||||
|  |         "admin" | ||||||
|  |       ], | ||||||
|  |       "type": "array" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "description": "Is Disabled", | ||||||
|  |       "example": false, | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "title": "List", | ||||||
|  |       "description": "Returns a list of Users", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "GET", | ||||||
|  |       "rel": "self", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Create", | ||||||
|  |       "description": "Creates a new User", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "POST", | ||||||
|  |       "rel": "create", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "required": [ | ||||||
|  |           "name", | ||||||
|  |           "nickname", | ||||||
|  |           "email" | ||||||
|  |         ], | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           }, | ||||||
|  |           "auth": { | ||||||
|  |             "type": "object", | ||||||
|  |             "description": "Auth Credentials", | ||||||
|  |             "example": { | ||||||
|  |               "type": "password", | ||||||
|  |               "secret": "bigredhorsebanana" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Update", | ||||||
|  |       "description": "Updates a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "PUT", | ||||||
|  |       "rel": "update", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Delete", | ||||||
|  |       "description": "Deletes a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "DELETE", | ||||||
|  |       "rel": "delete", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "boolean" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "$ref": "#/definitions/name" | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "$ref": "#/definitions/nickname" | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "$ref": "#/definitions/avatar" | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "$ref": "#/definitions/roles" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "$ref": "#/definitions/is_disabled" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										203
									
								
								src/backend/schema/endpoints/redirection-hosts.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/backend/schema/endpoints/redirection-hosts.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "endpoints/redirection-hosts", | ||||||
|  |   "title": "Users", | ||||||
|  |   "description": "Endpoints relating to Redirection Hosts", | ||||||
|  |   "stability": "stable", | ||||||
|  |   "type": "object", | ||||||
|  |   "definitions": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "description": "Name", | ||||||
|  |       "example": "Jamie Curnow", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 100 | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "description": "Nickname", | ||||||
|  |       "example": "Jamie", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 50 | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "description": "Avatar", | ||||||
|  |       "example": "http://somewhere.jpg", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 150, | ||||||
|  |       "readOnly": true | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "description": "Roles", | ||||||
|  |       "example": [ | ||||||
|  |         "admin" | ||||||
|  |       ], | ||||||
|  |       "type": "array" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "description": "Is Disabled", | ||||||
|  |       "example": false, | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "title": "List", | ||||||
|  |       "description": "Returns a list of Users", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "GET", | ||||||
|  |       "rel": "self", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Create", | ||||||
|  |       "description": "Creates a new User", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "POST", | ||||||
|  |       "rel": "create", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "required": [ | ||||||
|  |           "name", | ||||||
|  |           "nickname", | ||||||
|  |           "email" | ||||||
|  |         ], | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           }, | ||||||
|  |           "auth": { | ||||||
|  |             "type": "object", | ||||||
|  |             "description": "Auth Credentials", | ||||||
|  |             "example": { | ||||||
|  |               "type": "password", | ||||||
|  |               "secret": "bigredhorsebanana" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Update", | ||||||
|  |       "description": "Updates a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "PUT", | ||||||
|  |       "rel": "update", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Delete", | ||||||
|  |       "description": "Deletes a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "DELETE", | ||||||
|  |       "rel": "delete", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "boolean" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "$ref": "#/definitions/name" | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "$ref": "#/definitions/nickname" | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "$ref": "#/definitions/avatar" | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "$ref": "#/definitions/roles" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "$ref": "#/definitions/is_disabled" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										203
									
								
								src/backend/schema/endpoints/streams.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/backend/schema/endpoints/streams.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "$id": "endpoints/streams", | ||||||
|  |   "title": "Users", | ||||||
|  |   "description": "Endpoints relating to Streams", | ||||||
|  |   "stability": "stable", | ||||||
|  |   "type": "object", | ||||||
|  |   "definitions": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "description": "Name", | ||||||
|  |       "example": "Jamie Curnow", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 100 | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "description": "Nickname", | ||||||
|  |       "example": "Jamie", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 50 | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "../definitions.json#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "description": "Avatar", | ||||||
|  |       "example": "http://somewhere.jpg", | ||||||
|  |       "type": "string", | ||||||
|  |       "minLength": 2, | ||||||
|  |       "maxLength": 150, | ||||||
|  |       "readOnly": true | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "description": "Roles", | ||||||
|  |       "example": [ | ||||||
|  |         "admin" | ||||||
|  |       ], | ||||||
|  |       "type": "array" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "description": "Is Disabled", | ||||||
|  |       "example": false, | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "title": "List", | ||||||
|  |       "description": "Returns a list of Users", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "GET", | ||||||
|  |       "rel": "self", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Create", | ||||||
|  |       "description": "Creates a new User", | ||||||
|  |       "href": "/users", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "POST", | ||||||
|  |       "rel": "create", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "required": [ | ||||||
|  |           "name", | ||||||
|  |           "nickname", | ||||||
|  |           "email" | ||||||
|  |         ], | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           }, | ||||||
|  |           "auth": { | ||||||
|  |             "type": "object", | ||||||
|  |             "description": "Auth Credentials", | ||||||
|  |             "example": { | ||||||
|  |               "type": "password", | ||||||
|  |               "secret": "bigredhorsebanana" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Update", | ||||||
|  |       "description": "Updates a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "PUT", | ||||||
|  |       "rel": "update", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "schema": { | ||||||
|  |         "type": "object", | ||||||
|  |         "properties": { | ||||||
|  |           "name": { | ||||||
|  |             "$ref": "#/definitions/name" | ||||||
|  |           }, | ||||||
|  |           "nickname": { | ||||||
|  |             "$ref": "#/definitions/nickname" | ||||||
|  |           }, | ||||||
|  |           "email": { | ||||||
|  |             "$ref": "#/definitions/email" | ||||||
|  |           }, | ||||||
|  |           "roles": { | ||||||
|  |             "$ref": "#/definitions/roles" | ||||||
|  |           }, | ||||||
|  |           "is_disabled": { | ||||||
|  |             "$ref": "#/definitions/is_disabled" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "properties": { | ||||||
|  |           "$ref": "#/properties" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "title": "Delete", | ||||||
|  |       "description": "Deletes a existing User", | ||||||
|  |       "href": "/users/{definitions.identity.example}", | ||||||
|  |       "access": "private", | ||||||
|  |       "method": "DELETE", | ||||||
|  |       "rel": "delete", | ||||||
|  |       "http_header": { | ||||||
|  |         "$ref": "../examples.json#/definitions/auth_header" | ||||||
|  |       }, | ||||||
|  |       "targetSchema": { | ||||||
|  |         "type": "boolean" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "id": { | ||||||
|  |       "$ref": "#/definitions/id" | ||||||
|  |     }, | ||||||
|  |     "created_on": { | ||||||
|  |       "$ref": "#/definitions/created_on" | ||||||
|  |     }, | ||||||
|  |     "modified_on": { | ||||||
|  |       "$ref": "#/definitions/modified_on" | ||||||
|  |     }, | ||||||
|  |     "name": { | ||||||
|  |       "$ref": "#/definitions/name" | ||||||
|  |     }, | ||||||
|  |     "nickname": { | ||||||
|  |       "$ref": "#/definitions/nickname" | ||||||
|  |     }, | ||||||
|  |     "email": { | ||||||
|  |       "$ref": "#/definitions/email" | ||||||
|  |     }, | ||||||
|  |     "avatar": { | ||||||
|  |       "$ref": "#/definitions/avatar" | ||||||
|  |     }, | ||||||
|  |     "roles": { | ||||||
|  |       "$ref": "#/definitions/roles" | ||||||
|  |     }, | ||||||
|  |     "is_disabled": { | ||||||
|  |       "$ref": "#/definitions/is_disabled" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -16,6 +16,18 @@ | |||||||
|     }, |     }, | ||||||
|     "users": { |     "users": { | ||||||
|       "$ref": "endpoints/users.json" |       "$ref": "endpoints/users.json" | ||||||
|  |     }, | ||||||
|  |     "proxy-hosts": { | ||||||
|  |       "$ref": "endpoints/proxy-hosts.json" | ||||||
|  |     }, | ||||||
|  |     "redirection-hosts": { | ||||||
|  |       "$ref": "endpoints/redirection-hosts.json" | ||||||
|  |     }, | ||||||
|  |     "dead-hosts": { | ||||||
|  |       "$ref": "endpoints/dead-hosts.json" | ||||||
|  |     }, | ||||||
|  |     "streams": { | ||||||
|  |       "$ref": "endpoints/streams.json" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -103,6 +103,26 @@ function makeExpansionString (expand) { | |||||||
|     return items.join(','); |     return items.join(','); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param   {String}   path | ||||||
|  |  * @param   {Array}    [expand] | ||||||
|  |  * @param   {String}   [query] | ||||||
|  |  * @returns {Promise} | ||||||
|  |  */ | ||||||
|  | function getAllObjects (path, expand, query) { | ||||||
|  |     let params = []; | ||||||
|  |  | ||||||
|  |     if (typeof expand === 'object' && expand !== null && expand.length) { | ||||||
|  |         params.push('expand=' + makeExpansionString(expand)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (typeof query === 'string') { | ||||||
|  |         params.push('query=' + query); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return fetch('get', path + (params.length ? '?' + params.join('&') : '')); | ||||||
|  | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     status: function () { |     status: function () { | ||||||
|         return fetch('get', ''); |         return fetch('get', ''); | ||||||
| @@ -168,17 +188,7 @@ module.exports = { | |||||||
|          * @returns {Promise} |          * @returns {Promise} | ||||||
|          */ |          */ | ||||||
|         getAll: function (expand, query) { |         getAll: function (expand, query) { | ||||||
|             let params = []; |             return getAllObjects('users', expand, query); | ||||||
|  |  | ||||||
|             if (typeof expand === 'object' && expand !== null && expand.length) { |  | ||||||
|                 params.push('expand=' + makeExpansionString(expand)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (typeof query === 'string') { |  | ||||||
|                 params.push('query=' + query); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return fetch('get', 'users' + (params.length ? '?' + params.join('&') : '')); |  | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
| @@ -237,6 +247,64 @@ module.exports = { | |||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  |     Nginx: { | ||||||
|  |  | ||||||
|  |         ProxyHosts: { | ||||||
|  |             /** | ||||||
|  |              * @param   {Array}    [expand] | ||||||
|  |              * @param   {String}   [query] | ||||||
|  |              * @returns {Promise} | ||||||
|  |              */ | ||||||
|  |             getAll: function (expand, query) { | ||||||
|  |                 return getAllObjects('nginx/proxy-hosts', expand, query); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         RedirectionHosts: { | ||||||
|  |             /** | ||||||
|  |              * @param   {Array}    [expand] | ||||||
|  |              * @param   {String}   [query] | ||||||
|  |              * @returns {Promise} | ||||||
|  |              */ | ||||||
|  |             getAll: function (expand, query) { | ||||||
|  |                 return getAllObjects('nginx/redirection-hosts', expand, query); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         Streams: { | ||||||
|  |             /** | ||||||
|  |              * @param   {Array}    [expand] | ||||||
|  |              * @param   {String}   [query] | ||||||
|  |              * @returns {Promise} | ||||||
|  |              */ | ||||||
|  |             getAll: function (expand, query) { | ||||||
|  |                 return getAllObjects('nginx/streams', expand, query); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         DeadHosts: { | ||||||
|  |             /** | ||||||
|  |              * @param   {Array}    [expand] | ||||||
|  |              * @param   {String}   [query] | ||||||
|  |              * @returns {Promise} | ||||||
|  |              */ | ||||||
|  |             getAll: function (expand, query) { | ||||||
|  |                 return getAllObjects('nginx/dead-hosts', expand, query); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     AccessLists: { | ||||||
|  |         /** | ||||||
|  |          * @param   {Array}    [expand] | ||||||
|  |          * @param   {String}   [query] | ||||||
|  |          * @returns {Promise} | ||||||
|  |          */ | ||||||
|  |         getAll: function (expand, query) { | ||||||
|  |             return getAllObjects('access-lists', expand, query); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|     Reports: { |     Reports: { | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
| @@ -244,6 +312,6 @@ module.exports = { | |||||||
|          */ |          */ | ||||||
|         getHostStats: function () { |         getHostStats: function () { | ||||||
|             return fetch('get', 'reports/hosts'); |             return fetch('get', 'reports/hosts'); | ||||||
|         }, |         } | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -124,60 +124,70 @@ module.exports = { | |||||||
|      * Nginx Proxy Hosts |      * Nginx Proxy Hosts | ||||||
|      */ |      */ | ||||||
|     showNginxProxy: function () { |     showNginxProxy: function () { | ||||||
|  |         if (Cache.User.isAdmin() || Cache.User.canView('proxy_hosts')) { | ||||||
|             let controller = this; |             let controller = this; | ||||||
|  |  | ||||||
|             require(['./main', './nginx/proxy/main'], (App, View) => { |             require(['./main', './nginx/proxy/main'], (App, View) => { | ||||||
|                 controller.navigate('/nginx/proxy'); |                 controller.navigate('/nginx/proxy'); | ||||||
|                 App.UI.showAppContent(new View()); |                 App.UI.showAppContent(new View()); | ||||||
|             }); |             }); | ||||||
|  |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Nginx Redirection Hosts |      * Nginx Redirection Hosts | ||||||
|      */ |      */ | ||||||
|     showNginxRedirection: function () { |     showNginxRedirection: function () { | ||||||
|  |         if (Cache.User.isAdmin() || Cache.User.canView('redirection_hosts')) { | ||||||
|             let controller = this; |             let controller = this; | ||||||
|  |  | ||||||
|             require(['./main', './nginx/redirection/main'], (App, View) => { |             require(['./main', './nginx/redirection/main'], (App, View) => { | ||||||
|                 controller.navigate('/nginx/redirection'); |                 controller.navigate('/nginx/redirection'); | ||||||
|                 App.UI.showAppContent(new View()); |                 App.UI.showAppContent(new View()); | ||||||
|             }); |             }); | ||||||
|  |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Nginx Stream Hosts |      * Nginx Stream Hosts | ||||||
|      */ |      */ | ||||||
|     showNginxStream: function () { |     showNginxStream: function () { | ||||||
|  |         if (Cache.User.isAdmin() || Cache.User.canView('streams')) { | ||||||
|             let controller = this; |             let controller = this; | ||||||
|  |  | ||||||
|             require(['./main', './nginx/stream/main'], (App, View) => { |             require(['./main', './nginx/stream/main'], (App, View) => { | ||||||
|                 controller.navigate('/nginx/stream'); |                 controller.navigate('/nginx/stream'); | ||||||
|                 App.UI.showAppContent(new View()); |                 App.UI.showAppContent(new View()); | ||||||
|             }); |             }); | ||||||
|  |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Nginx 404 Hosts |      * Nginx Dead Hosts | ||||||
|      */ |      */ | ||||||
|     showNginx404: function () { |     showNginxDead: function () { | ||||||
|  |         if (Cache.User.isAdmin() || Cache.User.canView('dead_hosts')) { | ||||||
|             let controller = this; |             let controller = this; | ||||||
|  |  | ||||||
|         require(['./main', './nginx/404/main'], (App, View) => { |             require(['./main', './nginx/dead/main'], (App, View) => { | ||||||
|                 controller.navigate('/nginx/404'); |                 controller.navigate('/nginx/404'); | ||||||
|                 App.UI.showAppContent(new View()); |                 App.UI.showAppContent(new View()); | ||||||
|             }); |             }); | ||||||
|  |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Nginx Access |      * Nginx Access | ||||||
|      */ |      */ | ||||||
|     showNginxAccess: function () { |     showNginxAccess: function () { | ||||||
|  |         if (Cache.User.isAdmin() || Cache.User.canView('access_lists')) { | ||||||
|             let controller = this; |             let controller = this; | ||||||
|  |  | ||||||
|             require(['./main', './nginx/access/main'], (App, View) => { |             require(['./main', './nginx/access/main'], (App, View) => { | ||||||
|                 controller.navigate('/nginx/access'); |                 controller.navigate('/nginx/access'); | ||||||
|                 App.UI.showAppContent(new View()); |                 App.UI.showAppContent(new View()); | ||||||
|             }); |             }); | ||||||
|  |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -2,8 +2,10 @@ | |||||||
|     <h1 class="page-title">Hi <%- getUserName() %></h1> |     <h1 class="page-title">Hi <%- getUserName() %></h1> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|  | <% if (columns) { %> | ||||||
| <div class="row"> | <div class="row"> | ||||||
|     <div class="col-sm-6 col-lg-3"> |     <% if (canShow('proxy_hosts')) { %> | ||||||
|  |     <div class="col-sm-<%- 24 / columns %> col-lg-<%- 12 / columns %>"> | ||||||
|         <div class="card p-3"> |         <div class="card p-3"> | ||||||
|             <div class="d-flex align-items-center"> |             <div class="d-flex align-items-center"> | ||||||
|                     <span class="stamp stamp-md bg-green mr-3"> |                     <span class="stamp stamp-md bg-green mr-3"> | ||||||
| @@ -15,8 +17,10 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |     <% } %> | ||||||
|  |  | ||||||
|     <div class="col-sm-6 col-lg-3"> |     <% if (canShow('redirection_hosts')) { %> | ||||||
|  |     <div class="col-sm-<%- 24 / columns %> col-lg-<%- 12 / columns %>"> | ||||||
|         <div class="card p-3"> |         <div class="card p-3"> | ||||||
|             <div class="d-flex align-items-center"> |             <div class="d-flex align-items-center"> | ||||||
|                     <span class="stamp stamp-md bg-yellow mr-3"> |                     <span class="stamp stamp-md bg-yellow mr-3"> | ||||||
| @@ -28,8 +32,10 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |     <% } %> | ||||||
|  |  | ||||||
|     <div class="col-sm-6 col-lg-3"> |     <% if (canShow('streams')) { %> | ||||||
|  |     <div class="col-sm-<%- 24 / columns %> col-lg-<%- 12 / columns %>"> | ||||||
|         <div class="card p-3"> |         <div class="card p-3"> | ||||||
|             <div class="d-flex align-items-center"> |             <div class="d-flex align-items-center"> | ||||||
|                     <span class="stamp stamp-md bg-blue mr-3"> |                     <span class="stamp stamp-md bg-blue mr-3"> | ||||||
| @@ -41,17 +47,21 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |     <% } %> | ||||||
|  |  | ||||||
|     <div class="col-sm-6 col-lg-3"> |     <% if (canShow('dead_hosts')) { %> | ||||||
|  |     <div class="col-sm-<%- 24 / columns %> col-lg-<%- 12 / columns %>"> | ||||||
|         <div class="card p-3"> |         <div class="card p-3"> | ||||||
|             <div class="d-flex align-items-center"> |             <div class="d-flex align-items-center"> | ||||||
|                     <span class="stamp stamp-md bg-red mr-3"> |                     <span class="stamp stamp-md bg-red mr-3"> | ||||||
|                       <i class="fe fe-zap-off"></i> |                       <i class="fe fe-zap-off"></i> | ||||||
|                     </span> |                     </span> | ||||||
|                 <div> |                 <div> | ||||||
|                     <h4 class="m-0"><a href="/nginx/404"><%- getHostStat('404') %> <small>404 Hosts</small></a></h4> |                     <h4 class="m-0"><a href="/nginx/404"><%- getHostStat('dead') %> <small>404 Hosts</small></a></h4> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |     <% } %> | ||||||
| </div> | </div> | ||||||
|  | <% } %> | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ const template   = require('./main.ejs'); | |||||||
| module.exports = Mn.View.extend({ | module.exports = Mn.View.extend({ | ||||||
|     template: template, |     template: template, | ||||||
|     id:       'dashboard', |     id:       'dashboard', | ||||||
|  |     columns: 0, | ||||||
|  |  | ||||||
|     stats: {}, |     stats: {}, | ||||||
|  |  | ||||||
| @@ -38,7 +39,13 @@ module.exports = Mn.View.extend({ | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 return '-'; |                 return '-'; | ||||||
|             } |             }, | ||||||
|  |  | ||||||
|  |             canShow: function (perm) { | ||||||
|  |                 return Cache.User.isAdmin() || Cache.User.canView(perm); | ||||||
|  |             }, | ||||||
|  |  | ||||||
|  |             columns: view.columns | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
| @@ -57,5 +64,31 @@ module.exports = Mn.View.extend({ | |||||||
|                     console.log(err); |                     console.log(err); | ||||||
|                 }); |                 }); | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param {Object}  [model] | ||||||
|  |      */ | ||||||
|  |     preRender: function (model) { | ||||||
|  |         this.columns = 0; | ||||||
|  |  | ||||||
|  |         // calculate the available columns based on permissions for the objects | ||||||
|  |         // and store as a variable | ||||||
|  |         //let view = this; | ||||||
|  |         let perms = ['proxy_hosts', 'redirection_hosts', 'streams', 'dead_hosts']; | ||||||
|  |  | ||||||
|  |         perms.map(perm => { | ||||||
|  |             this.columns += Cache.User.isAdmin() || Cache.User.canView(perm) ? 1 : 0; | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Prevent double rendering on initial calls | ||||||
|  |         if (typeof model !== 'undefined') { | ||||||
|  |             this.render(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.preRender(); | ||||||
|  |         this.listenTo(Cache.User, 'change', this.preRender); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								src/frontend/js/app/empty/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/frontend/js/app/empty/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <% if (title) { %> | ||||||
|  |     <h1 class="h2 mb-3"><%- title %></h1> | ||||||
|  | <% } | ||||||
|  |  | ||||||
|  | if (subtitle) { %> | ||||||
|  |     <p class="h4 text-muted font-weight-normal mb-7"><%- subtitle %></p> | ||||||
|  | <% } | ||||||
|  |  | ||||||
|  | if (link) { %> | ||||||
|  |     <a class="btn btn-teal" href="#"><%- link %></a> | ||||||
|  | <% } %> | ||||||
							
								
								
									
										30
									
								
								src/frontend/js/app/empty/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/frontend/js/app/empty/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     className: 'text-center m-7', | ||||||
|  |     template:  template, | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         action: 'a' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.action': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             this.getOption('action')(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: function () { | ||||||
|  |         return { | ||||||
|  |             title:    this.getOption('title'), | ||||||
|  |             subtitle: this.getOption('subtitle'), | ||||||
|  |             link:     this.getOption('link'), | ||||||
|  |             action:   typeof this.getOption('action') === 'function' | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | }); | ||||||
							
								
								
									
										7
									
								
								src/frontend/js/app/error/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/frontend/js/app/error/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <i class="fe fe-alert-triangle mr-2" aria-hidden="true"></i> | ||||||
|  | <%= code ? '<strong>' + code + '</strong> — ' : '' %> | ||||||
|  | <%- message %> | ||||||
|  |  | ||||||
|  | <% if (retry) { %> | ||||||
|  |     <br><br><a href="#" class="btn btn-sm btn-warning retry">Try again</a> | ||||||
|  | <% } %> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/error/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/error/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template:  template, | ||||||
|  |     className: 'alert alert-icon alert-warning m-5', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         retry: 'a.retry' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.retry': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             this.getOption('retry')(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: function () { | ||||||
|  |         return { | ||||||
|  |             message: this.getOption('message'), | ||||||
|  |             code:    this.getOption('code'), | ||||||
|  |             retry:   typeof this.getOption('retry') === 'function' | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | }); | ||||||
| @@ -1 +0,0 @@ | |||||||
| 404 |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| 'use strict'; |  | ||||||
|  |  | ||||||
| const Mn       = require('backbone.marionette'); |  | ||||||
| const template = require('./main.ejs'); |  | ||||||
|  |  | ||||||
| module.exports = Mn.View.extend({ |  | ||||||
|     template: template, |  | ||||||
|     id:       'nginx-404' |  | ||||||
| }); |  | ||||||
							
								
								
									
										32
									
								
								src/frontend/js/app/nginx/dead/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/frontend/js/app/nginx/dead/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | <td class="text-center"> | ||||||
|  |     <div class="avatar d-block" style="background-image: url(<%- avatar || '/images/default-avatar.jpg' %>)"> | ||||||
|  |         <span class="avatar-status <%- is_disabled ? 'bg-red' : 'bg-green' %>"></span> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- name %></div> | ||||||
|  |     <div class="small text-muted"> | ||||||
|  |         Created: <%- formatDbDate(created_on, 'Do MMMM YYYY') %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- email %></div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- roles.join(', ') %></div> | ||||||
|  | </td> | ||||||
|  | <td class="text-center"> | ||||||
|  |     <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-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit Details</a> | ||||||
|  |             <a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Edit Permissions</a> | ||||||
|  |             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> Set Password</a> | ||||||
|  |             <% if (!isSelf()) { %> | ||||||
|  |             <a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a> | ||||||
|  |             <div class="dropdown-divider"></div> | ||||||
|  |             <a href="#" class="delete-user dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> Delete User</a> | ||||||
|  |             <% } %> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
							
								
								
									
										72
									
								
								src/frontend/js/app/nginx/dead/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/frontend/js/app/nginx/dead/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn         = require('backbone.marionette'); | ||||||
|  | const Controller = require('../../../controller'); | ||||||
|  | const Api        = require('../../../api'); | ||||||
|  | const Cache      = require('../../../cache'); | ||||||
|  | const Tokens     = require('../../../tokens'); | ||||||
|  | const template   = require('./item.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     tagName:  'tr', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         edit:        'a.edit-user', | ||||||
|  |         permissions: 'a.edit-permissions', | ||||||
|  |         password:    'a.set-password', | ||||||
|  |         login:       'a.login', | ||||||
|  |         delete:      'a.delete-user' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.edit': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.permissions': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPermissions(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.password': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPasswordForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.delete': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserDeleteConfirm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.login': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |  | ||||||
|  |             if (Cache.User.get('id') !== this.model.get('id')) { | ||||||
|  |                 this.ui.login.prop('disabled', true).addClass('btn-disabled'); | ||||||
|  |  | ||||||
|  |                 Api.Users.loginAs(this.model.get('id')) | ||||||
|  |                     .then(res => { | ||||||
|  |                         Tokens.addToken(res.token, res.user.nickname || res.user.name); | ||||||
|  |                         window.location = '/'; | ||||||
|  |                         window.location.reload(); | ||||||
|  |                     }) | ||||||
|  |                     .catch(err => { | ||||||
|  |                         alert(err.message); | ||||||
|  |                         this.ui.login.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: { | ||||||
|  |         isSelf: function () { | ||||||
|  |             return Cache.User.get('id') === this.id; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(this.model, 'change', this.render); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								src/frontend/js/app/nginx/dead/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/frontend/js/app/nginx/dead/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <thead> | ||||||
|  |     <th width="30"> </th> | ||||||
|  |     <th>Name</th> | ||||||
|  |     <th>Email</th> | ||||||
|  |     <th>Roles</th> | ||||||
|  |     <th> </th> | ||||||
|  | </thead> | ||||||
|  | <tbody> | ||||||
|  |     <!-- items --> | ||||||
|  | </tbody> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/nginx/dead/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/nginx/dead/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 | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										16
									
								
								src/frontend/js/app/nginx/dead/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/frontend/js/app/nginx/dead/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <div class="card"> | ||||||
|  |     <div class="card-header"> | ||||||
|  |         <h3 class="card-title">404 Hosts</h3> | ||||||
|  |         <div class="card-options"> | ||||||
|  |             <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item">Add 404 Host</a> | ||||||
|  |         </div> | ||||||
|  |     </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> | ||||||
							
								
								
									
										70
									
								
								src/frontend/js/app/nginx/dead/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/frontend/js/app/nginx/dead/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn            = require('backbone.marionette'); | ||||||
|  | const DeadHostModel = require('../../../models/dead-host'); | ||||||
|  | const Api           = require('../../api'); | ||||||
|  | const Controller    = require('../../controller'); | ||||||
|  | const ListView      = require('./list/main'); | ||||||
|  | const ErrorView     = require('../../error/main'); | ||||||
|  | const template      = require('./main.ejs'); | ||||||
|  | const EmptyView     = require('../../empty/main'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     id:       'nginx-dead', | ||||||
|  |     template: template, | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         list_region: '.list-region', | ||||||
|  |         add:         '.add-item', | ||||||
|  |         dimmer:      '.dimmer' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         list_region: '@ui.list_region' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.add': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showNginxDeadForm(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         Api.Nginx.DeadHosts.getAll() | ||||||
|  |             .then(response => { | ||||||
|  |                 if (!view.isDestroyed()) { | ||||||
|  |                     if (response && response.length) { | ||||||
|  |                         view.showChildView('list_region', new ListView({ | ||||||
|  |                             collection: new DeadHostModel.Collection(response) | ||||||
|  |                         })); | ||||||
|  |                     } else { | ||||||
|  |                         view.showChildView('list_region', new EmptyView({ | ||||||
|  |                             title:    'There are no 404 Hosts', | ||||||
|  |                             subtitle: 'Why don\'t you create one?', | ||||||
|  |                             link:     'Add 404 Host', | ||||||
|  |                             action:   function () { | ||||||
|  |                                 Controller.showNginxDeadForm(); | ||||||
|  |                             } | ||||||
|  |                         })); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(err => { | ||||||
|  |                 view.showChildView('list_region', new ErrorView({ | ||||||
|  |                     code:    err.code, | ||||||
|  |                     message: err.message, | ||||||
|  |                     retry:   function () { | ||||||
|  |                         Controller.showNginxDead(); | ||||||
|  |                     } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										32
									
								
								src/frontend/js/app/nginx/proxy/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/frontend/js/app/nginx/proxy/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | <td class="text-center"> | ||||||
|  |     <div class="avatar d-block" style="background-image: url(<%- avatar || '/images/default-avatar.jpg' %>)"> | ||||||
|  |         <span class="avatar-status <%- is_disabled ? 'bg-red' : 'bg-green' %>"></span> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- name %></div> | ||||||
|  |     <div class="small text-muted"> | ||||||
|  |         Created: <%- formatDbDate(created_on, 'Do MMMM YYYY') %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- email %></div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- roles.join(', ') %></div> | ||||||
|  | </td> | ||||||
|  | <td class="text-center"> | ||||||
|  |     <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-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit Details</a> | ||||||
|  |             <a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Edit Permissions</a> | ||||||
|  |             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> Set Password</a> | ||||||
|  |             <% if (!isSelf()) { %> | ||||||
|  |             <a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a> | ||||||
|  |             <div class="dropdown-divider"></div> | ||||||
|  |             <a href="#" class="delete-user dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> Delete User</a> | ||||||
|  |             <% } %> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
							
								
								
									
										72
									
								
								src/frontend/js/app/nginx/proxy/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/frontend/js/app/nginx/proxy/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn         = require('backbone.marionette'); | ||||||
|  | const Controller = require('../../../controller'); | ||||||
|  | const Api        = require('../../../api'); | ||||||
|  | const Cache      = require('../../../cache'); | ||||||
|  | const Tokens     = require('../../../tokens'); | ||||||
|  | const template   = require('./item.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     tagName:  'tr', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         edit:        'a.edit-user', | ||||||
|  |         permissions: 'a.edit-permissions', | ||||||
|  |         password:    'a.set-password', | ||||||
|  |         login:       'a.login', | ||||||
|  |         delete:      'a.delete-user' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.edit': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.permissions': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPermissions(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.password': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPasswordForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.delete': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserDeleteConfirm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.login': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |  | ||||||
|  |             if (Cache.User.get('id') !== this.model.get('id')) { | ||||||
|  |                 this.ui.login.prop('disabled', true).addClass('btn-disabled'); | ||||||
|  |  | ||||||
|  |                 Api.Users.loginAs(this.model.get('id')) | ||||||
|  |                     .then(res => { | ||||||
|  |                         Tokens.addToken(res.token, res.user.nickname || res.user.name); | ||||||
|  |                         window.location = '/'; | ||||||
|  |                         window.location.reload(); | ||||||
|  |                     }) | ||||||
|  |                     .catch(err => { | ||||||
|  |                         alert(err.message); | ||||||
|  |                         this.ui.login.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: { | ||||||
|  |         isSelf: function () { | ||||||
|  |             return Cache.User.get('id') === this.id; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(this.model, 'change', this.render); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								src/frontend/js/app/nginx/proxy/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/frontend/js/app/nginx/proxy/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <thead> | ||||||
|  |     <th width="30"> </th> | ||||||
|  |     <th>Name</th> | ||||||
|  |     <th>Email</th> | ||||||
|  |     <th>Roles</th> | ||||||
|  |     <th> </th> | ||||||
|  | </thead> | ||||||
|  | <tbody> | ||||||
|  |     <!-- items --> | ||||||
|  | </tbody> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/nginx/proxy/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/nginx/proxy/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 | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | }); | ||||||
| @@ -1 +1,16 @@ | |||||||
| proxy | <div class="card"> | ||||||
|  |     <div class="card-header"> | ||||||
|  |         <h3 class="card-title">Proxy Hosts</h3> | ||||||
|  |         <div class="card-options"> | ||||||
|  |             <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item">Add Proxy Host</a> | ||||||
|  |         </div> | ||||||
|  |     </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> | ||||||
|   | |||||||
| @@ -1,9 +1,70 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const Mn             = require('backbone.marionette'); | const Mn             = require('backbone.marionette'); | ||||||
|  | const ProxyHostModel = require('../../../models/proxy-host'); | ||||||
|  | const Api            = require('../../api'); | ||||||
|  | const Controller     = require('../../controller'); | ||||||
|  | const ListView       = require('./list/main'); | ||||||
|  | const ErrorView      = require('../../error/main'); | ||||||
| const template       = require('./main.ejs'); | const template       = require('./main.ejs'); | ||||||
|  | const EmptyView      = require('../../empty/main'); | ||||||
|  |  | ||||||
| module.exports = Mn.View.extend({ | module.exports = Mn.View.extend({ | ||||||
|  |     id:       'nginx-proxy', | ||||||
|     template: template, |     template: template, | ||||||
|     id:       'nginx-proxy' |  | ||||||
|  |     ui: { | ||||||
|  |         list_region: '.list-region', | ||||||
|  |         add:         '.add-item', | ||||||
|  |         dimmer:      '.dimmer' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         list_region: '@ui.list_region' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.add': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showNginxProxyForm(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         Api.Nginx.ProxyHosts.getAll() | ||||||
|  |             .then(response => { | ||||||
|  |                 if (!view.isDestroyed()) { | ||||||
|  |                     if (response && response.length) { | ||||||
|  |                         view.showChildView('list_region', new ListView({ | ||||||
|  |                             collection: new ProxyHostModel.Collection(response) | ||||||
|  |                         })); | ||||||
|  |                     } else { | ||||||
|  |                         view.showChildView('list_region', new EmptyView({ | ||||||
|  |                             title:    'There are no Proxy Hosts', | ||||||
|  |                             subtitle: 'Why don\'t you create one?', | ||||||
|  |                             link:     'Add Proxy Host', | ||||||
|  |                             action:   function () { | ||||||
|  |                                 Controller.showNginxProxyForm(); | ||||||
|  |                             } | ||||||
|  |                         })); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(err => { | ||||||
|  |                 view.showChildView('list_region', new ErrorView({ | ||||||
|  |                     code:    err.code, | ||||||
|  |                     message: err.message, | ||||||
|  |                     retry:   function () { | ||||||
|  |                         Controller.showNginxProxy(); | ||||||
|  |                     } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/frontend/js/app/nginx/redirection/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/frontend/js/app/nginx/redirection/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | <td class="text-center"> | ||||||
|  |     <div class="avatar d-block" style="background-image: url(<%- avatar || '/images/default-avatar.jpg' %>)"> | ||||||
|  |         <span class="avatar-status <%- is_disabled ? 'bg-red' : 'bg-green' %>"></span> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- name %></div> | ||||||
|  |     <div class="small text-muted"> | ||||||
|  |         Created: <%- formatDbDate(created_on, 'Do MMMM YYYY') %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- email %></div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- roles.join(', ') %></div> | ||||||
|  | </td> | ||||||
|  | <td class="text-center"> | ||||||
|  |     <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-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit Details</a> | ||||||
|  |             <a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Edit Permissions</a> | ||||||
|  |             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> Set Password</a> | ||||||
|  |             <% if (!isSelf()) { %> | ||||||
|  |             <a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a> | ||||||
|  |             <div class="dropdown-divider"></div> | ||||||
|  |             <a href="#" class="delete-user dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> Delete User</a> | ||||||
|  |             <% } %> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
							
								
								
									
										72
									
								
								src/frontend/js/app/nginx/redirection/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/frontend/js/app/nginx/redirection/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn         = require('backbone.marionette'); | ||||||
|  | const Controller = require('../../../controller'); | ||||||
|  | const Api        = require('../../../api'); | ||||||
|  | const Cache      = require('../../../cache'); | ||||||
|  | const Tokens     = require('../../../tokens'); | ||||||
|  | const template   = require('./item.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     tagName:  'tr', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         edit:        'a.edit-user', | ||||||
|  |         permissions: 'a.edit-permissions', | ||||||
|  |         password:    'a.set-password', | ||||||
|  |         login:       'a.login', | ||||||
|  |         delete:      'a.delete-user' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.edit': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.permissions': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPermissions(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.password': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPasswordForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.delete': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserDeleteConfirm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.login': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |  | ||||||
|  |             if (Cache.User.get('id') !== this.model.get('id')) { | ||||||
|  |                 this.ui.login.prop('disabled', true).addClass('btn-disabled'); | ||||||
|  |  | ||||||
|  |                 Api.Users.loginAs(this.model.get('id')) | ||||||
|  |                     .then(res => { | ||||||
|  |                         Tokens.addToken(res.token, res.user.nickname || res.user.name); | ||||||
|  |                         window.location = '/'; | ||||||
|  |                         window.location.reload(); | ||||||
|  |                     }) | ||||||
|  |                     .catch(err => { | ||||||
|  |                         alert(err.message); | ||||||
|  |                         this.ui.login.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: { | ||||||
|  |         isSelf: function () { | ||||||
|  |             return Cache.User.get('id') === this.id; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(this.model, 'change', this.render); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								src/frontend/js/app/nginx/redirection/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/frontend/js/app/nginx/redirection/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <thead> | ||||||
|  | <th width="30"> </th> | ||||||
|  | <th>Name</th> | ||||||
|  | <th>Email</th> | ||||||
|  | <th>Roles</th> | ||||||
|  | <th> </th> | ||||||
|  | </thead> | ||||||
|  | <tbody> | ||||||
|  | <!-- items --> | ||||||
|  | </tbody> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/nginx/redirection/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/nginx/redirection/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 | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | }); | ||||||
| @@ -1 +1,16 @@ | |||||||
| redirection | <div class="card"> | ||||||
|  |     <div class="card-header"> | ||||||
|  |         <h3 class="card-title">Redirection Hosts</h3> | ||||||
|  |         <div class="card-options"> | ||||||
|  |             <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item">Add Redirection Host</a> | ||||||
|  |         </div> | ||||||
|  |     </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> | ||||||
|   | |||||||
| @@ -1,9 +1,70 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const Mn                   = require('backbone.marionette'); | const Mn                   = require('backbone.marionette'); | ||||||
|  | const RedirectionHostModel = require('../../../models/redirection-host'); | ||||||
|  | const Api                  = require('../../api'); | ||||||
|  | const Controller           = require('../../controller'); | ||||||
|  | const ListView             = require('./list/main'); | ||||||
|  | const ErrorView            = require('../../error/main'); | ||||||
| const template             = require('./main.ejs'); | const template             = require('./main.ejs'); | ||||||
|  | const EmptyView            = require('../../empty/main'); | ||||||
|  |  | ||||||
| module.exports = Mn.View.extend({ | module.exports = Mn.View.extend({ | ||||||
|  |     id:       'nginx-redirections', | ||||||
|     template: template, |     template: template, | ||||||
|     id:       'nginx-redirection' |  | ||||||
|  |     ui: { | ||||||
|  |         list_region: '.list-region', | ||||||
|  |         add:         '.add-item', | ||||||
|  |         dimmer:      '.dimmer' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         list_region: '@ui.list_region' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.add': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showNginxRedirectionForm(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         Api.Nginx.RedirectionHosts.getAll() | ||||||
|  |             .then(response => { | ||||||
|  |                 if (!view.isDestroyed()) { | ||||||
|  |                     if (response && response.length) { | ||||||
|  |                         view.showChildView('list_region', new ListView({ | ||||||
|  |                             collection: new RedirectionHostModel.Collection(response) | ||||||
|  |                         })); | ||||||
|  |                     } else { | ||||||
|  |                         view.showChildView('list_region', new EmptyView({ | ||||||
|  |                             title:    'There are no Redirection Hosts', | ||||||
|  |                             subtitle: 'Why don\'t you create one?', | ||||||
|  |                             link:     'Add Redirection Host', | ||||||
|  |                             action:   function () { | ||||||
|  |                                 Controller.showNginxRedirectionForm(); | ||||||
|  |                             } | ||||||
|  |                         })); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(err => { | ||||||
|  |                 view.showChildView('list_region', new ErrorView({ | ||||||
|  |                     code:    err.code, | ||||||
|  |                     message: err.message, | ||||||
|  |                     retry:   function () { | ||||||
|  |                         Controller.showNginxRedirection(); | ||||||
|  |                     } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/frontend/js/app/nginx/stream/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/frontend/js/app/nginx/stream/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | <td class="text-center"> | ||||||
|  |     <div class="avatar d-block" style="background-image: url(<%- avatar || '/images/default-avatar.jpg' %>)"> | ||||||
|  |         <span class="avatar-status <%- is_disabled ? 'bg-red' : 'bg-green' %>"></span> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- name %></div> | ||||||
|  |     <div class="small text-muted"> | ||||||
|  |         Created: <%- formatDbDate(created_on, 'Do MMMM YYYY') %> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- email %></div> | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  |     <div><%- roles.join(', ') %></div> | ||||||
|  | </td> | ||||||
|  | <td class="text-center"> | ||||||
|  |     <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-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit Details</a> | ||||||
|  |             <a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Edit Permissions</a> | ||||||
|  |             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> Set Password</a> | ||||||
|  |             <% if (!isSelf()) { %> | ||||||
|  |             <a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a> | ||||||
|  |             <div class="dropdown-divider"></div> | ||||||
|  |             <a href="#" class="delete-user dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> Delete User</a> | ||||||
|  |             <% } %> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </td> | ||||||
							
								
								
									
										72
									
								
								src/frontend/js/app/nginx/stream/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/frontend/js/app/nginx/stream/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn         = require('backbone.marionette'); | ||||||
|  | const Controller = require('../../../controller'); | ||||||
|  | const Api        = require('../../../api'); | ||||||
|  | const Cache      = require('../../../cache'); | ||||||
|  | const Tokens     = require('../../../tokens'); | ||||||
|  | const template   = require('./item.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     tagName:  'tr', | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         edit:        'a.edit-user', | ||||||
|  |         permissions: 'a.edit-permissions', | ||||||
|  |         password:    'a.set-password', | ||||||
|  |         login:       'a.login', | ||||||
|  |         delete:      'a.delete-user' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.edit': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.permissions': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPermissions(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.password': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserPasswordForm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.delete': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showUserDeleteConfirm(this.model); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         'click @ui.login': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |  | ||||||
|  |             if (Cache.User.get('id') !== this.model.get('id')) { | ||||||
|  |                 this.ui.login.prop('disabled', true).addClass('btn-disabled'); | ||||||
|  |  | ||||||
|  |                 Api.Users.loginAs(this.model.get('id')) | ||||||
|  |                     .then(res => { | ||||||
|  |                         Tokens.addToken(res.token, res.user.nickname || res.user.name); | ||||||
|  |                         window.location = '/'; | ||||||
|  |                         window.location.reload(); | ||||||
|  |                     }) | ||||||
|  |                     .catch(err => { | ||||||
|  |                         alert(err.message); | ||||||
|  |                         this.ui.login.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: { | ||||||
|  |         isSelf: function () { | ||||||
|  |             return Cache.User.get('id') === this.id; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(this.model, 'change', this.render); | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								src/frontend/js/app/nginx/stream/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/frontend/js/app/nginx/stream/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <thead> | ||||||
|  |     <th width="30"> </th> | ||||||
|  |     <th>Name</th> | ||||||
|  |     <th>Email</th> | ||||||
|  |     <th>Roles</th> | ||||||
|  |     <th> </th> | ||||||
|  | </thead> | ||||||
|  | <tbody> | ||||||
|  |     <!-- items --> | ||||||
|  | </tbody> | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/app/nginx/stream/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/nginx/stream/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 | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | }); | ||||||
| @@ -1 +1,16 @@ | |||||||
| stream | <div class="card"> | ||||||
|  |     <div class="card-header"> | ||||||
|  |         <h3 class="card-title">Streams</h3> | ||||||
|  |         <div class="card-options"> | ||||||
|  |             <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item">Add Stream</a> | ||||||
|  |         </div> | ||||||
|  |     </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> | ||||||
|   | |||||||
| @@ -1,9 +1,70 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const Mn          = require('backbone.marionette'); | const Mn          = require('backbone.marionette'); | ||||||
|  | const StreamModel = require('../../../models/stream'); | ||||||
|  | const Api         = require('../../api'); | ||||||
|  | const Controller  = require('../../controller'); | ||||||
|  | const ListView    = require('./list/main'); | ||||||
|  | const ErrorView   = require('../../error/main'); | ||||||
| const template    = require('./main.ejs'); | const template    = require('./main.ejs'); | ||||||
|  | const EmptyView   = require('../../empty/main'); | ||||||
|  |  | ||||||
| module.exports = Mn.View.extend({ | module.exports = Mn.View.extend({ | ||||||
|  |     id:       'nginx-streams', | ||||||
|     template: template, |     template: template, | ||||||
|     id:       'nginx-stream' |  | ||||||
|  |     ui: { | ||||||
|  |         list_region: '.list-region', | ||||||
|  |         add:         '.add-item', | ||||||
|  |         dimmer:      '.dimmer' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     regions: { | ||||||
|  |         list_region: '@ui.list_region' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.add': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.showNginxStreamForm(); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         Api.Nginx.RedirectionHosts.getAll() | ||||||
|  |             .then(response => { | ||||||
|  |                 if (!view.isDestroyed()) { | ||||||
|  |                     if (response && response.length) { | ||||||
|  |                         view.showChildView('list_region', new ListView({ | ||||||
|  |                             collection: new StreamModel.Collection(response) | ||||||
|  |                         })); | ||||||
|  |                     } else { | ||||||
|  |                         view.showChildView('list_region', new EmptyView({ | ||||||
|  |                             title:    'There are no Streams', | ||||||
|  |                             subtitle: 'Why don\'t you create one?', | ||||||
|  |                             link:     'Add Stream', | ||||||
|  |                             action:   function () { | ||||||
|  |                                 Controller.showNginxStreamForm(); | ||||||
|  |                             } | ||||||
|  |                         })); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(err => { | ||||||
|  |                 view.showChildView('list_region', new ErrorView({ | ||||||
|  |                     code:    err.code, | ||||||
|  |                     message: err.message, | ||||||
|  |                     retry:   function () { | ||||||
|  |                         Controller.showNginxStream(); | ||||||
|  |                     } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ module.exports = Mn.AppRouter.extend({ | |||||||
|         logout:              'logout', |         logout:              'logout', | ||||||
|         'nginx/proxy':       'showNginxProxy', |         'nginx/proxy':       'showNginxProxy', | ||||||
|         'nginx/redirection': 'showNginxRedirection', |         'nginx/redirection': 'showNginxRedirection', | ||||||
|         'nginx/404':         'showNginx404', |         'nginx/404':         'showNginxDead', | ||||||
|         'nginx/stream':      'showNginxStream', |         'nginx/stream':      'showNginxStream', | ||||||
|         'nginx/access':      'showNginxAccess', |         'nginx/access':      'showNginxAccess', | ||||||
|         '*default':          'showDashboard' |         '*default':          'showDashboard' | ||||||
|   | |||||||
| @@ -51,5 +51,9 @@ module.exports = Mn.View.extend({ | |||||||
|  |  | ||||||
|             return 'Sign out'; |             return 'Sign out'; | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(Cache.User, 'change', this.render); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -8,15 +8,28 @@ | |||||||
|                 <li class="nav-item dropdown"> |                 <li class="nav-item dropdown"> | ||||||
|                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-monitor"></i> Hosts</a> |                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-monitor"></i> Hosts</a> | ||||||
|                     <div class="dropdown-menu dropdown-menu-arrow"> |                     <div class="dropdown-menu dropdown-menu-arrow"> | ||||||
|  |                         <% if (canShow('proxy_hosts')) { %> | ||||||
|                         <a href="/nginx/proxy" class="dropdown-item ">Proxy Hosts</a> |                         <a href="/nginx/proxy" class="dropdown-item ">Proxy Hosts</a> | ||||||
|  |                         <% } %> | ||||||
|  |  | ||||||
|  |                         <% if (canShow('redirection_hosts')) { %> | ||||||
|                         <a href="/nginx/redirection" class="dropdown-item ">Redirections</a> |                         <a href="/nginx/redirection" class="dropdown-item ">Redirections</a> | ||||||
|  |                         <% } %> | ||||||
|  |  | ||||||
|  |                         <% if (canShow('streams')) { %> | ||||||
|                         <a href="/nginx/stream" class="dropdown-item ">Streams</a> |                         <a href="/nginx/stream" class="dropdown-item ">Streams</a> | ||||||
|  |                         <% } %> | ||||||
|  |  | ||||||
|  |                         <% if (canShow('dead_hosts')) { %> | ||||||
|                         <a href="/nginx/404" class="dropdown-item ">404 Hosts</a> |                         <a href="/nginx/404" class="dropdown-item ">404 Hosts</a> | ||||||
|  |                         <% } %> | ||||||
|                     </div> |                     </div> | ||||||
|                 </li> |                 </li> | ||||||
|  |                 <% if (canShow('access_lists')) { %> | ||||||
|                 <li class="nav-item"> |                 <li class="nav-item"> | ||||||
|                     <a href="/nginx/access" class="nav-link"><i class="fe fe-lock"></i> Access Lists</a> |                     <a href="/nginx/access" class="nav-link"><i class="fe fe-lock"></i> Access Lists</a> | ||||||
|                 </li> |                 </li> | ||||||
|  |                 <% } %> | ||||||
|                 <% if (showUsers()) { %> |                 <% if (showUsers()) { %> | ||||||
|                 <li class="nav-item"> |                 <li class="nav-item"> | ||||||
|                     <a href="/users" class="nav-link"><i class="fe fe-users"></i> Users</a> |                     <a href="/users" class="nav-link"><i class="fe fe-users"></i> Users</a> | ||||||
|   | |||||||
| @@ -17,14 +17,25 @@ module.exports = Mn.View.extend({ | |||||||
|  |  | ||||||
|     events: { |     events: { | ||||||
|         'click @ui.links': function (e) { |         'click @ui.links': function (e) { | ||||||
|  |             let href = $(e.currentTarget).attr('href'); | ||||||
|  |             if (href !== '#') { | ||||||
|                 e.preventDefault(); |                 e.preventDefault(); | ||||||
|             Controller.navigate($(e.currentTarget).attr('href'), true); |                 Controller.navigate(href, true); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     templateContext: { |     templateContext: { | ||||||
|         showUsers: function () { |         showUsers: function () { | ||||||
|             return Cache.User.isAdmin(); |             return Cache.User.isAdmin(); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         canShow: function (perm) { | ||||||
|  |             return Cache.User.isAdmin() || Cache.User.canView(perm); | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     initialize: function () { | ||||||
|  |         this.listenTo(Cache.User, 'change', this.render); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ module.exports = Mn.View.extend({ | |||||||
|  |  | ||||||
|     ui: { |     ui: { | ||||||
|         list_region: '.list-region', |         list_region: '.list-region', | ||||||
|         add_user:    '.add-user', |         add:         '.add-item', | ||||||
|         dimmer:      '.dimmer' |         dimmer:      '.dimmer' | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
| @@ -22,7 +22,7 @@ module.exports = Mn.View.extend({ | |||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     events: { |     events: { | ||||||
|         'click @ui.add_user': function (e) { |         'click @ui.add': function (e) { | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|             Controller.showUserForm(new UserModel.Model()); |             Controller.showUserForm(new UserModel.Model()); | ||||||
|         } |         } | ||||||
| @@ -37,15 +37,19 @@ module.exports = Mn.View.extend({ | |||||||
|                     view.showChildView('list_region', new ListView({ |                     view.showChildView('list_region', new ListView({ | ||||||
|                         collection: new UserModel.Collection(response) |                         collection: new UserModel.Collection(response) | ||||||
|                     })); |                     })); | ||||||
|  |  | ||||||
|                     // Remove loader |  | ||||||
|                     view.ui.dimmer.removeClass('active'); |  | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
|             .catch(err => { |             .catch(err => { | ||||||
|                 console.log(err); |                 view.showChildView('list_region', new ErrorView({ | ||||||
|                 //Controller.showError(err, 'Could not fetch Users'); |                     code:      err.code, | ||||||
|                 //view.trigger('loaded'); |                     message:   err.message, | ||||||
|  |                     retry:     function () { Controller.showUsers(); } | ||||||
|  |                 })); | ||||||
|  |  | ||||||
|  |                 console.error(err); | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 view.ui.dimmer.removeClass('active'); | ||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								src/frontend/js/models/dead-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/frontend/js/models/dead-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Backbone = require('backbone'); | ||||||
|  |  | ||||||
|  | const model = Backbone.Model.extend({ | ||||||
|  |     idAttribute: 'id', | ||||||
|  |  | ||||||
|  |     defaults: function () { | ||||||
|  |         return { | ||||||
|  |             created_on:          null, | ||||||
|  |             modified_on:         null, | ||||||
|  |             owner:               null, | ||||||
|  |             domain_name:         '', | ||||||
|  |             ssl_enabled:         false, | ||||||
|  |             ssl_provider:        false, | ||||||
|  |             meta:                [] | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     Model:      model, | ||||||
|  |     Collection: Backbone.Collection.extend({ | ||||||
|  |         model: model | ||||||
|  |     }) | ||||||
|  | }; | ||||||
							
								
								
									
										32
									
								
								src/frontend/js/models/proxy-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/frontend/js/models/proxy-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Backbone = require('backbone'); | ||||||
|  |  | ||||||
|  | const model = Backbone.Model.extend({ | ||||||
|  |     idAttribute: 'id', | ||||||
|  |  | ||||||
|  |     defaults: function () { | ||||||
|  |         return { | ||||||
|  |             created_on:      null, | ||||||
|  |             modified_on:     null, | ||||||
|  |             owner:           null, | ||||||
|  |             domain_name:     '', | ||||||
|  |             forward_ip:      '', | ||||||
|  |             forward_port:    0, | ||||||
|  |             access_list_id:  0, | ||||||
|  |             ssl_enabled:     false, | ||||||
|  |             ssl_provider:    false, | ||||||
|  |             ssl_forced:      false, | ||||||
|  |             caching_enabled: false, | ||||||
|  |             block_exploits:  false, | ||||||
|  |             meta:            [] | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     Model:      model, | ||||||
|  |     Collection: Backbone.Collection.extend({ | ||||||
|  |         model: model | ||||||
|  |     }) | ||||||
|  | }; | ||||||
							
								
								
									
										29
									
								
								src/frontend/js/models/redirection-host.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/models/redirection-host.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Backbone = require('backbone'); | ||||||
|  |  | ||||||
|  | const model = Backbone.Model.extend({ | ||||||
|  |     idAttribute: 'id', | ||||||
|  |  | ||||||
|  |     defaults: function () { | ||||||
|  |         return { | ||||||
|  |             created_on:          null, | ||||||
|  |             modified_on:         null, | ||||||
|  |             owner:               null, | ||||||
|  |             domain_name:         '', | ||||||
|  |             forward_domain_name: '', | ||||||
|  |             preserve_path:       false, | ||||||
|  |             ssl_enabled:         false, | ||||||
|  |             ssl_provider:        false, | ||||||
|  |             block_exploits:      false, | ||||||
|  |             meta:                [] | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     Model:      model, | ||||||
|  |     Collection: Backbone.Collection.extend({ | ||||||
|  |         model: model | ||||||
|  |     }) | ||||||
|  | }; | ||||||
							
								
								
									
										28
									
								
								src/frontend/js/models/stream.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/frontend/js/models/stream.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Backbone = require('backbone'); | ||||||
|  |  | ||||||
|  | const model = Backbone.Model.extend({ | ||||||
|  |     idAttribute: 'id', | ||||||
|  |  | ||||||
|  |     defaults: function () { | ||||||
|  |         return { | ||||||
|  |             created_on:      null, | ||||||
|  |             modified_on:     null, | ||||||
|  |             owner:           null, | ||||||
|  |             incoming_port:   0, | ||||||
|  |             forward_ip:      '', | ||||||
|  |             forwarding_port: 0, | ||||||
|  |             tcp_forwarding:  true, | ||||||
|  |             udp_forwarding:  false, | ||||||
|  |             meta:            [] | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     Model:      model, | ||||||
|  |     Collection: Backbone.Collection.extend({ | ||||||
|  |         model: model | ||||||
|  |     }) | ||||||
|  | }; | ||||||
| @@ -17,8 +17,33 @@ const model = Backbone.Model.extend({ | |||||||
|         }; |         }; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      */ | ||||||
|     isAdmin: function () { |     isAdmin: function () { | ||||||
|         return _.indexOf(this.get('roles'), 'admin') !== -1; |         return _.indexOf(this.get('roles'), 'admin') !== -1; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Checks if the perm has either `view` or `manage` value | ||||||
|  |      * | ||||||
|  |      * @param   {String}  item | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      */ | ||||||
|  |     canView: function (item) { | ||||||
|  |         let permissions = this.get('permissions'); | ||||||
|  |         return permissions !== null && typeof permissions[item] !== 'undefined' && ['view', 'manage'].indexOf(permissions[item]) !== -1; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Checks if the perm has `manage` value | ||||||
|  |      * | ||||||
|  |      * @param   {String}  item | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      */ | ||||||
|  |     canManage: function (item) { | ||||||
|  |         let permissions = this.get('permissions'); | ||||||
|  |         return permissions !== null && typeof permissions[item] !== 'undefined' && permissions[item] === 'manage'; | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user