mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
1493 lines
70 KiB
HTML
1493 lines
70 KiB
HTML
<!-- single_user.html -->
|
|
{% extends 'base.html' %}
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css">
|
|
|
|
<link href="/static/dist/css/tabler-flags.min.css?1684106062" rel="stylesheet" />
|
|
|
|
|
|
<style>
|
|
|
|
.people-item {
|
|
padding:1em;
|
|
}
|
|
|
|
</style>
|
|
|
|
|
|
{% if user %}
|
|
|
|
|
|
|
|
|
|
<div class="modal modal-blur fade" id="modal-openpanel-settings-for-user" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Edit user preferences</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h3 class="card-title">Node.js Version</h3>
|
|
<p class="card-subtitle">The version of Node.js that is used in the Build Step for all user's applications.</p>
|
|
<select class="form-select">
|
|
<option>14.x</option>
|
|
<option>12.x</option>
|
|
</select>
|
|
</div>
|
|
<div class="card-footer">
|
|
Learn more about <a href="#">Node.js Version</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h3 class="card-title">PHP Version</h3>
|
|
<p class="card-subtitle">The default PHP version that is used for all future domains added by user.</p>
|
|
<select class="form-select">
|
|
<option>8.3</option>
|
|
<option>8.2x</option>
|
|
</select>
|
|
</div>
|
|
<div class="card-footer">
|
|
Learn more about <a href="#">default PHP version</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<label class="form-check">
|
|
<input class="form-check-input" type="checkbox">
|
|
<span class="form-check-label">Generate 'Domain Visitors' reports</span>
|
|
</label>
|
|
<label class="form-check">
|
|
<input class="form-check-input" type="checkbox">
|
|
<span class="form-check-label">Enable backups</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="sudoSwitch">
|
|
<label class="form-check-label" for="sudoSwitch">Sudo Access</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div>
|
|
<label class="form-label">Personalized message to appear on the user's dashboard</label>
|
|
<textarea id="custom_message_for_this_user" class="form-control" rows="3"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<a href="#" class="btn btn-link link-secondary" data-bs-dismiss="modal">
|
|
Cancel
|
|
</a>
|
|
<button type="submit" class="btn btn-primary ms-auto">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10" /></svg>
|
|
Save changes
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Modal for Success/Error Messages -->
|
|
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="messageModalLabel">Message</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body" id="messageModalBody">
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Function to show modal with message
|
|
function showMessageModal(title, message) {
|
|
$('#messageModalLabel').text(title);
|
|
$('#messageModalBody').text(message);
|
|
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
messageModal.show();
|
|
}
|
|
|
|
// Get current sudo status when the modal is shown
|
|
$('#modal-openpanel-settings-for-user').on('shown.bs.modal', function() {
|
|
var containerName = $('#containerName').val();
|
|
$.ajax({
|
|
url: `/json/user/sudo/${containerName}`,
|
|
type: 'GET',
|
|
success: function(response) {
|
|
if (response.sudo === "YES") {
|
|
$('#sudoSwitch').prop('checked', true);
|
|
} else {
|
|
$('#sudoSwitch').prop('checked', false);
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
showMessageModal('Error', xhr.responseJSON.error);
|
|
}
|
|
});
|
|
|
|
$.ajax({
|
|
url: `/get_custom_message_for_user/${containerName}`,
|
|
type: 'GET',
|
|
success: function(response) {
|
|
if (response.custom_message) {
|
|
$('#custom_message_for_this_user').val(response.custom_message);
|
|
} else {
|
|
$('#custom_message_for_this_user').val('');
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
// Check if the status code is 404
|
|
if (xhr.status === 404) {
|
|
// 404 when no user!
|
|
const response = xhr.responseJSON;
|
|
$('#custom_message_for_this_user').val('');
|
|
} else {
|
|
// For other errors, show the error message
|
|
showMessageModal('Error', xhr.responseJSON.error || 'An error occurred while retrieving the custom message.');
|
|
}
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
// Toggle sudo status on switch change
|
|
$('#sudoSwitch').change(function() {
|
|
var containerName = $('#containerName').val();
|
|
console.log('Username:', containerName);
|
|
const action = $(this).is(':checked') ? 'enable' : 'disable';
|
|
$.ajax({
|
|
url: `/json/user/sudo/${containerName}`,
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify({ action: action }),
|
|
success: function(response) {
|
|
showMessageModal('Success', response.message);
|
|
},
|
|
error: function(xhr) {
|
|
showMessageModal('Error', xhr.responseJSON.error);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="modal modal-blur fade" id="modal-edit-user" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Edit user {{user.username}}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form action="/user/edit/{{user.username}}" method="POST">
|
|
|
|
<div id="ipList"></div>
|
|
<div id="planList"></div>
|
|
<div class="row">
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Username</label>
|
|
<input type="text" class="form-control" name="new_username" placeholder="Username" value="{{user.username}}">
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Email address</label>
|
|
<input type="email" class="form-control" name="new_email" placeholder="some-email@example.com" autocomplete="off" value="{{ user.email }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-12">
|
|
<label class="form-label">Plan</label>
|
|
<div class="form-selectgroup-boxes row mb-3" id="planSelectGroup"></div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Password</label>
|
|
<input type="password" name="new_password" class="form-control" placeholder="unchanged if empty" autocomplete="off" value="">
|
|
</div>
|
|
</div>
|
|
<!--div class="col-lg-1">
|
|
<div class="mb-3">
|
|
<label class="form-label">2FA</label>
|
|
<label class="form-check form-switch">
|
|
<input class="form-check-input" name="new_2fa" type="checkbox">
|
|
</label>
|
|
</div>
|
|
</div-->
|
|
<div class="col-lg-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">IP address</label>
|
|
<select id="ipSelect" name="new_ip" class="form-select"></select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<a href="#" class="btn btn-link link-secondary" data-bs-dismiss="modal">
|
|
Cancel
|
|
</a>
|
|
<button type="submit" class="btn btn-primary ms-auto">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10" /></svg>
|
|
Save changes
|
|
</a>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="page-wrapper">
|
|
<div class="d-print-none">
|
|
<div class="container">
|
|
<div class="row g-3 align-items-center">
|
|
<div class="col-auto">
|
|
<span id="docker_color_status_indicator" class="status-indicator status-primary status-indicator-animated">
|
|
<span class="status-indicator-circle"></span>
|
|
<span class="status-indicator-circle"></span>
|
|
<span class="status-indicator-circle"></span>
|
|
</span>
|
|
</div>
|
|
<div class="col">
|
|
<h2 class="page-title">
|
|
{{ user.username.split('_')[-1] }}{% if "SUSPENDED_" in user.username %} <span class="badge bg-red-lt">SUSPENDED</span>{% endif %}
|
|
</h2>
|
|
|
|
|
|
|
|
|
|
|
|
<span style="display:none;" id="username_for_functions">{{ user.username.split('_')[-1] }}</span>
|
|
<span style="display:none;" id="plan_name_for_functions">{{ get_hosting_plan_name_by_id(user.plan_id) }}</span>
|
|
|
|
<div class="text-muted">
|
|
<ul class="list-inline list-inline-dots mb-0">
|
|
<li class="list-inline-item">Docker container: <span id="statusColorTextdocker" class=""><span id="stateStatus">loading..</span></span></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-auto ms-auto d-print-none">
|
|
<div class="btn-list">
|
|
|
|
{% if "SUSPENDED_" in user.username %}
|
|
|
|
<span data-bs-toggle="tooltip" data-bs-placement="top" title="Unsuspend account">
|
|
<a href="/user/unsuspend/{{ user.username }}" class="btn" id="unsuspendButton">
|
|
<svg xmlns="http://www.w3.org/2000/svg" style="margin:0px;" class="icon icon-tabler icon-tabler-player-play-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" /></svg></a></span>
|
|
|
|
|
|
{% else %}
|
|
<span data-bs-toggle="tooltip" data-bs-placement="top" title="Suspend account">
|
|
<a href="/user/suspend/{{ user.username }}" class="btn" id="suspendButton" data-bs-toggle="modal" data-bs-target="#confirmSuspendUserModal">
|
|
<svg xmlns="http://www.w3.org/2000/svg" style="margin:0px;" class="icon icon-tabler icon-tabler-player-pause-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 4h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h2a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2z" stroke-width="0" fill="currentColor" /><path d="M17 4h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h2a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2z" stroke-width="0" fill="currentColor" /></svg></a></span>
|
|
|
|
<!-- Suspend Confirmation Modal -->
|
|
<div class="modal modal-blur fade" id="confirmSuspendUserModal" aria-labelledby="confirmSuspendUserModalLabel" tabindex="-1" role="dialog" aria-hidden="true" data-bs-backdrop="static">
|
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
|
<div class="modal-content">
|
|
<button type="button" id="suspendModalxClose" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
<div class="modal-status bg-warning"></div>
|
|
<div class="modal-body text-center py-4">
|
|
<!-- Download SVG icon from http://tabler-icons.io/i/alert-triangle -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-warning icon-lg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
|
|
<h3 id="confirmSuspendUserModallLabel">Are you sure you want to suspend the user <b>{{user.username}}</b>?</h3>
|
|
<div class="text-muted"><small>Suspending an account will immediately disable the user's access to the OpenPanel. This action involves pausing the user's Docker container and revoking access to their email, website, and other associated services. Please be aware of the immediate impact before proceeding.</small></div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<div class="w-100">
|
|
<div class="row">
|
|
<div class="col"><a href="#" class="btn w-100" data-bs-dismiss="modal">
|
|
Cancel
|
|
</a></div>
|
|
<div class="col"><a href="#" id="confirmSuspend" class="btn btn-warning w-100">
|
|
Suspend
|
|
</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Delete Modal -->
|
|
<div class="modal modal-blur fade" id="confirmDeleteUserModal" aria-labelledby="confirmDeleteUserModalLabel" tabindex="-1" role="dialog" aria-hidden="true" data-bs-backdrop="static">
|
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
|
<div class="modal-content">
|
|
<button type="button" id="deleteModalxClose" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
<div class="modal-status bg-danger"></div>
|
|
<div class="modal-body text-center py-4">
|
|
<!-- Download SVG icon from http://tabler-icons.io/i/alert-triangle -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-danger icon-lg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
|
|
<h3 id="confirmDeleteUserModalLabel">Are you sure you want to delete the user <b>{{user.username}}</b>?</h3>
|
|
<div class="text-muted"> <small>Terminating an account will permanently remove the user's access to the OpenPanel. This action includes stopping and removing the user's Docker container, as well as permanently revoking access to their email, website, and other associated services. Exercise caution and fully understand the irreversible consequences before proceeding.</small></div>
|
|
<!-- Input field for confirmation -->
|
|
<div class="mt-3 mb-3">
|
|
<label for="deleteConfirmation" class="form-label">Type "DELETE" to confirm:</label>
|
|
<input type="text" class="form-control" id="deleteConfirmation">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<div class="w-100">
|
|
<div class="row">
|
|
<!--div class="col"><a href="#" class="btn w-100" data-bs-dismiss="modal">
|
|
Cancel
|
|
</a></div-->
|
|
<div class="col"><a href="#" id="confirmDelete" class="btn btn-danger w-100" style="display: none;">
|
|
Terminate
|
|
</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<span data-bs-toggle="tooltip" data-bs-placement="top" title="Delete account">
|
|
<a href="/user/delete/{{user.username}}" class="btn" id="deleteButton" data-bs-toggle="modal" data-bs-target="#confirmDeleteUserModal">
|
|
<svg xmlns="http://www.w3.org/2000/svg" style="margin:0px; color:red;" class="icon icon-tabler icon-tabler-trash-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 6a1 1 0 0 1 .117 1.993l-.117 .007h-.081l-.919 11a3 3 0 0 1 -2.824 2.995l-.176 .005h-8c-1.598 0 -2.904 -1.249 -2.992 -2.75l-.005 -.167l-.923 -11.083h-.08a1 1 0 0 1 -.117 -1.993l.117 -.007h16z" stroke-width="0" fill="currentColor" /><path d="M14 2a2 2 0 0 1 2 2a1 1 0 0 1 -1.993 .117l-.007 -.117h-4l-.007 .117a1 1 0 0 1 -1.993 -.117a2 2 0 0 1 1.85 -1.995l.15 -.005h4z" stroke-width="0" fill="currentColor" /></svg></a></span>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{% if "SUSPENDED_" in user.username %}
|
|
<a href="#" class="btn" style="pointer-events: auto! important; cursor: not-allowed! important;" disabled>
|
|
<!-- Download SVG icon from http://tabler-icons.io/i/settings -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" /><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /></svg>
|
|
Configure
|
|
</a>
|
|
|
|
|
|
|
|
{% else %}
|
|
<a href="#" class="btn" data-bs-toggle="modal" data-bs-target="#modal-openpanel-settings-for-user">
|
|
<!-- Download SVG icon from http://tabler-icons.io/i/settings -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" style="margin:0" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" /><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /></svg>
|
|
<span class="d-none d-sm-inline-block" style="margin-left:2px">Configure</span>
|
|
</a>
|
|
<input type="hidden" id="containerName" value="{{ user.username }}">
|
|
{% endif %}
|
|
|
|
|
|
{% if "SUSPENDED_" in user.username %}
|
|
<a href="#" class="btn btn-secondary" style="pointer-events: auto! important; cursor: not-allowed! important;" disabled>
|
|
User is suspended
|
|
</a>
|
|
{% else %}
|
|
<a href="#" class="btn btn-primary loginLink" user="{{ user.username }}" target="_blank">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-login-2" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 8v-2a2 2 0 0 1 2 -2h7a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-7a2 2 0 0 1 -2 -2v-2" /><path d="M3 12h13l-3 -3" /><path d="M13 15l3 -3" /></svg>
|
|
Login<span class="d-none d-sm-inline-block"> as user</span>
|
|
</a>
|
|
{% endif %}
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Page body -->
|
|
<div class="page-body">
|
|
<div class="container-xl">
|
|
<div class="row row-cards">
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div id="cpuIndicator" class="card-status-top bg-primary"></div>
|
|
<div class="card-body">
|
|
<h3 class="subheader m-0">CPU usage</h3>
|
|
<div class="h3 m-0" id="cpu-usage"><span class="placeholder col-9 mb-1"></span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="ramIndicator" class="card-status-top bg-primary"></div>
|
|
<h3 class="subheader m-0">Memory Usage</h3>
|
|
<div class="h3 m-0" id="mem-usage"><span class="placeholder col-9 mb-1"></span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<a class="ribbon bg-danger d-none" style="text-decoration:none;padding:0;" id="unlimited_storage_indicator" title="The Docker container can use all the space allocated to docker (/var/lib/docker)." data-bs-toggle="tooltip" data-bs-placement="top"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-exclamation-mark"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 19v.01" /><path d="M12 15v-10" /></svg></a>
|
|
<div class="card-body">
|
|
<div id="diskIndicator" class="card-status-top bg-primary"></div>
|
|
<h3 class="subheader m-0">Disk Usage</h3>
|
|
<div class="h3 m-0" id="disk-usage"><span class="placeholder col-9 mb-1"></span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
{% if server_ip != public_ip %}
|
|
<div class="ribbon bg-success">Dedicated IP</div>
|
|
{% endif %}
|
|
<div class="card-body">
|
|
<h3 class="subheader m-0">IP address</h3>
|
|
<div class="h3 m-0">{{ server_ip }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="col-md-8">
|
|
|
|
<ul class="nav nav-tabs card-header-tabs nav-fill" data-bs-toggle="tabs" role="tablist">
|
|
<li class="nav-item" role="presentation" style="">
|
|
<a href="#nav-info" id="nav-info-tab" class="nav-link active" data-bs-toggle="tab" aria-selected="true" role="tab" style="border-radius: 0px;">Docker</a>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-user-data" id="nav-user-data-tab" class="nav-link" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab" style="border-radius: 0px;">Websites</a>
|
|
</li>
|
|
{% if "SUSPENDED_" in user.username %}
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-manage" class="nav-link disabled" style="pointer-events: auto! important; cursor: not-allowed! important;" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab" style="border-radius: 0px;">Services</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-manage" id="nav-manage-tab" class="nav-link" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab" style="border-radius: 0px;">Services</a>
|
|
</li>
|
|
{% endif %}
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-backups" id="nav-backups-tab" class="nav-link" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab">Backups</a>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-resource" id="nav-resource-tab" class="nav-link" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab" style="border-radius: 0px;">Usage</a>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#nav-activity" id="nav-activity-tab" class="nav-link" data-bs-toggle="tab" aria-selected="false" tabindex="-1" role="tab" style="border-radius: 0px;">Activity</a>
|
|
</li>
|
|
</ul>
|
|
|
|
|
|
<div class="tab-content" id="nav-tabContent">
|
|
<div class="tab-pane fade show active" id="nav-info" role="tabpanel" aria-labelledby="nav-info-tab">
|
|
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Docker container</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<a data-bs-toggle="collapse" class="nav-link collapsed" href="#container_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body">
|
|
<div class="collapse" id="container_info" style="">
|
|
<p>Current Docker container information for the user:</p>
|
|
<p>
|
|
</p><ul>
|
|
<li><b>Server:</b> Indicates the node on which the account Docker container is running.</li>
|
|
<li><b>ID:</b> Is the unique Docker container's ID.</li>
|
|
<li><b>Docker Image:</b> Shows the name of the Docker image that the user is using as well as its OS and version.</li>
|
|
<li><b>Hostname:</b> Represents the hostname that the user sees inside their terminal environment.</li>
|
|
<li><b>Container Created:</b> Represents the time and date when the Docker container was created for the user.</li>
|
|
|
|
<li><b>Private IP:</b> the current private IP address that the Docker container is assigned, used only for networking and proxying requests to users' websites.</li>
|
|
<li><b>Memory Allocated:</b> Is the RAM allocated to the Docker container. This value is a hard limit and cannot be exceeded by users' processes.</li>
|
|
<li><b>CPU:</b> Is the number of CPU cores that are allocated to the user's container. This value is also a hard limit.</li>
|
|
<li><b>Exposed Ports:</b> Displays all published ports on the container, meaning that the container is listening on these ports, however, they might be disabled on the firewall.</li>
|
|
<li><b>MacAddress:</b> Is the MAC Address of a Docker container.</li>
|
|
|
|
|
|
</ul>
|
|
<p></p>
|
|
|
|
</div>
|
|
<div class="row mx-auto w-100 my-1">
|
|
<div class="col-6 p-0">
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Server</label>
|
|
<br><span class="text-muted" id="docker-context">{{ server_name }}</span>
|
|
<input type="hidden" name="serid" value="1">
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">ID</label><br>
|
|
<span class="text-muted"><small id="id"></small></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Docker image</label><br>
|
|
<span class="text-muted"><span id="image"></span> (<span id="labels"></span>)</span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Hostname</label><br>
|
|
<span class="text-muted" id="docker-hostname"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Container Created</label><br>
|
|
<span class="text-muted" id="created"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 p-0">
|
|
<div class="row mx-auto w-100 my-3" id="primary_ip">
|
|
<div class="col-12">
|
|
<label class="control-label">Private IP</label><br>
|
|
<span class="text-muted" id="ipAddress"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Memory allocated</label><br>
|
|
<span class="text-muted" id="memory"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">CPU</label><br>
|
|
<span class="text-muted" id="nanoCpus"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">Exposed Ports</label><br>
|
|
<span class="text-muted" id="exposedPorts"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mx-auto w-100 my-3">
|
|
<div class="col-12">
|
|
<label class="control-label">MacAddress</label><br>
|
|
<div class="w-auto d-flex align-items-center">
|
|
<span class="text-muted"> <span id="macAddress"></span><br></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Disk Usage</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<a data-bs-toggle="collapse" class="nav-link collapsed" href="#paths_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a>
|
|
</div>
|
|
</div>
|
|
</div><!-- card-header -->
|
|
|
|
|
|
{% if "SUSPENDED_" not in user.username %}
|
|
|
|
<div class="card-body">
|
|
<div class="progress progress-separated mb-3">
|
|
<div class="progress-bar bg-info" role="progressbar" id="system_used_percentage" style="width: 10%" aria-label="System & Databases"></div>
|
|
<div class="progress-bar bg-success" role="progressbar" id="system_free_percentage" style="width: 20%" aria-label="Free system space"></div>
|
|
<div class="progress-bar bg-primary" role="progressbar" id="home_used_percentage" style="width: 50%" aria-label="Home directory"></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="row">
|
|
<div class="col-auto d-flex align-items-center px-2">
|
|
<span class="legend me-2 bg-info"></span>
|
|
<span>Used by OS & databases</span>
|
|
<span class="d-none d-md-inline d-lg-none d-xxl-inline ms-2 text-secondary" id="system_used">415MB</span>
|
|
</div>
|
|
<div class="col-auto d-flex align-items-center px-2">
|
|
<span class="legend me-2 bg-success"></span>
|
|
<span>Free for databases</span>
|
|
<span class="d-none d-md-inline d-lg-none d-xxl-inline ms-2 text-secondary" id="system_free">415MB</span>
|
|
</div>
|
|
<div class="col-auto d-flex align-items-center pe-2">
|
|
<span class="legend me-2 bg-primary"></span>
|
|
<span>Used by websites</span>
|
|
<span class="d-none d-md-inline d-lg-none d-xxl-inline ms-2 text-secondary" id="home_used">915MB</span>
|
|
</div>
|
|
|
|
<div class="col-auto d-flex align-items-center ps-2">
|
|
<span class="legend me-2"></span>
|
|
<span>Free space for websites</span>
|
|
<span class="d-none d-md-inline d-lg-none d-xxl-inline ms-2 text-secondary" id="free_space_total">612MB</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
<div class="card-body" style="padding: 0; overflow: scroll;">
|
|
<div class="p-2 collapse" id="paths_info" style="">
|
|
<p>
|
|
Since Docker does not yet support resizing docker containers, OpenPanel uses storage files that can be extended or shrunk on the fly.
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>/home/{{ user.username.split('_')[-1] }}</code> is used for all website files that user uploads to their home directory.
|
|
</li>
|
|
<li>
|
|
<code>/var/lib/docker/devicemapper/mnt/..</code> is the total file system that the user's Docker container is limited to; this includes the OS itself, system services, databases, logs, etc.
|
|
</li>
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="row mx-auto w-100 my-1">
|
|
<div class="col-12 p-0">
|
|
<div class="col-12">
|
|
<table id="mounts-table" class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Path</th>
|
|
<th>Inodes Used</th>
|
|
<th>Inodes Total</th>
|
|
<th>Disk Used</th>
|
|
<th>Disk Total</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table> </div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
</div>
|
|
<div class="tab-pane fade" id="nav-user-data" role="tabpanel" aria-labelledby="nav-user-data-tab">
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Domains</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">Total:
|
|
{% if user.user_domains %}
|
|
{% set domain_count = user.user_domains|length %}
|
|
{{domain_count}}
|
|
{% else %}0{% endif %} <a data-bs-toggle="collapse" class="nav-link collapsed" href="#domains_info" style="display:inline;" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a></span>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="p-2 collapse" id="domains_info" style="">
|
|
<p>These are the domain names currently in use on the user's openpanel. From this interface, you can view the access log for each domain, modify its DNS zone file, and edit the Nginx vhosts file.</p>
|
|
|
|
<p>Upon saving modifications to the DNS zone file or the Nginx vHosts file, the corresponding service, BIND or Nginx, will undergo a reload process to ensure that the changes take effect immediately.</p>
|
|
</div>
|
|
<table id="domains-table" class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Domain</th>
|
|
<th>Root Directory</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% if user.user_domains %}
|
|
{% for domain in user.user_domains %}
|
|
|
|
{% if domain %}
|
|
<tr>
|
|
<td>
|
|
<a class="domain_link" href="http://{{ domain }}" target="_blank">{{ domain }} <i class="bi bi-box-arrow-up-right"></i></a>
|
|
<td>/home/{{ user.username.split('_')[-1] }}/{{ domain }}</td>
|
|
</td>
|
|
<td>
|
|
<a href="#" class="view_log_link" data-domain="{{ domain }}" data-bs-toggle="offcanvas" data-bs-target="#logOffcanvas">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-zoom-code" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /><path d="M21 21l-6 -6" /><path d="M8 8l-2 2l2 2" /><path d="M12 8l2 2l-2 2" /></svg><span class="d-none d-sm-inline-block"> View Access Log</span></a> |
|
|
<a href="#" class="edit_dns_link" data-domain="{{ domain }}" data-bs-toggle="offcanvas" data-bs-target="#dnsOffcanvas">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-edit" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" /><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" /><path d="M16 5l3 3" /></svg><span class="d-none d-sm-inline-block"> DNS Zone</span></a> | <a href="#" class="edit_nginx_link" data-domain="{{ domain }}" data-bs-toggle="offcanvas" data-bs-target="#nginxOffcanvas">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-edit" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" /><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" /><path d="M16 5l3 3" /></svg><span class="d-none d-sm-inline-block"> VirtualHosts</span></a></td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="4">None</td>
|
|
</tr>
|
|
{% endif %}
|
|
|
|
{% endfor %}
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="4">None</td>
|
|
</tr>
|
|
{% endif %}
|
|
|
|
|
|
</tbody>
|
|
</table>
|
|
</div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Websites</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<span>Total: {{ get_user_websites(user.id)|length }} <a data-bs-toggle="collapse" class="nav-link collapsed" href="#websites_info" style="display:inline;" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a></span>
|
|
</div>
|
|
</div>
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="p-2 collapse" id="websites_info" style="">
|
|
<p>These are the websites that are currently available in the user's openpanel. The user could have additional websites not displayed here, especially if those websites haven't been created or imported through the Applications interface of their openpanel.</p>
|
|
<p>For every website, you have the option to review the website URL, platform type, version, and the timestamp indicating when the user added it to the Applications interface. </p>
|
|
</div>
|
|
<table id="websites-table" class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Website</th>
|
|
<th>Type</th>
|
|
<th>Version</th>
|
|
<th>Installed on</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% if get_user_websites(user.id) %}
|
|
{% for site_info in get_user_websites(user.id) %}
|
|
<tr>
|
|
<td><a class="domain_link" href="http://{{ site_info[0] }}" target="_blank">{{ site_info[0] }} <i class="bi bi-box-arrow-up-right"></i></a></td>
|
|
<td>
|
|
{% if site_info[3]|lower == 'wordpress' %}
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-wordpress" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9.5 9h3" /><path d="M4 9h2.5" /><path d="M11 9l3 11l4 -9" /><path d="M5.5 9l3.5 11l3 -7" /><path d="M18 11c.177 -.528 1 -1.364 1 -2.5c0 -1.78 -.776 -2.5 -1.875 -2.5c-.898 0 -1.125 .812 -1.125 1.429c0 1.83 2 2.058 2 3.571z" /><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /></svg><span class="d-none d-sm-inline-block"> WordPress CMS</span>
|
|
{% elif site_info[3]|lower == 'websitebuilder' %}
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-app-window" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" /><path d="M6 8h.01" /><path d="M9 8h.01" /></svg><span class="d-none d-sm-inline-block"> Website Builder</span>
|
|
{% elif 'nodejs' in site_info[3]|lower %}
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-nodejs" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 9v8.044a2 2 0 0 1 -2.996 1.734l-1.568 -.9a3 3 0 0 1 -1.436 -2.561v-6.635a3 3 0 0 1 1.436 -2.56l6 -3.667a3 3 0 0 1 3.128 0l6 3.667a3 3 0 0 1 1.436 2.561v6.634a3 3 0 0 1 -1.436 2.56l-6 3.667a3 3 0 0 1 -3.128 0" /><path d="M17 9h-3.5a1.5 1.5 0 0 0 0 3h2a1.5 1.5 0 0 1 0 3h-3.5" /></svg><span class="d-none d-sm-inline-block"> {{ site_info[3] }} Application</span>
|
|
{% elif 'python' in site_info[3]|lower %}
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-python" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 9h-7a2 2 0 0 0 -2 2v4a2 2 0 0 0 2 2h3" /><path d="M12 15h7a2 2 0 0 0 2 -2v-4a2 2 0 0 0 -2 -2h-3" /><path d="M8 9v-4a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v5a2 2 0 0 1 -2 2h-4a2 2 0 0 0 -2 2v5a2 2 0 0 0 2 2h4a2 2 0 0 0 2 -2v-4" /><path d="M11 6l0 .01" /><path d="M13 18l0 .01" /></svg><span class="d-none d-sm-inline-block"> {{ site_info[3] }} Application</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ site_info[1] }}</td>
|
|
|
|
<td>{{ site_info[2].strftime('%d.%m.%Y %H:%M:%S') }}</td>
|
|
|
|
</tr>
|
|
{% endfor %}
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="4">None</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
</div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tab-pane fade" id="nav-resource" role="tabpanel" aria-labelledby="nav-resource-tab">
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title"><span class="d-none d-sm-inline-block">Docker Container </span> Stats</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<span id="info">Click the button to load data <a data-bs-toggle="collapse" class="nav-link collapsed" href="#stats_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a></span>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="collapse p-2" id="stats_info" style="">
|
|
<p>Explore the Docker container resource usage for the user.</p>
|
|
<p>
|
|
|
|
Color indicators show summary of the data in the table bellow.
|
|
<ul>
|
|
<li class="my-2"><span class="badge"> </span> - both CPU and RAM usage is bellow 1%</li>
|
|
<li class="my-2"><span class="badge bg-success"> </span> - CPU usage is between 1-35% and RAM usage is between 1-50%</li>
|
|
<li class="my-2"><span class="badge bg-warning"> </span> - CPU usage is above 35% or RAM usage is above 50%</li>
|
|
<li class="my-2"><span class="badge bg-danger"> </span> - both CPU and RAM usage are above 75%</li>
|
|
</ul>
|
|
|
|
|
|
<ul>
|
|
<li><b>CPU %</b> indicates the portion of the CPU's processing power utilized by the Docker container.</li>
|
|
<li><b>RAM %</b> usage illustrates the amount of RAM used relative to the total available RAM.</li>
|
|
<li><b>Network I/O</b> showcases the amount of data sent or received by the container over the network at that specific moment.</li>
|
|
<li><b>Block I/O</b> signifies the volume of data in bytes written or read from the container to the disk.</li>
|
|
</ul>
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div id="tracking" class="tracking m-4"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div id="resource-usage-data">
|
|
|
|
</div>
|
|
|
|
</div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tab-pane fade" id="nav-backups" role="tabpanel" aria-labelledby="nav-backups-tab">
|
|
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Backups</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<span id="backups2_info"><a data-bs-toggle="collapse" class="nav-link collapsed" href="#backups_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a></span>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="collapse p-2" id="backups_info" style="">
|
|
Explore all the backups available for user {{ user.username }}, including details such as the backup date, status and content.
|
|
</div>
|
|
<div id="backups">
|
|
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Created</th>
|
|
<th>Contains</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div></div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tab-pane fade" id="nav-manage" role="tabpanel" aria-labelledby="nav-manage-tab">
|
|
|
|
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Services</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<a data-bs-toggle="collapse" class="nav-link collapsed" href="#services_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="collapse p-2" id="services_info" style="">
|
|
<p>Here you can check the status of services installed inside user Docker container. You can <b>start</b>, <b>stop</b>, or <b>restart</b> services as needed. Keep in mind that any changes that users made through the OpenPanel are automatically saved in the configuration. This ensures that their service settings stay consistent during activities like account migration or backup restoration.</p>
|
|
<p>For setting permanent service status, it's recommended to use the OpenPanel. Changes made here are effective, but using the OpenPanel ensures that user preferences are saved for the long term.</p>
|
|
</div>
|
|
<div id="services-status">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Status</th>
|
|
<th>Service Name</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align: middle;">
|
|
<td><span class="placeholder col-9 mb-0"></span></td>
|
|
<td><span class="placeholder placeholder-xs col-11"></span></td>
|
|
<td style="font-size: x-large;">
|
|
<a href="#" tabindex="-1" class="btn btn-primary disabled placeholder col-8" aria-hidden="true"></a>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
</div></div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
</div>
|
|
<div class="tab-pane fade" id="nav-edit" role="tabpanel" aria-labelledby="nav-edit-tab">.edit..</div>
|
|
|
|
|
|
|
|
<div class="tab-pane fade" id="nav-activity" role="tabpanel" aria-labelledby="nav-activity-tab">
|
|
<div class="card card-post mt-4">
|
|
<div class="card-header">
|
|
<div class="row g-2 align-items-center" style="width:100%;">
|
|
<div class="col">
|
|
<h6 class="card-title">Activity</h6>
|
|
</div>
|
|
<div class="col-auto text-muted">
|
|
<a data-bs-toggle="collapse" class="nav-link collapsed" href="#activity_log_info" role="button" aria-expanded="false" aria-controls="Factor"><i class="bi bi-question-circle"></i></a>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div><!-- card-header -->
|
|
<div class="card-body" style="padding:0px;">
|
|
<div class="collapse p-2" id="activity_log_info" style="">
|
|
<p>Users activity log: <code>/etc/openpanel/openpanel/core/users/{{ user.username.split('_')[-1] }}/activity.log</code></p>
|
|
</div>
|
|
<div id="activity_log" style="overflow: scroll;">
|
|
<table class="table table-hover" id="activity-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th style="width:50%;">Activity</th>
|
|
<th>IP Address</th>
|
|
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
|
|
</div></div><!-- card-body -->
|
|
</div><!-- card -->
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="col-md-4">
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">
|
|
General<span class="d-none d-sm-inline-block"> information</span>
|
|
</h3>
|
|
<div class="card-actions">
|
|
|
|
{% if "SUSPENDED_" not in user.username %}
|
|
|
|
<a href="#" data-bs-toggle="modal" id="edit_user_info_modal" data-bs-target="#modal-edit-user" onclick="loadData()">Edit<svg xmlns="http://www.w3.org/2000/svg" class="icon ms-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z"></path><path d="M16 5l3 3"></path></svg>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<dl class="row">
|
|
<dt class="col-5">User ID:</dt>
|
|
<dd class="col-7">{{ user.id }}</dd>
|
|
<dt class="col-5">Email address:</dt>
|
|
<dd class="col-7">{{ user.email }}</dd>
|
|
<dt class="col-5">Two Factor:</dt>
|
|
<dd class="col-7">{% if user.twofa_enabled == 1 %}2FA is enabled{% else %}2FA is not enabled{% endif %}</dd>
|
|
<dt class="col-5">Hosting Plan:</dt>
|
|
<dd class="col-7"><a href="/plans#{{ get_hosting_plan_name_by_id(user.plan_id) }}" data-plan_id="{{user.plan_id}}">{{ get_hosting_plan_name_by_id(user.plan_id) }}</a></dd>
|
|
<dt class="col-5">IP Address:</dt>
|
|
<dd class="col-7">{{ server_ip }}</dd>
|
|
{% if country_code and country_name %}
|
|
<dt class="col-5"><span class="d-none d-sm-inline-block">Server</span> Location:</dt>
|
|
<dd class="col-7"><span class="flag flag-country-{{country_code.lower()}}"></span> {{country_name}}</dd>
|
|
{% endif %}
|
|
{% if "SUSPENDED_" not in user.username %}
|
|
<dt class="col-5">Private IP:</dt>
|
|
<dd class="col-7"><span id="ipAddress2"></span></dd>
|
|
{% endif %}
|
|
<dt class="col-5">Setup Date:</dt>
|
|
<dd class="col-7">{{ user.registered_date.strftime('%d.%m.%Y %H:%M:%S') }}</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="d-flex">
|
|
<a href="#nav-user-data" class="card-btn">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-world-www m-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M19.5 7a9 9 0 0 0 -7.5 -4a8.991 8.991 0 0 0 -7.484 4" /><path d="M11.5 3a16.989 16.989 0 0 0 -1.826 4" /><path d="M12.5 3a16.989 16.989 0 0 1 1.828 4" /><path d="M19.5 17a9 9 0 0 1 -7.5 4a8.991 8.991 0 0 1 -7.484 -4" /><path d="M11.5 21a16.989 16.989 0 0 1 -1.826 -4" /><path d="M12.5 21a16.989 16.989 0 0 0 1.828 -4" /><path d="M2 10l1 4l1.5 -4l1.5 4l1 -4" /><path d="M17 10l1 4l1.5 -4l1.5 4l1 -4" /><path d="M9.5 10l1 4l1.5 -4l1.5 4l1 -4" /></svg>
|
|
Domains: {% if user.user_domains is not none and user.user_domains|length > 0 %}
|
|
{{ user.user_domains|length }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
</a>
|
|
<a href="#nav-user-data" class="card-btn">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-app-window m-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" /><path d="M6 8h.01" /><path d="M9 8h.01" /></svg>
|
|
Websites: {{ get_user_websites(user.id)|length }}</a>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{% if "SUSPENDED_" not in user.username %}
|
|
|
|
<div class="card mb-4" style="margin-top: var(--tblr-gutter-y);">
|
|
|
|
<div class="card-header">
|
|
<h3 class="card-title">
|
|
Ports
|
|
</h3>
|
|
<div class="card-actions">
|
|
<a href="/security/firewall?search={{user.username}}">
|
|
View Firewall rules
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon ms-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z"></path><path d="M16 5l3 3"></path></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div id="ports" class="card-body">
|
|
|
|
<div id="ports-container" style="list-style: none; display: flex;"></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="nginxOffcanvas">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="domain_name_nginx">Edit DNS</h5>
|
|
<button id="saveNginx" class="btn btn-primary mt-2">Save</button>
|
|
</div>
|
|
<div class="offcanvas-body" style="overflow-y: hidden;">
|
|
<textarea id="nginxContent" rows="20" class="ql-container ql-snow" style="height:100%; width: 100%;"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="offcanvas offcanvas-bottom" tabindex="-1" id="logOffcanvas">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="log_domain_name">View log</h5>
|
|
</div>
|
|
<div class="offcanvas-body" style="overflow-y: hidden;padding:0px;">
|
|
<pre id="logContent" rows="20" class="ql-container ql-snow" style="border-radius: 0px!important; height:100%; width: 100%; padding-bottom: 0;margin-bottom: 0;" disabled></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="dnsOffcanvas">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="domain_name">Edit DNS</h5>
|
|
<button id="saveDns" class="btn btn-primary mt-2">Save</button>
|
|
</div>
|
|
<div class="offcanvas-body" style="overflow-y: hidden;">
|
|
<textarea id="dnsContent" rows="20" class="ql-container ql-snow" style="height:100%; width: 100%;"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<style>
|
|
.nav-line .nav-link {
|
|
color: #6e7985!important;
|
|
}
|
|
</style>
|
|
|
|
|
|
|
|
<script src="{{ url_for('static', filename='pages/users_single.js') }}?v=0.8" defer></script>
|
|
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var planId = document.querySelector('[data-plan_name]').getAttribute('data-plan_name');
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', '/plans?output=json', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
xhr.onreadystatechange = function () {
|
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|
var response = JSON.parse(xhr.responseText);
|
|
var plans = response.plans;
|
|
var matchingPlan = plans.find(function(plan) {
|
|
return plan.id === parseInt(planId);
|
|
});
|
|
// Extract relevant data from the matching plan
|
|
var ram = parseInt(matchingPlan.ram.replace(' GB', ''));
|
|
var cpu = parseInt(matchingPlan.cpu.replace(' cores', ''));
|
|
|
|
// Log the extracted RAM and CPU values to the console
|
|
console.log('Extracted RAM: ' + ram + ' GB');
|
|
console.log('Extracted CPU: ' + cpu + ' cores');
|
|
|
|
// Compare with existing data
|
|
var realRam = parseInt(document.getElementById('memory').textContent.replace(' GB', ''));
|
|
var realCpu = parseInt(document.getElementById('nanoCpus').textContent.replace(' cores', ''));
|
|
// Log the REAL RAM and CPU values to the console
|
|
console.log('Real RAM: ' + realCpu + ' GB');
|
|
console.log('Real CPU: ' + realCpu + ' cores');
|
|
// Log the comparison results to the console
|
|
if (ram !== realRam) {
|
|
console.log('Difference in RAM: ' + Math.abs(realRam - ram) + ' GB');
|
|
} else {
|
|
console.log('RAM matches the existing data.');
|
|
}
|
|
|
|
if (cpu !== realCpu) {
|
|
console.log('Difference in CPU: ' + Math.abs(realCpu - cpu) + ' cores');
|
|
} else {
|
|
console.log('CPU matches the existing data.');
|
|
}
|
|
}
|
|
};
|
|
xhr.send();
|
|
});
|
|
</script>
|
|
|
|
<script src="{{ url_for('static', filename='pages/users_both.js') }}?v=0.3" defer></script>
|
|
|
|
|
|
|
|
|
|
{% elif not user %}
|
|
|
|
|
|
<div class="page-wrapper">
|
|
<!-- Page header -->
|
|
<div class="page-header mt-0 d-print-none">
|
|
<div class="container-xl">
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col">
|
|
<!-- Page pre-title -->
|
|
<div class="page-pretitle">
|
|
OpenPanel
|
|
</div>
|
|
<h2 class="page-title">
|
|
Users
|
|
</h2>
|
|
</div>
|
|
<!-- Page title actions -->
|
|
<div class="col-auto ms-auto d-print-none">
|
|
<div class="btn-list">
|
|
<a href="#" id="addUserButton" class="btn btn-primary d-none d-sm-inline-block" data-bs-toggle="collapse" data-bs-target="#collapseAddNewUser" aria-expanded="false" aria-controls="collapseAddNewUser">
|
|
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 5l0 14"></path><path d="M5 12l14 0"></path></svg>New User</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- ovo je duplo i u not user -->
|
|
|
|
<div class="collapse mb-4 card" id="collapseAddNewUser">
|
|
|
|
|
|
|
|
<div class="card-header">
|
|
<ul class="nav nav-tabs card-header-tabs nav-fill" data-bs-toggle="tabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#tabs-create-user" class="nav-link active" data-bs-toggle="tab" aria-selected="true" role="tab" tabindex="-1"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-user-plus"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" /><path d="M16 19h6" /><path d="M19 16v6" /><path d="M6 21v-2a4 4 0 0 1 4 -4h4" /></svg> Create User</a>
|
|
</li>
|
|
|
|
<li class="nav-item" role="presentation">
|
|
<a href="#tabs-import-user" class="nav-link" data-bs-toggle="tab" aria-selected="false" role="tab"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-user-down"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" /><path d="M6 21v-2a4 4 0 0 1 4 -4h4c.342 0 .674 .043 .99 .124" /><path d="M19 16v6" /><path d="M22 19l-3 3l-3 -3" /></svg> Import User</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="tab-content">
|
|
<div class="tab-pane active show" id="tabs-create-user" role="tabpanel">
|
|
|
|
<!-- Form for adding new users -->
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-md-6 offset-md-3">
|
|
<h2 class="mb-3">Create a New User</h2>
|
|
<p></p>
|
|
<form id="userForm">
|
|
<div class="form-group">
|
|
<label for="admin_email">Email address:</label>
|
|
<input type="email" class="form-control" name="admin_email" id="admin_email" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="plan_name">Plan:</label>
|
|
<div class="input-group">
|
|
<select class="form-select" size="3" name="plan_name" id="plan_name" aria-label="size 3 select plan_name" required>
|
|
{% for plan in plans %}
|
|
<option value="{{ plan.name }}" {% if loop.first %}selected{% endif %}>{{ plan.name }} - {{ plan.description }} (docker image: {{ plan.docker_image }})</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<div class="col-md-6">
|
|
<label for="admin_username">Username:</label>
|
|
<input type="text" class="form-control" name="admin_username" id="admin_username" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="admin_password">Password:</label>
|
|
<div class="input-group">
|
|
<input type="password" class="form-control" name="admin_password" id="admin_password">
|
|
<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>
|
|
</div>
|
|
|
|
|
|
<br>
|
|
<button type="button" class="btn btn-primary" id="CreateUserButton">Create User</button>
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
<div class="tab-pane" id="tabs-import-user" role="tabpanel">
|
|
|
|
<!-- Form for importing users -->
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-md-6 offset-md-3">
|
|
<h2 class="mb-3">Import User from cPanel <span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span></h2>
|
|
<p></p>
|
|
<form id="userimportForm" method="POST" action="/import/cpanel">
|
|
<div class="form-group">
|
|
<label for="admin_email">Backup file:</label>
|
|
<input type="text" class="form-control" id="path" name="path" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="plan_name">Plan:</label>
|
|
<div class="input-group">
|
|
<select class="form-select" size="3" name="plan_name" id="plan_name" aria-label="size 3 select plan_name" required>
|
|
{% for plan in plans %}
|
|
<option value="{{ plan.name }}" {% if loop.first %}selected{% endif %}>{{ plan.name }} - {{ plan.description }} (docker image: {{ plan.docker_image }})</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<br>
|
|
<button type="submit" class="btn btn-primary" id="ImportUserButton">Import from Backup</button>
|
|
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
{% endblock %}
|