Prechádzať zdrojové kódy

Added status of certificates to the certificate list and show on which domain names the certificates are in use

Julian Gassner 1 rok pred
rodič
commit
080bd0b749

+ 6 - 0
backend/internal/certificate.js

@@ -313,6 +313,9 @@ const internalCertificate = {
 					.where('is_deleted', 0)
 					.andWhere('id', data.id)
 					.allowGraph('[owner]')
+					.allowGraph('[proxy_hosts]')
+					.allowGraph('[redirection_hosts]')
+					.allowGraph('[dead_hosts]')
 					.first();
 
 				if (access_data.permission_visibility !== 'all') {
@@ -464,6 +467,9 @@ const internalCertificate = {
 					.where('is_deleted', 0)
 					.groupBy('id')
 					.allowGraph('[owner]')
+					.allowGraph('[proxy_hosts]')
+					.allowGraph('[redirection_hosts]')
+					.allowGraph('[dead_hosts]')
 					.orderBy('nice_name', 'ASC');
 
 				if (access_data.permission_visibility !== 'all') {

+ 38 - 1
backend/models/certificate.js

@@ -4,7 +4,6 @@
 const db      = require('../db');
 const helpers = require('../lib/helpers');
 const Model   = require('objection').Model;
-const User    = require('./user');
 const now     = require('./now_helper');
 
 Model.knex(db);
@@ -68,6 +67,11 @@ class Certificate extends Model {
 	}
 
 	static get relationMappings () {
+		const ProxyHost 	  = require('./proxy_host');
+		const DeadHost 		  = require('./dead_host');
+		const User      	  = require('./user');
+		const RedirectionHost = require('./redirection_host');
+
 		return {
 			owner: {
 				relation:   Model.HasOneRelation,
@@ -79,6 +83,39 @@ class Certificate extends Model {
 				modify: function (qb) {
 					qb.where('user.is_deleted', 0);
 				}
+			},
+			proxy_hosts: {
+				relation:   Model.HasManyRelation,
+				modelClass: ProxyHost,
+				join:       {
+					from: 'certificate.id',
+					to:   'proxy_host.certificate_id'
+				},
+				modify: function (qb) {
+					qb.where('proxy_host.is_deleted', 0);
+				}
+			},
+			dead_hosts: {
+				relation:   Model.HasManyRelation,
+				modelClass: DeadHost,
+				join:       {
+					from: 'certificate.id',
+					to:   'dead_host.certificate_id'
+				},
+				modify: function (qb) {
+					qb.where('dead_host.is_deleted', 0);
+				}
+			},
+			redirection_hosts: {
+				relation:   Model.HasManyRelation,
+				modelClass: RedirectionHost,
+				join:       {
+					from: 'certificate.id',
+					to:   'redirection_host.certificate_id'
+				},
+				modify: function (qb) {
+					qb.where('redirection_host.is_deleted', 0);
+				}
 			}
 		};
 	}

+ 1 - 3
frontend/js/app/dashboard/main.js

@@ -50,8 +50,7 @@ module.exports = Mn.View.extend({
     onRender: function () {
         let view = this;
 
-        if (typeof view.stats.hosts === 'undefined') {
-            Api.Reports.getHostStats()
+        Api.Reports.getHostStats()
                 .then(response => {
                     if (!view.isDestroyed()) {
                         view.stats.hosts = response;
@@ -61,7 +60,6 @@ module.exports = Mn.View.extend({
                 .catch(err => {
                     console.log(err);
                 });
-        }
     },
 
     /**

+ 15 - 1
frontend/js/app/nginx/certificates/list/item.ejs

@@ -33,6 +33,13 @@
 <td class="<%- isExpired() ? 'text-danger' : '' %>">
     <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
 </td>
+<td>
+    <% if (active_domain_names().length > 0) { %>
+        <span class="status-icon bg-success"></span> <%- i18n('certificates', 'in-use') %>
+    <% } else { %>
+        <span class="status-icon bg-danger"></span> <%- i18n('certificates', 'inactive') %>
+    <% } %>
+</td>
 <% if (canManage) { %>
 <td class="text-right">
     <div class="item-action dropdown">
@@ -48,7 +55,14 @@
                 <div class="dropdown-divider"></div>
             <% } %>
             <a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
+            <% if (active_domain_names().length > 0) { %>
+                <div class="dropdown-divider"></div>
+                <span class="dropdown-header"><%- i18n('certificates', 'active-domain_names') %></span>
+                <% active_domain_names().forEach(function(host) { %>
+                    <a href="https://<%- host %>" class="dropdown-item" target="_blank"><%- host %></a>
+                <% }); %>
+            <% } %>
         </div>
     </div>
 </td>
-<% } %>
+<% } %>

+ 16 - 6
frontend/js/app/nginx/certificates/list/item.js

@@ -44,14 +44,24 @@ module.exports = Mn.View.extend({
         },
     },
 
-    templateContext: {
-        canManage: App.Cache.User.canManage('certificates'),
-        isExpired: function () {
-            return moment(this.expires_on).isBefore(moment());
-        },
-        dns_providers: dns_providers
+    templateContext: function () {
+        return {
+            canManage: App.Cache.User.canManage('certificates'),
+            isExpired: function () {
+                return moment(this.expires_on).isBefore(moment());
+            },
+            dns_providers: dns_providers,
+            active_domain_names: function () {
+                const { proxy_hosts = [], redirect_hosts = [], dead_hosts = [] } = this;
+                return [...proxy_hosts, ...redirect_hosts, ...dead_hosts].reduce((acc, host) => {
+                    acc.push(...(host.domain_names || []));
+                    return acc;
+                }, []);
+            }
+        };
     },
 
+
     initialize: function () {
         this.listenTo(this.model, 'change', this.render);
     }

+ 1 - 0
frontend/js/app/nginx/certificates/list/main.ejs

@@ -3,6 +3,7 @@
     <th><%- i18n('str', 'name') %></th>
     <th><%- i18n('all-hosts', 'cert-provider') %></th>
     <th><%- i18n('str', 'expires') %></th>
+    <th><%- i18n('str', 'status') %></th>
     <% if (canManage) { %>
     <th>&nbsp;</th>
     <% } %>

+ 2 - 2
frontend/js/app/nginx/certificates/main.js

@@ -74,7 +74,7 @@ module.exports = Mn.View.extend({
             e.preventDefault();
             let query = this.ui.query.val();
 
-            this.fetch(['owner'], query)
+            this.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'], query)
                 .then(response => this.showData(response))
                 .catch(err => {
                     this.showError(err);
@@ -89,7 +89,7 @@ module.exports = Mn.View.extend({
     onRender: function () {
         let view = this;
 
-        view.fetch(['owner'])
+        view.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'])
             .then(response => {
                 if (!view.isDestroyed()) {
                     if (response && response.length) {

+ 12 - 12
frontend/js/app/user/form.ejs

@@ -1,10 +1,10 @@
 <div class="modal-content">
-    <div class="modal-header">
-        <h5 class="modal-title"><%- i18n('users', '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>
+    <form>
+        <div class="modal-header">
+            <h5 class="modal-title"><%- i18n('users', 'form-title', {id: id}) %></h5>
+            <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
+        </div>
+        <div class="modal-body">
             <div class="row">
                 <div class="col-sm-6 col-md-6">
                     <div class="form-group">
@@ -49,10 +49,10 @@
                 </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>
+        <div class="modal-footer">
+            <button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
+            <button type="submit" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
+        </div>
+    </form>
 </div>

+ 1 - 1
frontend/js/app/user/form.js

@@ -19,7 +19,7 @@ module.exports = Mn.View.extend({
 
     events: {
 
-        'click @ui.save': function (e) {
+        'submit @ui.form': function (e) {
             e.preventDefault();
             this.ui.error.hide();
             let view = this;

+ 4 - 1
frontend/js/i18n/messages.json

@@ -206,7 +206,10 @@
       "reachability-other": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.",
       "download": "Download",
       "renew-title": "Renew Let's Encrypt Certificate",
-      "search": "Search Certificate…"
+      "search": "Search Certificate…",
+      "in-use"  : "In use",
+      "inactive": "Inactive",
+      "active-domain_names": "Active domain names"
     },
     "access-lists": {
       "title": "Access Lists",