mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
396 lines
12 KiB
HTML
396 lines
12 KiB
HTML
{% extends 'base.html' %}
|
|
{% block content %}
|
|
|
|
<style>
|
|
td {vertical-align: middle;}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
table.table {
|
|
table-layout: fixed;
|
|
}
|
|
table.table td {
|
|
word-wrap: break-word;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
span.advanced-text {display:none;}
|
|
}
|
|
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.advanced-settings {
|
|
align-items: center;
|
|
text-align: right;
|
|
color: black;
|
|
}
|
|
|
|
.advanced-settings i {
|
|
margin-right: 5px;
|
|
transform: rotate(-90deg);
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
|
|
|
|
[data-bs-theme=light] .domain_link {
|
|
color: black;
|
|
}
|
|
|
|
|
|
.domain_link {
|
|
border-bottom: 1px dashed #999;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.advanced-settings.active i {
|
|
transform: rotate(0);
|
|
}
|
|
|
|
thead {
|
|
border: 1px solid rgb(90 86 86 / 11%);
|
|
}
|
|
th {
|
|
text-transform: uppercase;
|
|
font-weight: 400;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="collapse mb-2" id="addEmailForm" style="display: none;">
|
|
<div class="card card-body">
|
|
|
|
<div class="container">
|
|
<a href="#" class="nije-link" id="cancelLinkemails" style="display: none;"><i class="bi bi-x-lg" style="right: 15px;top: 15px;position: absolute;color: black;padding: 6px 10px;border-radius: 50px;"></i></a>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 offset-md-3">
|
|
<h2 class="mb-3"><i class="bi bi-envelope-plus"></i> {{ _("Create new email account") }}</h2>
|
|
<p>{{ _("Use this form to create new email addresses for any of the domains on your account.") }}</p>
|
|
<form action="/emails" method="post">
|
|
<div class="form-group">
|
|
<label for="domain" class="form-label" data-toggle="tooltip" data-placement="top" title="{{ _('Choose the domain that you want to use. Your email address will end with this domain (username@domain.com).') }}">{{ _("Domain:") }}</label>
|
|
<div class="input-group">
|
|
</select>
|
|
<select class="form-select" name="domain" id="domain">
|
|
{% for domain in domains %}
|
|
<option class="punycode" value="{{ domain.domain_url }}">{{ domain.domain_url }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="at_address" data-toggle="tooltip" data-placement="top" title="{{ _('Enter the username that you want to use. Your email address will start with this username (username@domain.com).') }}">{{ _("Username:") }}</label>
|
|
|
|
|
|
<input type="text" class="form-control" name="email_username" required>
|
|
<div class="input-group-append" style="width: 100%;">
|
|
<input type="text" class="form-control" width="40%" name="at_address" id="at_address" disabled>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Check if the URL contains the parameter "install"
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const installParam = urlParams.get('create');
|
|
|
|
if (installParam || window.location.hash === '#create') {
|
|
// Show the Bootstrap collapsible element
|
|
$("#addEmailForm").collapse('show');
|
|
}
|
|
|
|
|
|
// Add event listener to the dropdown
|
|
$("#domain").change(function() {
|
|
// Get the selected domain URL
|
|
var selectedDomain = $("#domain option:selected").text();
|
|
|
|
// Update the admin email input value
|
|
var adminEmailInput = $("#at_address");
|
|
var currentAdminEmail = adminEmailInput.val();
|
|
adminEmailInput.val('@' + selectedDomain);
|
|
});
|
|
// Add event listener to the "Install WordPress" button to toggle form and jumbotron
|
|
$("#addEmailForm").on('shown.bs.collapse', function () {
|
|
$("#jumbotronSection").hide();
|
|
$("#cancelLinkemails").show();
|
|
});
|
|
|
|
// Add event listener to the "Cancel" link to toggle form and jumbotron
|
|
$("#cancelLinkemails").click(function() {
|
|
$("#addEmailForm").collapse('hide');
|
|
$("#jumbotronSection").show();
|
|
$("#cancelLinkemails").hide();
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var selectedDomain = $("#domain option:selected").text();
|
|
|
|
// Update the admin email input value
|
|
var adminEmailInput = $("#at_address");
|
|
var currentAdminEmail = adminEmailInput.val();
|
|
adminEmailInput.val('@' + selectedDomain);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
<div class="form-group">
|
|
<label for="email_password" class="form-label">{{ _("Password:") }}</label>
|
|
<div class="input-group">
|
|
<input type="password" class="form-control" name="email_password" id="email_password" required>
|
|
<div class="input-group-append">
|
|
<button class="btn btn-outline-success" type="button" id="generatePassword">
|
|
{{ _("Generate") }}
|
|
</button>
|
|
<button class="btn btn-outline-secondary" type="button" id="togglePassword">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
function generateRandomStrongPassword(length) {
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
|
let result = "";
|
|
for (let i = 0; i < length; i++) {
|
|
const randomIndex = Math.floor(Math.random() * charset.length);
|
|
result += charset.charAt(randomIndex);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function generateInitiallyUsernameAndPassword() {
|
|
const generatedPassword = generateRandomStrongPassword(16);
|
|
|
|
document.getElementById("email_password").value = generatedPassword;
|
|
};
|
|
|
|
generateInitiallyUsernameAndPassword();
|
|
|
|
document.getElementById("generatePassword").addEventListener("click", function() {
|
|
const generatedPassword = generateRandomStrongPassword(16);
|
|
document.getElementById("email_password").value = generatedPassword;
|
|
|
|
const passwordField = document.getElementById("email_password");
|
|
if (passwordField.type === "password") {
|
|
passwordField.type = "text";
|
|
}
|
|
|
|
});
|
|
|
|
document.getElementById("togglePassword").addEventListener("click", function() {
|
|
const passwordField = document.getElementById("email_password");
|
|
if (passwordField.type === "password") {
|
|
passwordField.type = "text";
|
|
} else {
|
|
passwordField.type = "password";
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<br>
|
|
<button type="submit" class="btn btn-primary">{{ _("Create") }}</button>
|
|
</form>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th width="">{{ _('Account @ Domain') }}</th>
|
|
<th width="" data-toggle="tooltip" data-placement="bottom" title="{{ _('Current disk usage for the email account.') }}">{{ _('Storage') }}<span class="desktop-only">{{ _(' Used') }}</span></th>
|
|
|
|
<th width="">{{ _('Options') }}</th>
|
|
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
{% for email_entry in current_emails_list %}
|
|
{% set parts = email_entry.split(' ') %}
|
|
{% set status = parts[0] %}
|
|
{% set address = parts[1] %}
|
|
{% set quota = ' '.join(parts[2:]) %}
|
|
{% set quota_parts = quota.split('[') %}
|
|
{% if quota_parts|length > 1 %}
|
|
{% set percentage_str = quota_parts[1].split(']')[0] %}
|
|
{% else %}
|
|
{% set percentage_str = '0' %}
|
|
{% endif %}
|
|
|
|
<tr class="domain_row">
|
|
<td><span class="punycode">{{ address }}</span>
|
|
<td>{{ quota }}
|
|
<br>
|
|
<div class="progress" style="height: 10px;">
|
|
<div id="disk-progress-bar" class="progress-bar w-4 bg-success" role="progressbar" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage_str }};"></div>
|
|
</div>
|
|
</td>
|
|
|
|
|
|
<td>
|
|
<div class="flex">
|
|
<a href="/webmail/{{ address }}" class="btn btn-primary btn-sm webmail-link" data-email="{{ address }}" role="button"><i class="bi bi-box-arrow-up-right"></i> Webmail</a>
|
|
<a href="/emails/{{ address }}" class="btn btn-outline-primary btn-sm" role="button"><i class="bi bi-wrench-adjustable"></i> Manage</a>
|
|
<a href="/emails/connect/{{ address }}" class="btn btn-outline-primary d-none btn-sm" role="button"><i class="bi bi-phone"></i> Connect Devices</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
// Attach event listener to all webmail links
|
|
document.querySelectorAll('.webmail-link').forEach(function(link) {
|
|
link.addEventListener('click', function(e) {
|
|
e.preventDefault(); // Prevent the default link behavior
|
|
|
|
const email = this.dataset.email; // Get the email from the data attribute
|
|
const url = `/webmail/${email}`; // Construct the URL
|
|
let btnClass, toastMessage;
|
|
|
|
btnClass = 'primary';
|
|
toastMessage = "{{ _('Webmail for ') }}" + email + "{{ _(' opened in new window.') }}";
|
|
const toast = toaster({
|
|
body: toastMessage,
|
|
className: `border-0 text-white bg-${btnClass}`,
|
|
});
|
|
|
|
window.open(url, '_blank');
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
|
|
</section>
|
|
<footer class="main-footer btn-toolbar" role="toolbar">
|
|
|
|
<div class="btn-group" role="group" aria-label="{{ _('Status') }}">
|
|
<input type="text" class="form-control" placeholder="{{ _('Search addresses') }}" id="searchDomainInput">
|
|
</div>
|
|
|
|
<div class="ms-auto" role="group" aria-label="{{ _('Actions') }}">
|
|
<button type="button" class="btn btn-primary d-flex align-items-center gap-2" id="showAddEmailFormBtn"><i class="bi bi-plus-lg"></i> <span class="desktop-only">{{ _('Create') }}</span></button>
|
|
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
function initializeDomainManagement() {
|
|
|
|
// Get references to search input and display settings div
|
|
const searchDomainInput = document.getElementById("searchDomainInput");
|
|
|
|
// Get all domain rows to be used for filtering
|
|
const domainRows = document.querySelectorAll(".domain_row");
|
|
|
|
// Handle search input changes
|
|
searchDomainInput.addEventListener("input", function() {
|
|
const searchTerm = searchDomainInput.value.trim().toLowerCase();
|
|
|
|
// Loop through domain rows and hide/show based on search term
|
|
domainRows.forEach(function(row) {
|
|
const domainName = row.querySelector("td:nth-child(1)").textContent.toLowerCase();
|
|
const domainUrl = row.querySelector("td:nth-child(2)").textContent.toLowerCase();
|
|
|
|
// Show row if search term matches domain name or domain URL, otherwise hide it
|
|
if (domainName.includes(searchTerm) || domainUrl.includes(searchTerm)) {
|
|
row.style.display = "table-row";
|
|
} else {
|
|
row.style.display = "none";
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
}
|
|
|
|
initializeDomainManagement ();
|
|
|
|
|
|
|
|
|
|
|
|
// Toggle display of "Add New Domain" form
|
|
const showAddEmailFormBtn = document.getElementById("showAddEmailFormBtn");
|
|
showAddEmailFormBtn.addEventListener("click", function() {
|
|
addEmailForm.style.display = addEmailForm.style.display === "none" ? "block" : "none";
|
|
});
|
|
|
|
|
|
function toggleEmailDomainForm() {
|
|
const currentFragment = window.location.hash;
|
|
const addNewFragment = "#create";
|
|
|
|
if (currentFragment === addNewFragment) {
|
|
addEmailForm.style.display = "block";
|
|
} else {
|
|
addEmailForm.style.display = "none";
|
|
}
|
|
}
|
|
|
|
// Listen for changes in the URL's fragment identifier
|
|
window.addEventListener("hashchange", toggleEmailDomainForm);
|
|
|
|
// Check the initial fragment identifier when the page loads
|
|
window.addEventListener("load", toggleEmailDomainForm);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|