Jamie Curnow 7 lat temu
rodzic
commit
9da3bafd4c

+ 13 - 0
src/frontend/js/app/controller.js

@@ -214,6 +214,19 @@ module.exports = {
         }
     },
 
+    /**
+     * Nginx Stream Form
+     *
+     * @param [model]
+     */
+    showNginxStreamForm: function (model) {
+        if (Cache.User.isAdmin() || Cache.User.canManage('proxy_hosts')) {
+            require(['./main', './nginx/stream/form'], function (App, View) {
+                App.UI.showModalDialog(new View({model: model}));
+            });
+        }
+    },
+
     /**
      * Nginx Dead Hosts
      */

+ 19 - 0
src/frontend/js/app/nginx/stream/delete.ejs

@@ -0,0 +1,19 @@
+<div class="modal-content">
+    <div class="modal-header">
+        <h5 class="modal-title"><%- i18n('streams', 'delete') %></h5>
+        <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
+    </div>
+    <div class="modal-body">
+        <form>
+            <div class="row">
+                <div class="col-sm-12 col-md-12">
+                    <%= i18n('streams', 'delete-confirm') %>
+                </div>
+            </div>
+        </form>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
+        <button type="button" class="btn btn-danger save"><%- i18n('str', 'sure') %></button>
+    </div>
+</div>

+ 36 - 0
src/frontend/js/app/nginx/stream/delete.js

@@ -0,0 +1,36 @@
+'use strict';
+
+const Mn       = require('backbone.marionette');
+const App      = require('../../main');
+const template = require('./delete.ejs');
+
+require('jquery-serializejson');
+
+module.exports = Mn.View.extend({
+    template:  template,
+    className: 'modal-dialog',
+
+    ui: {
+        form:    'form',
+        buttons: '.modal-footer button',
+        cancel:  'button.cancel',
+        save:    'button.save'
+    },
+
+    events: {
+
+        'click @ui.save': function (e) {
+            e.preventDefault();
+
+            App.Api.Nginx.Streams.delete(this.model.get('id'))
+                .then(() => {
+                    App.Controller.showNginxStream();
+                    App.UI.closeModal();
+                })
+                .catch(err => {
+                    alert(err.message);
+                    this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
+                });
+        }
+    }
+});

+ 52 - 0
src/frontend/js/app/nginx/stream/form.ejs

@@ -0,0 +1,52 @@
+<div class="modal-content">
+    <div class="modal-header">
+        <h5 class="modal-title"><%- i18n('streams', 'form-title', {id: id}) %></h5>
+        <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
+    </div>
+    <div class="modal-body">
+        <form>
+            <div class="row">
+                <div class="col-sm-12 col-md-12">
+                    <div class="form-group">
+                        <label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
+                        <input name="incoming_port" type="number" class="form-control text-monospace" placeholder="8080" value="<%- incoming_port %>" required>
+                    </div>
+                </div>
+                <div class="col-sm-8 col-md-8">
+                    <div class="form-group">
+                        <label class="form-label"><%- i18n('streams', 'forward-ip') %><span class="form-required">*</span></label>
+                        <input type="text" name="forward_ip" class="form-control text-monospace" placeholder="000.000.000.000" value="<%- forward_ip %>" autocomplete="off" maxlength="15" required>
+                    </div>
+                </div>
+                <div class="col-sm-4 col-md-4">
+                    <div class="form-group">
+                        <label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
+                        <input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="80" value="<%- forwarding_port %>" required>
+                    </div>
+                </div>
+                <div class="col-sm-6 col-md-6">
+                    <div class="form-group">
+                        <label class="custom-switch">
+                            <input type="checkbox" class="custom-switch-input" name="tcp_forwarding" value="1"<%- tcp_forwarding ? ' checked' : '' %>>
+                            <span class="custom-switch-indicator"></span>
+                            <span class="custom-switch-description"><%- i18n('streams', 'tcp-forwarding') %></span>
+                        </label>
+                    </div>
+                </div>
+                <div class="col-sm-6 col-md-6">
+                    <div class="form-group">
+                        <label class="custom-switch">
+                            <input type="checkbox" class="custom-switch-input" name="udp_forwarding" value="1"<%- udp_forwarding ? ' checked' : '' %>>
+                            <span class="custom-switch-indicator"></span>
+                            <span class="custom-switch-description"><%- i18n('streams', 'udp_forwarding') %></span>
+                        </label>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <div class="modal-footer">
+        <button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
+        <button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
+    </div>
+</div>

+ 93 - 0
src/frontend/js/app/nginx/stream/form.js

@@ -0,0 +1,93 @@
+'use strict';
+
+const _           = require('underscore');
+const Mn          = require('backbone.marionette');
+const App         = require('../../main');
+const StreamModel = require('../../../models/stream');
+const template    = require('./form.ejs');
+
+require('jquery-serializejson');
+require('jquery-mask-plugin');
+require('selectize');
+
+module.exports = Mn.View.extend({
+    template:      template,
+    className:     'modal-dialog',
+    max_file_size: 5120,
+
+    ui: {
+        form:       'form',
+        forward_ip: 'input[name="forward_ip"]',
+        buttons:    '.modal-footer button',
+        cancel:     'button.cancel',
+        save:       'button.save'
+    },
+
+    events: {
+        'click @ui.save': function (e) {
+            e.preventDefault();
+
+            if (!this.ui.form[0].checkValidity()) {
+                $('<input type="submit">').hide().appendTo(this.ui.form).click().remove();
+                return;
+            }
+
+            let view = this;
+            let data = this.ui.form.serializeJSON();
+
+            // Manipulate
+            data.forward_port = parseInt(data.forward_port, 10);
+            _.map(data, function (item, idx) {
+                if (typeof item === 'string' && item === '1') {
+                    item = true;
+                } else if (typeof item === 'object' && item !== null) {
+                    _.map(item, function (item2, idx2) {
+                        if (typeof item2 === 'string' && item2 === '1') {
+                            item[idx2] = true;
+                        }
+                    });
+                }
+                data[idx] = item;
+            });
+
+            let method = App.Api.Nginx.Streams.create;
+            let is_new = true;
+
+            if (this.model.get('id')) {
+                // edit
+                is_new  = false;
+                method  = App.Api.Nginx.Streams.update;
+                data.id = this.model.get('id');
+            }
+
+            this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
+            method(data)
+                .then(result => {
+                    view.model.set(result);
+
+                    App.UI.closeModal(function () {
+                        if (is_new) {
+                            App.Controller.showNginxStream();
+                        }
+                    });
+                })
+                .catch(err => {
+                    alert(err.message);
+                    this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
+                });
+        }
+    },
+
+    onRender: function () {
+        this.ui.forward_ip.mask('099.099.099.099', {
+            clearIfNotMatch: true,
+            placeholder:     '000.000.000.000'
+        });
+    },
+
+    initialize: function (options) {
+        if (typeof options.model === 'undefined' || !options.model) {
+            this.model = new StreamModel.Model();
+        }
+    }
+});

+ 21 - 13
src/frontend/js/app/nginx/stream/list/item.ejs

@@ -1,32 +1,40 @@
 <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 class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
+        <span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
     </div>
 </td>
 <td>
-    <div><%- name %></div>
+    <div>
+        <% domain_names.map(function(host) {
+            %>
+            <span class="tag"><%- host %></span>
+            <%
+        });
+        %>
+    </div>
     <div class="small text-muted">
-        Created: <%- formatDbDate(created_on, 'Do MMMM YYYY') %>
+        <%- i18n('str', 'created-on', {date: formatDbDate(created_on, 'Do MMMM YYYY')}) %>
     </div>
 </td>
 <td>
-    <div><%- email %></div>
+    <div class="text-monospace"><%- forward_ip %>:<%- forward_port %></div>
+</td>
+<td>
+    <div><%- ssl_enabled && ssl_provider ? i18n('ssl', ssl_provider) : i18n('ssl', 'none') %></div>
 </td>
 <td>
-    <div><%- roles.join(', ') %></div>
+    <div><%- access_list_id ? access_list.name : i18n('str', 'public') %></div>
 </td>
+<% if (canManage) { %>
 <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>
+            <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
+            <a href="#" class="logs dropdown-item"><i class="dropdown-icon fe fe-book"></i> <%- i18n('str', 'logs') %></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>
-            <% } %>
+            <a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
         </div>
     </div>
 </td>
+<% } %>

+ 8 - 45
src/frontend/js/app/nginx/stream/list/item.js

@@ -1,69 +1,32 @@
 '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');
+const Mn       = require('backbone.marionette');
+const App      = require('../../../main');
+const template = require('./item.ejs');
 
 module.exports = Mn.View.extend({
     template: template,
     tagName:  'tr',
 
     ui: {
-        edit:        'a.edit-user',
-        permissions: 'a.edit-permissions',
-        password:    'a.set-password',
-        login:       'a.login',
-        delete:      'a.delete-user'
+        edit:   'a.edit',
+        delete: 'a.delete'
     },
 
     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);
+            App.Controller.showNginxProxyForm(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');
-                    });
-            }
+            App.Controller.showNginxProxyDeleteConfirm(this.model);
         }
     },
 
     templateContext: {
-        isSelf: function () {
-            return Cache.User.get('id') === this.id;
-        }
+        canManage: App.Cache.User.canManage('proxy_hosts')
     },
 
     initialize: function () {

+ 6 - 3
src/frontend/js/app/nginx/stream/list/main.ejs

@@ -1,9 +1,12 @@
 <thead>
     <th width="30">&nbsp;</th>
-    <th>Name</th>
-    <th>Email</th>
-    <th>Roles</th>
+    <th><%- i18n('str', 'source') %></th>
+    <th><%- i18n('str', 'destination') %></th>
+    <th><%- i18n('str', 'ssl') %></th>
+    <th><%- i18n('str', 'access') %></th>
+    <% if (canManage) { %>
     <th>&nbsp;</th>
+    <% } %>
 </thead>
 <tbody>
     <!-- items -->

+ 8 - 3
src/frontend/js/app/nginx/stream/list/main.js

@@ -1,8 +1,9 @@
 'use strict';
 
-const Mn         = require('backbone.marionette');
-const ItemView   = require('./item');
-const template   = require('./main.ejs');
+const Mn       = require('backbone.marionette');
+const App      = require('../../../main');
+const ItemView = require('./item');
+const template = require('./main.ejs');
 
 const TableBody = Mn.CollectionView.extend({
     tagName:   'tbody',
@@ -21,6 +22,10 @@ module.exports = Mn.View.extend({
         }
     },
 
+    templateContext: {
+        canManage: App.Cache.User.canManage('proxy_hosts')
+    },
+
     onRender: function () {
         this.showChildView('body', new TableBody({
             collection: this.collection

+ 2 - 2
src/frontend/js/app/nginx/stream/main.ejs

@@ -1,10 +1,10 @@
 <div class="card">
     <div class="card-status bg-blue"></div>
     <div class="card-header">
-        <h3 class="card-title">Streams</h3>
+        <h3 class="card-title"><%- i18n('streams', 'title') %></h3>
         <div class="card-options">
             <% if (showAddButton) { %>
-            <a href="#" class="btn btn-outline-blue btn-sm ml-2 add-item">Add Stream</a>
+            <a href="#" class="btn btn-outline-blue btn-sm ml-2 add-item"><%- i18n('streams', 'add') %></a>
             <% } %>
         </div>
     </div>

+ 15 - 16
src/frontend/js/app/nginx/stream/main.js

@@ -1,17 +1,15 @@
 'use strict';
 
 const Mn          = require('backbone.marionette');
+const App         = require('../../main');
 const StreamModel = require('../../../models/stream');
-const Api         = require('../../api');
-const Cache       = require('../../cache');
-const Controller  = require('../../controller');
 const ListView    = require('./list/main');
 const ErrorView   = require('../../error/main');
-const template    = require('./main.ejs');
 const EmptyView   = require('../../empty/main');
+const template    = require('./main.ejs');
 
 module.exports = Mn.View.extend({
-    id:       'nginx-streams',
+    id:       'nginx-stream',
     template: template,
 
     ui: {
@@ -27,18 +25,18 @@ module.exports = Mn.View.extend({
     events: {
         'click @ui.add': function (e) {
             e.preventDefault();
-            Controller.showNginxStreamForm();
+            App.Controller.showNginxStreamForm();
         }
     },
 
     templateContext: {
-        showAddButton: Cache.User.canManage('streams')
+        showAddButton: App.Cache.User.canManage('streams')
     },
 
     onRender: function () {
         let view = this;
 
-        Api.Nginx.RedirectionHosts.getAll()
+        App.Api.Nginx.Streams.getAll(['owner'])
             .then(response => {
                 if (!view.isDestroyed()) {
                     if (response && response.length) {
@@ -46,15 +44,16 @@ module.exports = Mn.View.extend({
                             collection: new StreamModel.Collection(response)
                         }));
                     } else {
-                        let manage = Cache.User.canManage('streams');
+                        let manage = App.Cache.User.canManage('streams');
 
                         view.showChildView('list_region', new EmptyView({
-                            title:     'There are no Streams',
-                            subtitle:  manage ? 'Why don\'t you create one?' : 'And you don\'t have permission to create one.',
-                            link:      manage ? 'Add Stream' : null,
-                            btn_color: 'blue',
-                            action:    function () {
-                                Controller.showNginxStreamForm();
+                            title:      App.i18n('streams', 'empty'),
+                            subtitle:   App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
+                            link:       manage ? App.i18n('streams', 'add') : null,
+                            btn_color:  'blue',
+                            permission: 'streams',
+                            action:     function () {
+                                App.Controller.showNginxStreamForm();
                             }
                         }));
                     }
@@ -65,7 +64,7 @@ module.exports = Mn.View.extend({
                     code:    err.code,
                     message: err.message,
                     retry:   function () {
-                        Controller.showNginxStream();
+                        App.Controller.showNginxStream();
                     }
                 }));
 

+ 3 - 1
src/frontend/js/i18n/messages.json

@@ -97,7 +97,9 @@
       "title": "404 Hosts"
     },
     "streams": {
-      "title": "Streams"
+      "title": "Streams",
+      "empty": "There are no Streams",
+      "add": "Add Stream"
     },
     "access-lists": {
       "title": "Access Lists",

+ 3 - 3
src/frontend/js/models/stream.js

@@ -11,12 +11,12 @@ const model = Backbone.Model.extend({
             created_on:      null,
             modified_on:     null,
             owner:           null,
-            incoming_port:   0,
+            incoming_port:   3000,
             forward_ip:      '',
-            forwarding_port: 0,
+            forwarding_port: 3000,
             tcp_forwarding:  true,
             udp_forwarding:  false,
-            meta:            []
+            meta:            {}
         };
     }
 });