scripts for setup, nginx and service, fixing issue with server shutdown when both are running
This commit is contained in:
@@ -4,6 +4,30 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Current IP Detection -->
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-geo-alt me-2"></i>
|
||||
Your Current IP
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<div class="fw-bold font-monospace fs-5 mb-2" id="current-ip">
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
Detecting...
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="useCurrentIP()">
|
||||
<i class="bi bi-arrow-up me-1"></i>
|
||||
Use This IP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="card">
|
||||
@@ -73,113 +97,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current IP Detection and Available Domains -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-geo-alt me-2"></i>
|
||||
Your Current IP
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<div class="fw-bold font-monospace fs-5 mb-2" id="current-ip">
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
Detecting...
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="useCurrentIP()">
|
||||
<i class="bi bi-arrow-up me-1"></i>
|
||||
Use This IP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if domains %}
|
||||
<div class="col-md-4 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-server me-2"></i>
|
||||
Available Domains
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% for domain in domains %}
|
||||
<div class="mb-2">
|
||||
<div class="fw-bold">{{ domain.domain_name }}</div>
|
||||
<small class="text-muted">
|
||||
Created: {{ domain.created_at.strftime('%Y-%m-%d') }}
|
||||
</small>
|
||||
</div>
|
||||
{% if not loop.last %}<hr class="my-2">{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Example Use Cases -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-lightbulb me-2"></i>
|
||||
Common Use Cases
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-primary">
|
||||
<i class="bi bi-server me-1"></i>
|
||||
Application Servers
|
||||
</h6>
|
||||
<p class="text-muted small">
|
||||
Web applications that need to send transactional emails
|
||||
(password resets, notifications, etc.)
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-success">
|
||||
<i class="bi bi-clock me-1"></i>
|
||||
Scheduled Tasks
|
||||
</h6>
|
||||
<p class="text-muted small">
|
||||
Cron jobs or scheduled scripts that send automated
|
||||
reports or alerts
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-warning">
|
||||
<i class="bi bi-monitor me-1"></i>
|
||||
Monitoring Systems
|
||||
</h6>
|
||||
<p class="text-muted small">
|
||||
Monitoring tools that send alerts and status updates
|
||||
to administrators
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-info">
|
||||
<i class="bi bi-cloud me-1"></i>
|
||||
Cloud Services
|
||||
</h6>
|
||||
<p class="text-muted small">
|
||||
Cloud-based applications or services that need to
|
||||
send emails on behalf of your domain
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
@@ -187,15 +105,22 @@
|
||||
// Detect current IP address
|
||||
async function detectCurrentIP() {
|
||||
try {
|
||||
const response = await fetch('https://api.ipify.org?format=json');
|
||||
const response = await fetch('https://ifconfig.me/all.json');
|
||||
const data = await response.json();
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
`<span class="text-primary">${data.ip}</span>`;
|
||||
} catch (error) {
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
`<span class="text-primary">${data.ip_addr}</span>`;
|
||||
} catch (er) {
|
||||
try {
|
||||
const response = await fetch('https://httpbin.org/ip');
|
||||
const data = await response.json();
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
`<span class="text-primary">${data.origin}</span>`;
|
||||
} catch (error) {
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
'<span class="text-muted">Unable to detect</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useCurrentIP() {
|
||||
const currentIPElement = document.getElementById('current-ip');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Add User - Email Server{% endblock %}
|
||||
{% block title %}Add Sender - Email Server{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="bi bi-person-plus me-2"></i>
|
||||
Add New User
|
||||
Add New Sender
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@@ -50,7 +50,7 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-text">
|
||||
The domain this user belongs to
|
||||
The domain this sender belongs to
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,11 +61,11 @@
|
||||
id="can_send_as_domain"
|
||||
name="can_send_as_domain">
|
||||
<label class="form-check-label" for="can_send_as_domain">
|
||||
<strong>Domain Administrator</strong>
|
||||
<strong>Domain Sender</strong>
|
||||
</label>
|
||||
<div class="form-text">
|
||||
If checked, user can send emails as any address in their domain.
|
||||
Otherwise, user can only send as their own email address.
|
||||
If checked, sender can send emails as any address in their domain.
|
||||
Otherwise, sender can only send as their own email address.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,19 +76,19 @@
|
||||
Permission Levels
|
||||
</h6>
|
||||
<ul class="mb-0">
|
||||
<li><strong>Regular User:</strong> Can only send emails from their own email address</li>
|
||||
<li><strong>Domain Admin:</strong> Can send emails from any address in their domain (e.g., noreply@domain.com, support@domain.com)</li>
|
||||
<li><strong>Regular Sender:</strong> Can only send emails from their own email address</li>
|
||||
<li><strong>Domain Sender:</strong> Can send emails from any address in their domain (e.g., noreply@domain.com, support@domain.com)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ url_for('email.users_list') }}" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i>
|
||||
Back to Users
|
||||
Back to Senders
|
||||
</a>
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-person-plus me-2"></i>
|
||||
Add User
|
||||
Add Sender
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -98,35 +98,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Domain information sidebar -->
|
||||
<div class="row mt-4">
|
||||
{% if domains %}
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Available Domains
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
{% for domain in domains %}
|
||||
<div class="col-md-6 mb-2">
|
||||
<div class="border rounded p-2">
|
||||
<div class="fw-bold">{{ domain.domain_name }}</div>
|
||||
<small class="text-muted">
|
||||
Created: {{ domain.created_at.strftime('%Y-%m-%d') }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
|
||||
@@ -190,12 +190,12 @@
|
||||
{% if item.existing_spf %}
|
||||
<div class="mb-2">
|
||||
<strong>Current SPF:</strong>
|
||||
<div class="dns-record text-info">{{ item.existing_spf }}</div>
|
||||
<div class="dns-record">{{ item.existing_spf }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="mb-2">
|
||||
<strong>Recommended SPF:</strong>
|
||||
<div class="dns-record text-success">{{ item.recommended_spf }}</div>
|
||||
<div class="dns-record">{{ item.recommended_spf }}</div>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary btn-sm" onclick="copyToClipboard('{{ item.recommended_spf }}')">
|
||||
<i class="bi bi-clipboard me-1"></i>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
name="can_send_as_domain"
|
||||
{% if user.can_send_as_domain %}checked{% endif %}>
|
||||
<label class="form-check-label" for="can_send_as_domain">
|
||||
<strong>Can send as domain</strong>
|
||||
<strong>Can send as any email from domain</strong>
|
||||
</label>
|
||||
<div class="form-text">
|
||||
Allow this user to send emails using any address within their domain
|
||||
|
||||
@@ -200,10 +200,10 @@
|
||||
// Detect current IP address
|
||||
async function detectCurrentIP() {
|
||||
try {
|
||||
const response = await fetch('https://api.ipify.org?format=json');
|
||||
const response = await fetch('https://ifconfig.me/all.json');
|
||||
const data = await response.json();
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
`<span class="text-primary">${data.ip}</span>`;
|
||||
`<span class="text-primary">${data.ip_addr}</span>`;
|
||||
} catch (error) {
|
||||
document.getElementById('current-ip').innerHTML =
|
||||
'<span class="text-muted">Unable to detect</span>';
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>
|
||||
<i class="bi bi-journal-text me-2"></i>
|
||||
Server Logs
|
||||
Emails Log
|
||||
</h2>
|
||||
<div class="btn-group">
|
||||
<a href="{{ url_for('email.logs', type='all') }}"
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
Server Settings
|
||||
</h2>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-outline-danger me-2" onclick="restartSmtpServer()" id="restart-smtp-btn">
|
||||
<i class="bi bi-arrow-repeat me-2"></i>
|
||||
Restart SMTP Server
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-warning" onclick="resetToDefaults()">
|
||||
<i class="bi bi-arrow-clockwise me-2"></i>
|
||||
Reset to Defaults
|
||||
@@ -351,5 +355,28 @@
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
function restartSmtpServer() {
|
||||
showConfirmation("Are you sure you want to restart the SMTP server?", "Restart SMTP Server", "Restart", "btn-danger").then(confirmed => {
|
||||
if (!confirmed) return;
|
||||
const btn = document.getElementById('restart-smtp-btn');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Restarting...';
|
||||
fetch('/api/server/restart', {method: 'POST'})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
showToast(data.message || 'SMTP server restarted.', 'success');
|
||||
} else {
|
||||
showToast(data.message || 'Failed to restart SMTP server.', 'danger');
|
||||
}
|
||||
})
|
||||
.catch(() => showToast('Failed to restart SMTP server.', 'danger'))
|
||||
.finally(() => {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="bi bi-arrow-repeat me-2"></i> Restart SMTP Server';
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<li class="nav-item mb-2">
|
||||
<h6 class="text-muted text-uppercase small mb-2 mt-3">
|
||||
<i class="bi bi-globe me-1"></i>
|
||||
Domain Management
|
||||
Email Server Management
|
||||
</h6>
|
||||
</li>
|
||||
|
||||
@@ -38,20 +38,12 @@
|
||||
<span class="badge bg-secondary ms-auto">{{ domain_count if domain_count is defined else '' }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Authentication Section -->
|
||||
<li class="nav-item mb-2">
|
||||
<h6 class="text-muted text-uppercase small mb-2 mt-3">
|
||||
<i class="bi bi-shield-lock me-1"></i>
|
||||
Authentication
|
||||
</h6>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="nav-item mb-1">
|
||||
<a href="{{ url_for('email.users_list') }}"
|
||||
class="nav-link text-white {{ 'active' if request.endpoint in ['email.users_list', 'email.add_user'] else '' }}">
|
||||
<i class="bi bi-people me-2"></i>
|
||||
Users
|
||||
Allowed Senders
|
||||
<span class="badge bg-secondary ms-auto">{{ user_count if user_count is defined else '' }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@@ -65,14 +57,6 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- DKIM Section -->
|
||||
<li class="nav-item mb-2">
|
||||
<h6 class="text-muted text-uppercase small mb-2 mt-3">
|
||||
<i class="bi bi-key me-1"></i>
|
||||
Email Security
|
||||
</h6>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mb-1">
|
||||
<a href="{{ url_for('email.dkim_list') }}"
|
||||
class="nav-link text-white {{ 'active' if request.endpoint == 'email.dkim_list' else '' }}">
|
||||
@@ -81,7 +65,24 @@
|
||||
<span class="badge bg-secondary ms-auto">{{ dkim_count if dkim_count is defined else '' }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mb-1">
|
||||
<a href="{{ url_for('email.logs') }}"
|
||||
class="nav-link text-white {{ 'active' if request.endpoint == 'email.logs' else '' }}">
|
||||
<i class="bi bi-journal-text me-2"></i>
|
||||
Emails Log
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Authentication Section -->
|
||||
<li class="nav-item mb-2">
|
||||
<h6 class="text-muted text-uppercase small mb-2 mt-3">
|
||||
<i class="bi bi-shield-lock me-1"></i>
|
||||
Authentication
|
||||
</h6>
|
||||
</li>
|
||||
|
||||
|
||||
<!-- Configuration Section -->
|
||||
<li class="nav-item mb-2">
|
||||
<h6 class="text-muted text-uppercase small mb-2 mt-3">
|
||||
|
||||
@@ -1,25 +1,78 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Users - Email Server Management{% endblock %}
|
||||
{% block page_title %}User Management{% endblock %}
|
||||
{% block title %}Senders - Email Server Management{% endblock %}
|
||||
{% block page_title %}Sender Management{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>
|
||||
<i class="bi bi-people me-2"></i>
|
||||
Users
|
||||
Senders
|
||||
</h2>
|
||||
<a href="{{ url_for('email.add_user') }}" class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-2"></i>
|
||||
Add User
|
||||
Add Sender
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if users %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Sender Statistics
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
<strong>Active Senders:</strong> {{ users|selectattr('0.is_active')|list|length }}
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-star text-warning me-2"></i>
|
||||
<strong>Domain Sender:</strong> {{ users|selectattr('0.can_send_as_domain')|list|length }}
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-person text-info me-2"></i>
|
||||
<strong>Regular Senders:</strong> {{ users|rejectattr('0.can_send_as_domain')|list|length }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-lightbulb me-2"></i>
|
||||
Permission Levels
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-2">
|
||||
<span class="badge bg-warning me-2" style="color: black;">Domain Sender</span>
|
||||
Can send as any email address in their domain
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge bg-info me-2" style="color: black;">Regular Sender</span>
|
||||
Can only send as their own email address
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>
|
||||
All Users
|
||||
All Senders
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
@@ -47,16 +100,16 @@
|
||||
</td>
|
||||
<td>
|
||||
{% if user.can_send_as_domain %}
|
||||
<span class="badge bg-warning">
|
||||
<span class="badge bg-warning" style="color: black;">
|
||||
<i class="bi bi-star me-1"></i>
|
||||
Domain Admin
|
||||
Domain Sender
|
||||
</span>
|
||||
<br>
|
||||
<small class="text-muted">Can send as *@{{ domain.domain_name }}</small>
|
||||
{% else %}
|
||||
<span class="badge bg-info">
|
||||
<span class="badge bg-info" style="color: black;">
|
||||
<i class="bi bi-person me-1"></i>
|
||||
User
|
||||
Regular Sender
|
||||
</span>
|
||||
<br>
|
||||
<small class="text-muted">Can only send as {{ user.email }}</small>
|
||||
@@ -85,7 +138,7 @@
|
||||
<!-- Edit Button -->
|
||||
<a href="{{ url_for('email.edit_user', user_id=user.id) }}"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
title="Edit User">
|
||||
title="Edit Sender">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
|
||||
@@ -94,7 +147,7 @@
|
||||
<form method="post" action="{{ url_for('email.delete_user', user_id=user.id) }}" class="d-inline">
|
||||
<button type="submit"
|
||||
class="btn btn-outline-warning btn-sm"
|
||||
title="Disable User"
|
||||
title="Disable Sender"
|
||||
onclick="return confirm('Disable user {{ user.email }}?')">
|
||||
<i class="bi bi-pause-circle"></i>
|
||||
</button>
|
||||
@@ -103,7 +156,7 @@
|
||||
<form method="post" action="{{ url_for('email.enable_user', user_id=user.id) }}" class="d-inline">
|
||||
<button type="submit"
|
||||
class="btn btn-outline-success btn-sm"
|
||||
title="Enable User"
|
||||
title="Enable Sender"
|
||||
onclick="return confirm('Enable user {{ user.email }}?')">
|
||||
<i class="bi bi-play-circle"></i>
|
||||
</button>
|
||||
@@ -114,7 +167,7 @@
|
||||
<form method="post" action="{{ url_for('email.remove_user', user_id=user.id) }}" class="d-inline">
|
||||
<button type="submit"
|
||||
class="btn btn-outline-danger btn-sm"
|
||||
title="Permanently Remove User"
|
||||
title="Permanently Remove Sender"
|
||||
onclick="return confirm('Permanently remove user {{ user.email }}? This cannot be undone!')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
@@ -129,67 +182,15 @@
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-people text-muted" style="font-size: 4rem;"></i>
|
||||
<h4 class="text-muted mt-3">No users configured</h4>
|
||||
<p class="text-muted">Add users to enable username/password authentication</p>
|
||||
<h4 class="text-muted mt-3">No senders configured</h4>
|
||||
<p class="text-muted">Add sender to enable username/password authentication</p>
|
||||
<a href="{{ url_for('email.add_user') }}" class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-2"></i>
|
||||
Add Your First User
|
||||
Add Your First Sender
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if users %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
User Statistics
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
<strong>Active users:</strong> {{ users|selectattr('0.is_active')|list|length }}
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-star text-warning me-2"></i>
|
||||
<strong>Domain admins:</strong> {{ users|selectattr('0.can_send_as_domain')|list|length }}
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-person text-info me-2"></i>
|
||||
<strong>Regular users:</strong> {{ users|rejectattr('0.can_send_as_domain')|list|length }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-lightbulb me-2"></i>
|
||||
Permission Levels
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-2">
|
||||
<span class="badge bg-warning me-2">Domain Admin</span>
|
||||
Can send as any email address in their domain
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge bg-info me-2">Regular User</span>
|
||||
Can only send as their own email address
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user