Files
CyberPanel/websiteFunctions/templates/websiteFunctions/ftpQuotaManagement.html

352 lines
15 KiB
HTML

{% extends "baseTemplate/index.html" %}
{% load static %}
{% block title %}
FTP Quota Management - CyberPanel
{% endblock %}
{% block content %}
<style>
/* Ensure FTP Quota info section is readable - dark text on light background */
.ftp-quota-info .alert-info {
background: #e0f2fe !important;
color: #0c4a6e !important;
border: 1px solid #7dd3fc;
}
.ftp-quota-info .alert-info h5,
.ftp-quota-info .alert-info p,
.ftp-quota-info .alert-info .btn-primary {
color: inherit !important;
}
.ftp-quota-info .alert-info .btn-primary {
background: #0284c7 !important;
border-color: #0284c7 !important;
color: white !important;
}
</style>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-folder"></i>
FTP Quota Management
</h3>
</div>
<div class="card-body">
<!-- Enable FTP Quota Section -->
<div class="row mb-4 ftp-quota-info">
<div class="col-12">
<div id="ftpDisabledWarning" class="alert alert-warning" style="display: none;">
<h5><i class="fas fa-exclamation-triangle"></i> Pure-FTPd is not running</h5>
<p class="mb-0">Please enable Pure-FTPd first (e.g. from <strong>Server Status → Services</strong>) before enabling the FTP Quota system.</p>
</div>
<div id="ftpQuotaAlreadyEnabled" class="alert alert-success" style="display: none;">
<h5><i class="fas fa-check-circle"></i> FTP Quota system is already enabled</h5>
<p class="mb-0">Pure-FTPd is running with quota support. You can manage per-user quotas in the table below.</p>
</div>
<div id="ftpQuotaInfoDefault" class="alert alert-info">
<h5><i class="fas fa-info-circle"></i> FTP Quota System</h5>
<p>Enable and manage individual FTP user quotas. This allows you to set storage limits for each FTP user.</p>
<button type="button" id="btnEnableFTPQuota" class="btn btn-primary" onclick="enableFTPQuota()">
<i class="fas fa-play"></i> <span id="btnEnableFTPQuotaText">Enable FTP Quota System</span>
</button>
</div>
</div>
</div>
<!-- FTP Quotas List -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4>FTP User Quotas</h4>
<button class="btn btn-success btn-sm" onclick="refreshQuotas()">
<i class="fas fa-sync"></i> Refresh
</button>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped" id="quotasTable">
<thead>
<tr>
<th>FTP User</th>
<th>Domain</th>
<th>Quota Size (MB)</th>
<th>Used (MB)</th>
<th>Usage %</th>
<th>File Limit</th>
<th>Files Used</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="quotasTableBody">
<tr>
<td colspan="9" class="text-center">
<i class="fas fa-spinner fa-spin"></i> Loading...
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Edit Quota Modal -->
<div class="modal fade" id="editQuotaModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit FTP Quota</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editQuotaForm">
<input type="hidden" id="quotaId" name="quota_id">
<div class="form-group">
<label for="quotaSize">Quota Size (MB)</label>
<input type="number" class="form-control" id="quotaSize" name="quota_size_mb" min="0" placeholder="0 = Unlimited">
</div>
<div class="form-group">
<label for="quotaFiles">File Limit</label>
<input type="number" class="form-control" id="quotaFiles" name="quota_files" min="0" placeholder="0 = Unlimited">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="saveQuota()">Save Changes</button>
</div>
</div>
</div>
</div>
<script>
function getCsrfToken() {
var name = 'csrftoken';
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var c = cookies[i].trim();
if (c.indexOf(name + '=') === 0) return c.substring(name.length + 1);
}
return '{{ csrf_token }}';
}
function showNotification(type, message) {
if (typeof PNotify !== 'undefined') {
try {
new PNotify({ type: type === 'success' ? 'success' : 'error', text: message });
return;
} catch (e) {}
}
var alertClass = type === 'success' ? 'alert-success' : 'alert-danger';
var icon = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle';
var notification = '<div class="alert ' + alertClass + ' alert-dismissible fade show" role="alert">' +
'<i class="fas ' + icon + '"></i> ' + message +
'<button type="button" class="close" data-dismiss="alert"><span>&times;</span></button></div>';
var target = document.querySelector('.ftp-quota-info .alert-info');
if (target && target.parentNode) {
var wrap = document.createElement('div');
wrap.innerHTML = notification;
target.parentNode.insertBefore(wrap.firstChild, target);
setTimeout(function() {
var al = target.parentNode.querySelector('.alert');
if (al && al.remove) al.remove();
}, 6000);
}
}
function updateFTPQuotaStatus() {
$.ajax({
url: '{% url "getFTPQuotaStatus" %}',
type: 'POST',
data: { 'csrfmiddlewaretoken': getCsrfToken() },
headers: { 'X-CSRFToken': getCsrfToken() },
dataType: 'json',
success: function(data) {
var warning = document.getElementById('ftpDisabledWarning');
var already = document.getElementById('ftpQuotaAlreadyEnabled');
var defaultBox = document.getElementById('ftpQuotaInfoDefault');
var btn = document.getElementById('btnEnableFTPQuota');
var btnText = document.getElementById('btnEnableFTPQuotaText');
if (!data || data.status !== 1) return;
if (!data.ftp_running) {
if (warning) warning.style.display = 'block';
if (already) already.style.display = 'none';
if (defaultBox) defaultBox.style.display = 'none';
if (btn) { btn.disabled = true; btn.title = 'Start Pure-FTPd from Server Status → Services first'; }
if (btnText) btnText.textContent = 'Enable FTP Quota System (start Pure-FTPd first)';
} else if (data.quota_configured) {
if (warning) warning.style.display = 'none';
if (already) already.style.display = 'block';
if (defaultBox) defaultBox.style.display = 'none';
if (btn) { btn.disabled = true; btn.title = ''; }
if (btnText) btnText.textContent = 'FTP Quota system is already enabled';
} else {
if (warning) warning.style.display = 'none';
if (already) already.style.display = 'none';
if (defaultBox) defaultBox.style.display = 'block';
if (btn) { btn.disabled = false; btn.title = ''; }
if (btnText) btnText.textContent = 'Enable FTP Quota System';
}
}
});
}
function enableFTPQuota() {
var btn = document.getElementById('btnEnableFTPQuota');
var btnText = document.getElementById('btnEnableFTPQuotaText');
if (!btn || !btnText) return;
if (btn.disabled) return;
var originalHtml = btnText.innerHTML;
btn.disabled = true;
btnText.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Enabling...';
$.ajax({
url: '{% url "enableFTPQuota" %}',
type: 'POST',
data: { 'csrfmiddlewaretoken': getCsrfToken() },
headers: { 'X-CSRFToken': getCsrfToken() },
dataType: 'json',
success: function(data) {
if (data && data.status === 1) {
showNotification('success', data.message || 'FTP quota system enabled successfully');
updateFTPQuotaStatus();
refreshQuotas();
} else {
showNotification('error', (data && (data.message || data.error_message)) || 'Enable failed');
}
},
error: function(xhr) {
var msg = 'Request failed';
if (xhr.responseJSON && (xhr.responseJSON.message || xhr.responseJSON.error_message)) {
msg = xhr.responseJSON.message || xhr.responseJSON.error_message;
} else if (xhr.responseText && xhr.responseText.length < 500) {
try {
var j = JSON.parse(xhr.responseText);
msg = j.message || j.error_message || msg;
} catch (e) {}
}
if (xhr.status === 403 || xhr.status === 302) {
msg = 'Session may have expired. Please refresh the page and try again.';
}
showNotification('error', msg);
},
complete: function() {
btn.disabled = false;
btnText.innerHTML = originalHtml;
updateFTPQuotaStatus();
}
});
}
function refreshQuotas() {
var tbody = document.getElementById('quotasTableBody');
if (tbody) tbody.innerHTML = '<tr><td colspan="9" class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading...</td></tr>';
$.ajax({
url: '{% url "getFTPQuotas" %}',
type: 'POST',
data: { 'csrfmiddlewaretoken': '{{ csrf_token }}' },
dataType: 'json',
success: function(data) {
if (data && data.status === 1) {
displayQuotas(data.quotas || []);
} else {
var msg = (data && (data.error_message || data.message)) || 'Unknown error';
showNotification('error', msg);
if (tbody) tbody.innerHTML = '<tr><td colspan="9" class="text-center text-danger">' + msg + '</td></tr>';
}
},
error: function(xhr) {
var msg = (xhr.responseJSON && (xhr.responseJSON.error_message || xhr.responseJSON.message)) || (xhr.statusText || 'Request failed');
showNotification('error', msg);
if (tbody) tbody.innerHTML = '<tr><td colspan="9" class="text-center text-danger">' + msg + '</td></tr>';
}
});
}
function displayQuotas(quotas) {
const tbody = document.getElementById('quotasTableBody');
if (quotas.length === 0) {
tbody.innerHTML = '<tr><td colspan="9" class="text-center">No FTP quotas found</td></tr>';
return;
}
let html = '';
quotas.forEach(quota => {
const percentage = quota.quota_percentage.toFixed(1);
const statusClass = quota.is_active ? 'success' : 'danger';
const statusText = quota.is_active ? 'Active' : 'Inactive';
html += `
<tr>
<td>${quota.ftp_user}</td>
<td>${quota.domain}</td>
<td>${quota.quota_size_mb === 0 ? 'Unlimited' : quota.quota_size_mb}</td>
<td>${quota.quota_used_mb}</td>
<td>
<div class="progress">
<div class="progress-bar" style="width: ${percentage}%"></div>
</div>
${percentage}%
</td>
<td>${quota.quota_files === 0 ? 'Unlimited' : quota.quota_files}</td>
<td>${quota.quota_files_used}</td>
<td><span class="badge badge-${statusClass}">${statusText}</span></td>
<td>
<button class="btn btn-sm btn-primary" onclick="editQuota(${quota.id}, ${quota.quota_size_mb}, ${quota.quota_files})">
<i class="fas fa-edit"></i>
</button>
</td>
</tr>
`;
});
tbody.innerHTML = html;
}
function editQuota(id, size, files) {
document.getElementById('quotaId').value = id;
document.getElementById('quotaSize').value = size;
document.getElementById('quotaFiles').value = files;
$('#editQuotaModal').modal('show');
}
function saveQuota() {
const formData = {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'quota_id': document.getElementById('quotaId').value,
'quota_size_mb': document.getElementById('quotaSize').value,
'quota_files': document.getElementById('quotaFiles').value
};
$.post('{% url "updateFTPQuota" %}', formData, function(data) {
if (data.status === 1) {
showNotification('success', (data && (data.message || data.error_message)) || 'Success');
$('#editQuotaModal').modal('hide');
refreshQuotas();
} else {
showNotification('error', (data && (data.error_message || data.message)) || 'Unknown error');
}
});
}
// Load status and quotas on page load
$(document).ready(function() {
updateFTPQuotaStatus();
refreshQuotas();
});
</script>
{% endblock %}