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

This commit is contained in:
Julian Gassner 2024-12-04 03:45:56 +01:00
parent 8351dd41f6
commit 080bd0b749
10 changed files with 96 additions and 27 deletions

View File

@ -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') {

View File

@ -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);
}
}
};
}

View File

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

View File

@ -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,6 +55,13 @@
<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>

View File

@ -44,14 +44,24 @@ module.exports = Mn.View.extend({
},
},
templateContext: {
templateContext: function () {
return {
canManage: App.Cache.User.canManage('certificates'),
isExpired: function () {
return moment(this.expires_on).isBefore(moment());
},
dns_providers: dns_providers
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);
}

View File

@ -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>
<% } %>

View File

@ -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) {

View File

@ -1,10 +1,10 @@
<div class="modal-content">
<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">
<form>
<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>
<button type="submit" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
</div>
</form>
</div>

View File

@ -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;

View File

@ -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",