This commit is contained in:
62
templates/Maketank/user/2fa.html.twig
Normal file
62
templates/Maketank/user/2fa.html.twig
Normal file
@@ -0,0 +1,62 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
{% if userinfo.type_2fa == 0 %}
|
||||
{% set linkeraction = 'preadd' %}
|
||||
{% elseif userinfo['2fa_unsaved'] is defined and userinfo['2fa_unsaved'] %}
|
||||
{% set linkeraction = 'add' %}
|
||||
{% else %}
|
||||
{% set linkeraction = 'delete' %}
|
||||
{% endif %}
|
||||
<form action="{{ linker({'section':'index','action':linkeraction}) }}" class="col-12 max-w-420 d-flex flex-column" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ lng('login.2fa') }}</h5>
|
||||
|
||||
<div>
|
||||
{% if userinfo.type_2fa == 0 %}
|
||||
<label for="type_2fa" class="col-form-label">{{ lng('2fa.2fa_overview_desc')|raw }}</label>
|
||||
<select class="form-select" name="type_2fa" id="type_2fa" required>
|
||||
{% for val,opt in type_select_values %}
|
||||
<option value="{{ val }}">{{ opt }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
{% elseif userinfo.type_2fa == 2 %}
|
||||
<label for="qrcode" class="col-form-label">{{ lng('2fa.2fa_ga_desc')|raw }}</label>
|
||||
<img src="{{ ga_qrcode }}" class="img-fluid" alt="QRCode" id="qrcode"/><br>
|
||||
<span>Code: <code>{{ userinfo.data_2fa }}</code></span>
|
||||
{% endif %}
|
||||
|
||||
{% if userinfo['2fa_unsaved'] is defined and userinfo['2fa_unsaved'] %}
|
||||
<br>
|
||||
<label for="codevalidation" class="col-form-label">{{ lng('login.2facode') }}</label>
|
||||
<input type="text" name="codevalidation" id="codevalidation" class="form-control" required/>
|
||||
<input type="hidden" name="type_2fa" id="type_2fa" value="{{ userinfo.type_2fa }}"/>
|
||||
<input type="hidden" name="data_2fa" id="data_2fa" value="{{ userinfo.data_2fa }}"/>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body d-grid gap-2">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
|
||||
<input type="hidden" name="page" value="{{ page }}"/>
|
||||
<input type="hidden" name="send" value="send"/>
|
||||
{% if userinfo.type_2fa == 0 %}
|
||||
<button class="btn btn-primary rounded-top-0" type="submit" name="preadd">
|
||||
{{ lng('2fa.2fa_add') }}</button>
|
||||
{% elseif userinfo['2fa_unsaved'] is defined and userinfo['2fa_unsaved'] %}
|
||||
<button class="btn btn-primary rounded-top-0" type="submit" name="add">
|
||||
{{ lng('2fa.2fa_add') }}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-warning rounded-top-0" type="submit" name="delete">
|
||||
{{ lng('2fa.2fa_delete') }}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
34
templates/Maketank/user/change_language.html.twig
Normal file
34
templates/Maketank/user/change_language.html.twig
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<form action="{{ linker({'section':'index'}) }}" class="col-12 max-w-420 d-flex flex-column" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ lng('menue.main.changelanguage') }}</h5>
|
||||
|
||||
<div>
|
||||
<label for="def_language" class="col-form-label">{{ lng('login.language') }}</label>
|
||||
<select class="form-select" name="def_language" id="def_language" required>
|
||||
<option value="profile">{{ lng('login.profile_lng') }}</option>
|
||||
{% for val,lang in languages %}
|
||||
<option value="{{ val }}" {% if default_lang == val %} selected="selected" {% endif %}>{{ lang|raw }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body d-grid gap-2">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
|
||||
<input type="hidden" name="page" value="{{ page }}"/>
|
||||
<input type="hidden" name="send" value="send"/>
|
||||
<button class="btn btn-primary rounded-top-0" type="submit" name="dosave">
|
||||
<i class="fa-regular fa-floppy-disk"></i>
|
||||
{{ lng('menue.main.changelanguage') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
57
templates/Maketank/user/change_password.html.twig
Normal file
57
templates/Maketank/user/change_password.html.twig
Normal file
@@ -0,0 +1,57 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<form action="{{ linker({'section':'index'}) }}" class="col-12 max-w-420 d-flex flex-column" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ lng('menue.main.changepassword') }}</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="old_password" class="col-form-label">{{ lng('changepassword.old_password') }}</label>
|
||||
<input class="form-control" type="password" name="old_password" id="old_password" value="" required/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_password" class="col-form-label">{{ lng('changepassword.new_password') }}</label>
|
||||
<input class="form-control" type="password" name="new_password" id="new_password" value="" required/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_password_confirm" class="col-form-label">{{ lng('changepassword.new_password_confirm') }}</label>
|
||||
<input class="form-control" type="password" name="new_password_confirm" id="new_password_confirm" value="" required/>
|
||||
</div>
|
||||
|
||||
{% if userinfo.adminsession == 0 %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="change_main_ftp" class="col-form-label">{{ lng('changepassword.also_change_ftp') }}</label>
|
||||
<div class="form-check form-switch">
|
||||
<input type="hidden" name="change_main_ftp" value="false">
|
||||
<input class="form-check-input" type="checkbox" name="change_main_ftp" id="change_main_ftp" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="change_stats" class="col-form-label">{{ lng('changepassword.also_change_stats') }}</label>
|
||||
<div class="form-check form-switch">
|
||||
<input type="hidden" name="change_stats" value="false">
|
||||
<input class="form-check-input" type="checkbox" name="change_stats" id="change_stats" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="card-body d-grid gap-2">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
|
||||
<input type="hidden" name="page" value="{{ page }}"/>
|
||||
<input type="hidden" name="send" value="send"/>
|
||||
<button class="btn btn-primary rounded-top-0" type="submit" name="dosave">
|
||||
<i class="fa-regular fa-floppy-disk"></i>
|
||||
{{ lng('menue.main.changepassword') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
34
templates/Maketank/user/change_theme.html.twig
Normal file
34
templates/Maketank/user/change_theme.html.twig
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<form action="{{ linker({'section':'index'}) }}" class="col-12 max-w-420 d-flex flex-column" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ lng('menue.main.changetheme') }}</h5>
|
||||
|
||||
<div>
|
||||
<label for="theme" class="col-form-label">{{ lng('panel.theme') }}</label>
|
||||
<select class="form-select" name="theme" id="theme" required>
|
||||
{% for val,t in themes %}
|
||||
<option value="{{ val }}" {% if default_theme == val %} selected="selected" {% endif %}>{{ t|raw }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body d-grid gap-2">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
|
||||
<input type="hidden" name="page" value="{{ page }}"/>
|
||||
<input type="hidden" name="send" value="send"/>
|
||||
<button class="btn btn-primary rounded-top-0" type="submit" name="dosave">
|
||||
<i class="fa-regular fa-floppy-disk"></i>
|
||||
{{ lng('menue.main.changetheme') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
31
templates/Maketank/user/dashboard-item.html.twig
Normal file
31
templates/Maketank/user/dashboard-item.html.twig
Normal file
@@ -0,0 +1,31 @@
|
||||
{% macro ditem(lngstr, available, used, assigned = null, formatbytes = false, byte_usage = null) %}
|
||||
<div class="col border-end border-bottom p-3">
|
||||
<div class="row mb-1">
|
||||
<div class="col text-truncate">{{ lng(lngstr) }}{% if byte_usage %} <small>({{ byte_usage|formatBytes }})</small>{% endif %}</div>
|
||||
<div class="col-auto">
|
||||
<small>{% if formatbytes %}{{ used|formatBytes }}{% else %}{{ used }}{% endif %}/{% if available < 0 %}{{ lng('panel.unlimited') }}{% else %}{% if formatbytes %}{{ available|formatBytes }}{% else %}{{ available }}{% endif %}{% endif %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress progress-thin my-auto">
|
||||
{% set usageperc = 1 %}
|
||||
{% if available > 0 %}
|
||||
{% set usageperc = (used / available) * 100|round %}
|
||||
{% endif %}
|
||||
<div
|
||||
class="progress-bar{% if available < 0 %} bg-secondary{% elseif usageperc >= 75 and usageperc < 90 %} bg-warning{% elseif usageperc >= 90 %} bg-danger{% endif %}"
|
||||
role="progressbar"
|
||||
style="width: {% if available < 0 %}100{% else %}{{ usageperc }}{% endif %}%;"
|
||||
aria-valuenow="{% if available < 0 %}100{% else %}{{ used }}{% endif %}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="{% if available < 0 %}100{% else %}{{ available }}{% endif %}"></div>
|
||||
</div>
|
||||
{% if assigned is not empty %}
|
||||
<div class="progress progress-thin mt-2 my-auto">
|
||||
<div class="progress-bar bg-primary" role="progressbar"
|
||||
style="width:{% if available > 0 %}{{ (assigned / available) * 100|round }}{% else %}1{% endif %}%;"
|
||||
aria-valuenow="{{ assigned }}" aria-valuemin="0"
|
||||
aria-valuemax="{{ available }}"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
34
templates/Maketank/user/dns-editor.html.twig
Normal file
34
templates/Maketank/user/dns-editor.html.twig
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "Froxlor/user/table.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pb-2">
|
||||
{% include 'Froxlor/misc/alertbox.html.twig' %}
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs mb-3" id="ex1" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link active" id="ex1-tab-1" data-bs-toggle="tab" href="#ex1-tabs-1" role="tab" aria-controls="ex1-tabs-1" aria-selected="true">DNS Editor</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="ex1-tab-2" data-bs-toggle="tab" href="#ex1-tabs-2" role="tab" aria-controls="ex1-tabs-2" aria-selected="false">DNS Zone</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="ex1-content">
|
||||
<div class="tab-pane fade show active" id="ex1-tabs-1" role="tabpanel" aria-labelledby="ex1-tab-1">
|
||||
{{ parent() }}
|
||||
|
||||
{% import "Froxlor/form/form.html.twig" as form %}
|
||||
{{ form.form(formdata, formaction|default('#'), formdata.title, editid|default('')) }}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="ex1-tabs-2" role="tabpanel" aria-labelledby="ex1-tab-2">
|
||||
{% if zonefile is not empty %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<textarea class="logcontent form-control" rows="25" cols="60" readonly>{{ zonefile }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
26
templates/Maketank/user/error_report.html.twig
Normal file
26
templates/Maketank/user/error_report.html.twig
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
<div>
|
||||
<h5 class="mb-1">
|
||||
<i class="fa-solid fa-bug me-1"></i>
|
||||
{{ lng('error.send_report_title') }}
|
||||
</h5>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ linker({'section':'index','page':'send_error_report','errorid':errorid}) }}" class="col-12 d-flex flex-column" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="alert alert-primary" role="alert">{{ lng('error.send_report_desc')|raw }}</div>
|
||||
<code class="border rounded bg-white p-2 mb-3">{{ mail_html|nl2br }}</code>
|
||||
|
||||
<div>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
|
||||
<input type="hidden" name="send" value="send"/>
|
||||
|
||||
<div class="col-12 text-end">
|
||||
<button type="submit" class="btn btn-primary">{{ lng('error.send_report') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
16
templates/Maketank/user/form-datatable.html.twig
Normal file
16
templates/Maketank/user/form-datatable.html.twig
Normal file
@@ -0,0 +1,16 @@
|
||||
{% extends "Froxlor/user/form.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
{% if tabledata.table.tr is not empty and tabledata.table.tr is iterable %}
|
||||
<div class="row mb-2">
|
||||
{% set type = 'warning' %}
|
||||
{% set alert_msg = lng('error.customerhasongoingbackupjob') %}
|
||||
{% include 'Froxlor/misc/alertbox.html.twig' %}
|
||||
</div>
|
||||
{% import "Froxlor/table/table.html.twig" as table %}
|
||||
{{ table.table(tabledata) }}
|
||||
{% endif %}
|
||||
|
||||
{{ parent() }}
|
||||
|
||||
{% endblock %}
|
||||
10
templates/Maketank/user/form-note.html.twig
Normal file
10
templates/Maketank/user/form-note.html.twig
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends "Froxlor/user/form.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
{% if alert_msg is defined and alert_msg is not empty %}
|
||||
<div class="mb-4">
|
||||
{% include 'Froxlor/misc/alertbox.html.twig' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
23
templates/Maketank/user/form-replacers.html.twig
Normal file
23
templates/Maketank/user/form-replacers.html.twig
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "Froxlor/user/form.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ parent() }}
|
||||
|
||||
{% if replacers is not empty and replacers is iterable %}
|
||||
<div class="card my-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ lng('admin.templates.template_replace_vars') }}</h5>
|
||||
<dl class="row">
|
||||
{% for replacer in replacers.replacers %}
|
||||
{% if (replacer.visible is defined and replacer.visible) or replacer.visible is not defined %}
|
||||
<dt class="col-sm-3">{{ '{' }}{{ replacer.var }}{{ '}' }}</dt>
|
||||
<dd class="col-sm-9">{{ replacer.description }}</dd>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
57
templates/Maketank/user/form.html.twig
Normal file
57
templates/Maketank/user/form.html.twig
Normal file
@@ -0,0 +1,57 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
|
||||
{% if formdata.title is not empty %}
|
||||
<div>
|
||||
<h5 class="mb-1">
|
||||
{% if formdata.image is not empty %}
|
||||
<i class="{{ formdata.image }} me-1"></i>
|
||||
{% endif %}
|
||||
{{ formdata.title }}
|
||||
</h5>
|
||||
{% if formdata.description is not empty %}
|
||||
<span class="text-muted">{{ formdata.description }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
|
||||
{% if formdata.self_overview is defined and formdata.self_overview is iterable %}
|
||||
{% if actions_links is not defined %}{% set actions_links = [] %}{% endif %}
|
||||
{% set actions_tmp = actions_links %}
|
||||
{% set actions_links = {'href': linker(formdata.self_overview), 'icon': 'fa-solid fa-reply','label': lng('panel.backtooverview')} %}
|
||||
{% set actions_links = {actions_links}|merge(actions_tmp) %}
|
||||
{% endif %}
|
||||
|
||||
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}
|
||||
<div>
|
||||
{% if actions_links is iterable %}
|
||||
{% for link in actions_links %}
|
||||
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
|
||||
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i><span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{# TODO: eventually not used anymore because of using a documentation link
|
||||
{% if entity_info is defined and entity_info is not empty %}
|
||||
<div class="alert alert-info" role="alert">
|
||||
{{ entity_info|raw }}
|
||||
</div>
|
||||
{% endif %}
|
||||
#}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% import "Froxlor/form/form.html.twig" as form %}
|
||||
|
||||
{{ form.form(formdata, formaction|default('#'), formdata.title, editid|default(''), false, idprefix|default('')) }}
|
||||
|
||||
{% endblock %}
|
||||
0
templates/Maketank/user/index.html
Normal file
0
templates/Maketank/user/index.html
Normal file
329
templates/Maketank/user/index.html.twig
Normal file
329
templates/Maketank/user/index.html.twig
Normal file
@@ -0,0 +1,329 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<h3 class="page-header">{{ lng('panel.dashboard') }}</h3>
|
||||
|
||||
{% if get_setting('panel.is_configured') == 0 and userinfo.adminsession == 1 and userinfo.change_serversettings == 1 %}
|
||||
<div class="alert alert-info position-relative p-5">
|
||||
<h3>{{ lng('welcome.title') }}</h3>
|
||||
<p class="lead mb-5">{{ lng('welcome.config_note') }}</p>
|
||||
<a class="btn btn-lg btn-light text-info" href="{{ linker({'section': 'configfiles', 'page': 'configfiles'}) }}">{{ lng('welcome.config_now') }}</a>
|
||||
<aside class="position-absolute bottom-0 end-0 p-5 d-none d-md-block">
|
||||
<i class="fa-solid fa-hat-wizard fa-5x"></i>
|
||||
</aside>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
{% import "Froxlor/user/dashboard-item.html.twig" as dashboard %}
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
{# admin-resources #}
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-xl-5 g-0">
|
||||
{{ dashboard.ditem('admin.customers', userinfo.customers, overview.number_customers) }}
|
||||
{{ dashboard.ditem('admin.domains', userinfo.domains, overview.number_domains) }}
|
||||
{{ dashboard.ditem('customer.diskspace', userinfo.diskspace_bytes, overview.diskspace_bytes_used, overview.diskspace_bytes, true) }}
|
||||
{{ dashboard.ditem('customer.traffic', userinfo.traffic_bytes, overview.traffic_bytes_used, overview.traffic_bytes, true) }}
|
||||
{{ dashboard.ditem('customer.subdomains', userinfo.subdomains, overview.subdomains_used, overview.subdomains_assigned) }}
|
||||
{{ dashboard.ditem('customer.mysqls', userinfo.mysqls, overview.mysqls_used, overview.mysqls_assigned) }}
|
||||
{{ dashboard.ditem('customer.emails', userinfo.emails, overview.emails_used, overview.emails_assigned) }}
|
||||
{{ dashboard.ditem('customer.accounts', userinfo.email_accounts, overview.email_accounts_used, overview.email_accounts_assigned) }}
|
||||
{{ dashboard.ditem('customer.forwarders', userinfo.email_forwarders, overview.email_forwarders_used, overview.email_forwarders_assigned) }}
|
||||
{{ dashboard.ditem('customer.ftps', userinfo.ftps, overview.ftps_used, overview.ftps_assigned) }}
|
||||
</div>
|
||||
{% else %}
|
||||
{# customer-resources #}
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-xl-4 g-0">
|
||||
{{ dashboard.ditem('customer.total_diskspace', userinfo.diskspace_bytes, userinfo.total_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.diskspace', userinfo.diskspace_bytes, userinfo.diskspace_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.traffic', userinfo.traffic_bytes, userinfo.traffic_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.subdomains', userinfo.subdomains, userinfo.subdomains_used) }}
|
||||
{{ dashboard.ditem('customer.mysqls', userinfo.mysqls, userinfo.mysqls_used, null, false, userinfo.dbspace_used) }}
|
||||
{{ dashboard.ditem('customer.emails', userinfo.emails, userinfo.emails_used) }}
|
||||
{{ dashboard.ditem('customer.accounts', userinfo.email_accounts, userinfo.email_accounts_used, null, false, userinfo.mailspace_used) }}
|
||||
{{ dashboard.ditem('customer.forwarders', userinfo.email_forwarders, userinfo.email_forwarders_used) }}
|
||||
{{ dashboard.ditem('customer.ftps', userinfo.ftps, userinfo.ftps_used) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
<div
|
||||
class="col-12 col-lg-6">
|
||||
{# system infos #}
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-gears me-1"></i>
|
||||
{{ lng('admin.systemdetails') }}
|
||||
<div class="float-end">
|
||||
<button id="copySysInfo" class="btn btn-outline-dark" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .5rem;" title="Copy to clipboard"><i class="fa-solid fa-copy"></i></button>
|
||||
</div>
|
||||
<div id="ccSysInfo" class="d-none">
|
||||
- Froxlor: {{ call_static('\\Froxlor\\Froxlor', 'getVersionString') }}
|
||||
- {{ lng('serversettings.update_channel.title') }}: {{ get_setting('system.update_channel') }}
|
||||
- {{ lng('admin.serversoftware') }}: {{ sysinfo.webserver }}
|
||||
- {{ lng('admin.phpversion') }}: {{ sysinfo.phpversion }}
|
||||
- {{ lng('admin.mysqlserverversion') }}: {{ sysinfo.mysqlserverversion }}
|
||||
- {{ lng('admin.webserverinterface') }}: {{ sysinfo.phpsapi }}
|
||||
- Kernel: {{ sysinfo.kernel }}
|
||||
- OS: {{ get_setting('system.distribution') }}
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.hostname') }}</div>
|
||||
{{ sysinfo.hostname }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.serversoftware') }}</div>
|
||||
{{ sysinfo.webserver }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.phpversion') }}</div>
|
||||
<a href="{{ linker({'section':'settings','page':'phpinfo'}) }}">{{ sysinfo.phpversion }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.mysqlserverversion') }}</div>
|
||||
{{ sysinfo.mysqlserverversion }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.webserverinterface') }}</div>
|
||||
{{ sysinfo.phpsapi }}
|
||||
</div>
|
||||
</li>
|
||||
{% if sysinfo.memory is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.memory') }}</div>
|
||||
<pre>{{ sysinfo.memory }}</pre>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.sysload') }}</div>
|
||||
{{ sysinfo.load }}
|
||||
</div>
|
||||
</li>
|
||||
{% if sysinfo.kernel is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">Kernel</div>
|
||||
{{ sysinfo.kernel }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if sysinfo.uptime is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">Uptime</div>
|
||||
{{ sysinfo.uptime }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if userinfo.custom_notes is not empty and userinfo.custom_notes_show == 1 %}
|
||||
<div class="card mb-3">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item list-group-item-info d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
{{ userinfo.custom_notes|nl2br|raw }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="col-12 col-md-6 col-lg-4">
|
||||
{# account info #}
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-user me-1"></i>
|
||||
{{ lng('index.accountdetails') }}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('login.username') }}</div>
|
||||
{{ userinfo.loginname }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.email') }}</div>
|
||||
{{ userinfo.email }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.services') }}</div>
|
||||
{% if userinfo.imap == 1 %}
|
||||
<span class="badge bg-success">IMAP</span>
|
||||
{% endif %}
|
||||
{% if userinfo.pop3 == 1 %}
|
||||
<span class="badge bg-success">POP3</span>
|
||||
{% endif %}
|
||||
{% if userinfo.phpenabled == 1 %}
|
||||
<span class="badge bg-success">PHP</span>
|
||||
{% endif %}
|
||||
{% if userinfo.perlenabled == 1 %}
|
||||
<span class="badge bg-success">Perl/CGI</span>
|
||||
{% endif %}
|
||||
{% if userinfo.api_allowed == 1 %}
|
||||
<a href="{{ linker({'section':'index','page':'apikeys'}) }}">
|
||||
<span class="badge bg-success">API</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% if stdsubdomain is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('admin.stdsubdomain') }}</div>
|
||||
{{ stdsubdomain }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.domains') }}</div>
|
||||
{% for domain in domains %}
|
||||
{{ domain }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<span class="badge bg-primary rounded-pill">{{ domains|length }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-12 col-md-6 col-lg-4">
|
||||
{# customer details #}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-id-card me-1"></i>
|
||||
{{ lng('index.customerdetails') }}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
{% if userinfo.customernumber is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.customernumber') }}</div>
|
||||
{{ userinfo.customernumber }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if userinfo.company is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.company') }}</div>
|
||||
{{ userinfo.company }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if userinfo.name is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.name') }}</div>
|
||||
{{ userinfo.firstname }}
|
||||
{{ userinfo.name }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if userinfo.street is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.street') }}</div>
|
||||
{{ userinfo.street }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if userinfo.city is not empty %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('customer.zipcode') }}/{{ lng('customer.city') }}</div>
|
||||
{{ userinfo.zipcode }}
|
||||
{{ userinfo.city }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if userinfo.custom_notes is not empty and userinfo.custom_notes_show == 1 %}
|
||||
<li class="list-group-item list-group-item-info d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
{{ userinfo.custom_notes|nl2br|raw }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-12 {% if userinfo.adminsession == 1 %}col-lg-6{% else %}col-lg-4{% endif %}">
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
{# froxlor-details #}
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-wrench me-1"></i>
|
||||
{{ lng('admin.froxlordetails') }}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
<div class="fw-bold">{{ lng('tasks.outstanding_tasks') }}</div>
|
||||
{% for task in outstanding_tasks %}
|
||||
<i class="fa-regular fa-clock"></i>
|
||||
{{ task.desc }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</li>
|
||||
{% for cronrun in cron_last_runs %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">{{ cronrun.title }}</div>
|
||||
<span class="badge bg-primary">
|
||||
{% if cronrun.lastrun > 0 %}
|
||||
{{ cronrun.lastrun|date('d.m.Y H:i') }}
|
||||
{% else %}
|
||||
{{ lng('cronjobs.notyetrun') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if (get_setting('admin.show_news_feed') == 1 and userinfo.adminsession == 1) or (get_setting('customer.show_news_feed') == 1 and userinfo.adminsession == 0) %}
|
||||
<div id="newsfeed" class="card" {% if userinfo.adminsession == 0 %} data-role="customer" {% endif %}>
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-info-circle me-1"></i>
|
||||
{% if get_setting('customer.news_feed_url') is empty %}Froxlor
|
||||
{% endif %}Newsfeed
|
||||
</div>
|
||||
<div class="list-group list-group-flush" id="newsfeeditems">
|
||||
<div class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto">
|
||||
Loading newsfeed...
|
||||
</div>
|
||||
<span>
|
||||
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
2
templates/Maketank/user/inline-form.html.twig
Normal file
2
templates/Maketank/user/inline-form.html.twig
Normal file
@@ -0,0 +1,2 @@
|
||||
{% import "Froxlor/form/form.html.twig" as form %}
|
||||
{{ form.form(formdata, formaction|default('#'), formdata.title, editid|default(''), true, idprefix|default('')) }}
|
||||
47
templates/Maketank/user/logfiles.html.twig
Normal file
47
templates/Maketank/user/logfiles.html.twig
Normal file
@@ -0,0 +1,47 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
<div>
|
||||
<h5 class="mb-1">
|
||||
<i class="fa-solid fa-magnifying-glass me-1"></i>
|
||||
{{ lng('panel.viewlogs') }}
|
||||
</h5>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
|
||||
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}
|
||||
<div>
|
||||
{% if actions_links is iterable %}
|
||||
{% for link in actions_links %}
|
||||
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
|
||||
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i>
|
||||
<span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<ul class="nav nav-tabs mb-3" id="ex1" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link active" id="ex1-tab-1" data-bs-toggle="tab" href="#ex1-tabs-1" role="tab" aria-controls="ex1-tabs-1" aria-selected="true">Error log</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="ex1-tab-2" data-bs-toggle="tab" href="#ex1-tabs-2" role="tab" aria-controls="ex1-tabs-2" aria-selected="false">Access log</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="ex1-content">
|
||||
<div class="tab-pane fade show active" id="ex1-tabs-1" role="tabpanel" aria-labelledby="ex1-tab-1">
|
||||
<textarea rows="16" class="logcontent" readonly>{{ error_log_content }}</textarea>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="ex1-tabs-2" role="tabpanel" aria-labelledby="ex1-tab-2">
|
||||
<textarea rows="16" class="logcontent" readonly>{{ access_log_content }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
9
templates/Maketank/user/newsfeeditem.html.twig
Normal file
9
templates/Maketank/user/newsfeeditem.html.twig
Normal file
@@ -0,0 +1,9 @@
|
||||
<a href="{{ link|default('#')|raw }}" class="list-group-item list-group-item-action" target="_blank">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<b class="mb-1">{{ title }}</b>
|
||||
{% if date is not empty %}
|
||||
<small>{{ date }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="small mb-1">{{ content|raw }}</p>
|
||||
</a>
|
||||
163
templates/Maketank/user/resource-counter.html.twig
Normal file
163
templates/Maketank/user/resource-counter.html.twig
Normal file
@@ -0,0 +1,163 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
<h5 class="mb-1">
|
||||
<i class="fa-solid fa-calculator me-1"></i>
|
||||
{{ lng('admin.updatecounters') }}
|
||||
</h5>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for usersection,data in counters|reverse(true) %}
|
||||
<div class="card table-responsive">
|
||||
<table class="table table-borderless table-striped align-middle mb-0 px-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="3">{{ lng('admin.' ~ usersection) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in data %}
|
||||
<tr>
|
||||
{% if usersection == 'customers' %}
|
||||
<th class="px-3 w-50" scope="row">
|
||||
{{ call_static('\\Froxlor\\User', 'getCorrectUserSalutation', [user]) }}
|
||||
(<a href="{{ linker({'section': 'customers', 'page':'customers','action': 'su','id':user.customerid}) }}">{{ user.loginname }}</a>)
|
||||
</th>
|
||||
<td class="px-3 w-25">
|
||||
{{ lng('customer.subdomains') }}:
|
||||
<span class="{% if user.subdomains_used == user.subdomains_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.subdomains_used }}
|
||||
->
|
||||
{{ user.subdomains_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.mysqls') }}:
|
||||
<span class="{% if user.mysqls_used == user.mysqls_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.mysqls_used }}
|
||||
->
|
||||
{{ user.mysqls_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.ftps') }}:
|
||||
<span class="{% if user.ftps_used == user.ftps_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.ftps_used }}
|
||||
->
|
||||
{{ user.ftps_used_new }}</b>
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 w-25">
|
||||
{{ lng('customer.emails') }}:
|
||||
<span class="{% if user.emails_used == user.emails_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.emails_used }}
|
||||
->
|
||||
{{ user.emails_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.accounts') }}:
|
||||
<span class="{% if user.email_accounts_used == user.email_accounts_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_accounts_used }}
|
||||
->
|
||||
{{ user.email_accounts_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.forwarders') }}:
|
||||
<span class="{% if user.email_forwarders_used == user.email_forwarders_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_forwarders_used }}
|
||||
->
|
||||
{{ user.email_forwarders_used_new }}</b>
|
||||
</span>
|
||||
{% if get_setting('system.mail_quota_enabled') == 1 %}
|
||||
<br/>{{ lng('customer.email_quota') }}:
|
||||
<span class="{% if user.email_quota_used == user.email_quota_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_quota_used }}
|
||||
->
|
||||
{{ user.email_quota_used_new }}</b>
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% else %}
|
||||
<th class="px-3 w-50" scope="row">
|
||||
{{ user.name }}
|
||||
{% if user.adminid != call_static('\\Froxlor\\CurrentUser', 'getField', ['adminid']) %}
|
||||
(<a href="{{ linker({'section': 'admins', 'page':'admins','action': 'su','id':user.adminid}) }}">{{ user.loginname }}</a>)
|
||||
{% endif %}
|
||||
</th>
|
||||
<td class="px-3 w-25">
|
||||
{{ lng('admin.customers') }}:
|
||||
<span class="{% if user.customers_used == user.customers_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.customers_used }}
|
||||
->
|
||||
{{ user.customers_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.domains') }}:
|
||||
<span class="{% if user.domains_used == user.domains_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.domains_used }}
|
||||
->
|
||||
{{ user.domains_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.subdomains') }}:
|
||||
<span class="{% if user.subdomains_used == user.subdomains_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.subdomains_used }}
|
||||
->
|
||||
{{ user.subdomains_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.diskspace') }}:
|
||||
<span class="{% if user.diskspace_used == user.diskspace_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ (user.diskspace_used * 1024)|formatBytes }}
|
||||
->
|
||||
{{ (user.diskspace_used_new * 1024)|formatBytes }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.traffic') }}:
|
||||
<span class="{% if user.traffic_used == user.traffic_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ (user.traffic_used * 1024)|formatBytes }}
|
||||
->
|
||||
{{ (user.traffic_used_new * 1024)|formatBytes }}</b>
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 w-25">
|
||||
{{ lng('customer.mysqls') }}:
|
||||
<span class="{% if user.mysqls_used == user.mysqls_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.mysqls_used }}
|
||||
->
|
||||
{{ user.mysqls_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.ftps') }}:
|
||||
<span class="{% if user.ftps_used == user.ftps_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.ftps_used }}
|
||||
->
|
||||
{{ user.ftps_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.emails') }}:
|
||||
<span class="{% if user.emails_used == user.emails_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.emails_used }}
|
||||
->
|
||||
{{ user.emails_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.accounts') }}:
|
||||
<span class="{% if user.email_accounts_used == user.email_accounts_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_accounts_used }}
|
||||
->
|
||||
{{ user.email_accounts_used_new }}</b>
|
||||
</span><br/>
|
||||
{{ lng('customer.forwarders') }}:
|
||||
<span class="{% if user.email_forwarders_used == user.email_forwarders_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_forwarders_used }}
|
||||
->
|
||||
{{ user.email_forwarders_used_new }}</b>
|
||||
</span>
|
||||
{% if get_setting('system.mail_quota_enabled') == 1 %}
|
||||
<br/>{{ lng('customer.email_quota') }}:
|
||||
<span class="{% if user.email_quota_used == user.email_quota_used_new %}text-success{% else %}warning{% endif %}">
|
||||
<b>{{ user.email_quota_used }}
|
||||
->
|
||||
{{ user.email_quota_used_new }}</b>
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
8
templates/Maketank/user/table-note.html.twig
Normal file
8
templates/Maketank/user/table-note.html.twig
Normal file
@@ -0,0 +1,8 @@
|
||||
{% extends "Froxlor/user/table.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pb-2">
|
||||
{% include 'Froxlor/misc/alertbox.html.twig' %}
|
||||
</div>
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
18
templates/Maketank/user/table-tpl.html.twig
Normal file
18
templates/Maketank/user/table-tpl.html.twig
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "Froxlor/user/table.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
{% set listing = maillisting %}
|
||||
{{ parent() }}
|
||||
|
||||
{% set listing = filelisting %}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% set listing = maillisting %}
|
||||
{{ parent() }}
|
||||
|
||||
{% set listing = filelisting %}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
60
templates/Maketank/user/table.html.twig
Normal file
60
templates/Maketank/user/table.html.twig
Normal file
@@ -0,0 +1,60 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
|
||||
{% if listing.title is not empty %}
|
||||
<h5 class="mb-1">
|
||||
{% if listing.icon is not empty %}
|
||||
<i class="{{ listing.icon }} me-1"></i>
|
||||
{% endif %}
|
||||
{{ listing.title }}
|
||||
{% if listing.total_entries > 0 %}
|
||||
<small>
|
||||
<span class="badge rounded-pill bg-secondary">{{ listing.total_entries }}</span>
|
||||
</small>
|
||||
{% endif %}
|
||||
</h5>
|
||||
{% if listing.description is not empty %}
|
||||
<span class="text-muted mt-2">{{ listing.description }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
|
||||
{% if listing.is_search and listing.self_overview is defined and listing.self_overview is iterable %}
|
||||
{% set actions_tmp = actions_links|default([]) %}
|
||||
{% set actions_links = {'href': linker(listing.self_overview), 'icon': 'fa-solid fa-reply','label': lng('panel.backtooverview')} %}
|
||||
{% set actions_links = {actions_links}|merge(actions_tmp) %}
|
||||
{% endif %}
|
||||
|
||||
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}
|
||||
<div>
|
||||
{% if actions_links is iterable %}
|
||||
{% for link in actions_links %}
|
||||
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
|
||||
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i>
|
||||
<span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{# TODO: eventually not used anymore because of using a documentation link
|
||||
{% if entity_info is defined and entity_info is not empty %}
|
||||
<div class="alert alert-info" role="alert">
|
||||
{{ entity_info|raw }}
|
||||
</div>
|
||||
{% endif %}
|
||||
#}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% import "Froxlor/table/table.html.twig" as table %}
|
||||
|
||||
{{ table.table(listing) }}
|
||||
|
||||
{% endblock %}
|
||||
305
templates/Maketank/user/traffic.html.twig
Normal file
305
templates/Maketank/user/traffic.html.twig
Normal file
@@ -0,0 +1,305 @@
|
||||
{% extends "Froxlor/userarea.html.twig" %}
|
||||
|
||||
{% block heading %}
|
||||
|
||||
<div>
|
||||
<h5 class="mb-1">
|
||||
<i class="fa-solid fa-chart-area me-1"></i>
|
||||
{{ lng('admin.traffic') }}
|
||||
</h5>
|
||||
<span class="text-muted">{{ lng('admin.traffic_sub') }}</span>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Range -->
|
||||
<!-- TODO: set url on change. e.g.: ?param=days:7 -->
|
||||
<div class="d-flex justify-content-center justify-content-md-end">
|
||||
<select class="form-select mb-3 mb-md-4 w-auto mt-md-n4" aria-label="select the traffic range" name="range" data-baseref="{{ linker({'section':'traffic'}) }}">
|
||||
<option value="hours:24" {% if range == 'hours:24' %}selected{% endif %}>{{ lng('traffic.ranges.last24h') }}</option>
|
||||
<option value="days:7" {% if range == 'days:7' %}selected{% endif %}>{{ lng('traffic.ranges.last7d') }}</option>
|
||||
<option value="days:30" {% if range == 'days:30' %}selected{% endif %}>{{ lng('traffic.ranges.last30d') }}</option>
|
||||
<option value="currentmonth" {% if range == 'currentmonth' %}selected{% endif %}>{{ lng('traffic.ranges.cm') }}</option>
|
||||
<option value="months:3" {% if range == 'months:3' %}selected{% endif %}>{{ lng('traffic.ranges.last3m') }}</option>
|
||||
<option value="months:6" {% if range == 'months:6' %}selected{% endif %}>{{ lng('traffic.ranges.last6m') }}</option>
|
||||
<option value="months:12" {% if range == 'months:12' %}selected{% endif %}>{{ lng('traffic.ranges.last12m') }}</option>
|
||||
<option value="currentyear" {% if range == 'currentyear' %}selected{% endif %}>{{ lng('traffic.ranges.cy') }}</option>
|
||||
{% for yd in years_avail %}
|
||||
{% if yd.year != "now"|date('Y') %}
|
||||
<option value="year:{{ yd.year }}" {% if range == 'year:' ~ yd.year %}selected{% endif %}>{{ yd.year }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="row row-cols-1 row-cols-md-2 g-0">
|
||||
<div class="col p-3 border-end">
|
||||
<canvas id="trafficsummary" style="max-height:30vh;"></canvas>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<canvas id="customersummary" style="max-height:30vh;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Overview for given range -->
|
||||
<div class="card">
|
||||
<div class="row row-cols-2 row-cols-md-4 g-0">
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.total|formatBytes }}</h3>
|
||||
<span>{{ lng('traffic.months.total') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.http|formatBytes }}</h3>
|
||||
<span>{{ lng('traffic.http') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.ftp|formatBytes }}</h3>
|
||||
<span>{{ lng('traffic.ftp') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.mail|formatBytes }}</h3>
|
||||
<span>{{ lng('traffic.mail') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
<!-- Overview for given range by user -->
|
||||
<h4 class="page-header">{{ lng('traffic.bycustomers') }}</h4>
|
||||
{% if users is not empty %}
|
||||
<div class="card table-responsive">
|
||||
<table class="table table-borderless table-striped align-middle mb-0 px-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{ lng('login.username') }}</th>
|
||||
<th scope="col">{{ lng('traffic.months.total') }}</th>
|
||||
<th scope="col">{{ lng('traffic.http') }}</th>
|
||||
<th scope="col">{{ lng('traffic.ftp') }}</th>
|
||||
<th scope="col">{{ lng('traffic.mail') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for uid,user in users %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ linker({'section':'customers','page':'customers','action':'su','id':uid}) }}">{{ user.loginname }}</a>
|
||||
</td>
|
||||
<td>{{ user.total|formatBytes }}</td>
|
||||
<td>{{ user.http|formatBytes }}</td>
|
||||
<td>{{ user.ftp|formatBytes }}</td>
|
||||
<td>{{ user.mail|formatBytes }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>{{ lng('traffic.nodata') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
const labelsS = ['{{ lng('traffic.http') }}', '{{ lng('traffic.ftp') }}', '{{ lng('traffic.mail') }}'];
|
||||
|
||||
const dataS = {
|
||||
labels: labelsS,
|
||||
datasets: [{
|
||||
label: '{{ lng('traffic.trafficoverview') }}',
|
||||
backgroundColor: ['rgb(255, 99, 132)', 'rgb(200, 199, 132)', 'rgb(255, 99, 0)'],
|
||||
data: [{value: '{{ metrics.http|default(0) }}', formatted: '{{ metrics.http|formatBytes }}'}, {value: '{{ metrics.ftp|default(0) }}', formatted: '{{ metrics.ftp|formatBytes }}'}, {value: '{{ metrics.mail|default(0) }}', formatted: '{{ metrics.mail|formatBytes }}'}]
|
||||
}]
|
||||
};
|
||||
|
||||
const configS = {
|
||||
type: 'pie',
|
||||
data: dataS,
|
||||
options: {
|
||||
parsing: {
|
||||
key: 'value'
|
||||
},
|
||||
responsive: true,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: '{{ lng('traffic.sumtotal') }}'
|
||||
},
|
||||
legend: {
|
||||
position: 'right'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
usePointStyle: true,
|
||||
callbacks: {
|
||||
label: (data) => {
|
||||
return data.label + ' ' + data.raw.formatted
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sChart = new Chart(document.getElementById('trafficsummary'), configS);
|
||||
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
const labelsC = [];
|
||||
const dataValues = [];
|
||||
{% for user in users|sort((a, b) => a.total <=> b.total)|slice(0, 5) %}
|
||||
labelsC.push('{{ user.loginname }}');
|
||||
dataValues.push({value: '{{ user.total|default(0) }}', formatted: '{{ user.total|formatBytes }}'});
|
||||
{% endfor %}
|
||||
|
||||
const dataC = {
|
||||
labels: labelsC,
|
||||
datasets: [{
|
||||
label: '{{ lng('traffic.top5customers') }}',
|
||||
backgroundColor: ['rgb(255, 99, 132)', 'rgb(200, 199, 132)', 'rgb(255, 99, 0)', 'rgb(100, 100, 132)', 'rgb(240, 150, 232)'],
|
||||
data: dataValues
|
||||
}]
|
||||
};
|
||||
|
||||
const configC = {
|
||||
type: 'pie',
|
||||
data: dataC,
|
||||
options: {
|
||||
parsing: {
|
||||
key: 'value'
|
||||
},
|
||||
responsive: true,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: '{{ lng('traffic.top5customers') }}'
|
||||
},
|
||||
legend: {
|
||||
position: 'right'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
usePointStyle: true,
|
||||
callbacks: {
|
||||
label: (data) => {
|
||||
return data.label + ' ' + data.raw.formatted
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const cChart = new Chart(document.getElementById('customersummary'), configC);
|
||||
|
||||
{% elseif not (range starts with 'hours') %}
|
||||
|
||||
const labelsC = [];
|
||||
const dataValues = [];
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
{% for d,dd in days %}
|
||||
labelsC.push('{{ d }}');
|
||||
{% endfor %}
|
||||
{% elseif range starts with 'months' or range starts with 'year' or range == 'currentyear' %}
|
||||
{% for m,md in months %}
|
||||
labelsC.push('{{ m }}');
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for yr,year in years %}
|
||||
labelsC.push('{{ yr }}');
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
const dataC = {
|
||||
labels: labelsC,
|
||||
datasets: [
|
||||
{
|
||||
label: '{{ lng('traffic.sumhttp') }}',
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.http|default(0) }}', formatted: '{{ dd.http|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
{% elseif range starts with 'months' or range starts with 'year' or range == 'currentyear' %}
|
||||
data: [{% for m,md in months %}{value: '{{ md.http|default(0) }}', formatted: '{{ md.http|formatBytes }}', axisv: '{{ m }}'},{% endfor %}],
|
||||
{% else %}
|
||||
data: [{% for yr,year in years %}{value: '{{ year.http|default(0) }}', formatted: '{{ year.http|formatBytes }}', axisv: '{{ yr }}'},{% endfor %}],
|
||||
{% endif %}
|
||||
parsing: {
|
||||
xAxisKey: 'axisv'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '{{ lng('traffic.sumftp') }}',
|
||||
backgroundColor: 'rgb(200, 199, 132)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.ftp|default(0) }}', formatted: '{{ dd.ftp|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
{% elseif range starts with 'months' or range starts with 'year' or range == 'currentyear' %}
|
||||
data: [{% for m,md in months %}{value: '{{ md.ftp|default(0) }}', formatted: '{{ md.ftp|formatBytes }}', axisv: '{{ m }}'},{% endfor %}],
|
||||
{% else %}
|
||||
data: [{% for yr,year in years %}{value: '{{ year.ftp|default(0) }}', formatted: '{{ year.ftp|formatBytes }}', axisv: '{{ yr }}'},{% endfor %}],
|
||||
{% endif %}
|
||||
parsing: {
|
||||
xAxisKey: 'axisv'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '{{ lng('traffic.summail') }}',
|
||||
backgroundColor: 'rgb(255, 99, 0)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.mail|default(0) }}', formatted: '{{ dd.mail|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
{% elseif range starts with 'months' or range starts with 'year' or range == 'currentyear' %}
|
||||
data: [{% for m,md in months %}{value: '{{ md.ftp|default(0) }}', formatted: '{{ md.ftp|formatBytes }}', axisv: '{{ m }}'},{% endfor %}],
|
||||
{% else %}
|
||||
data: [{% for yr,year in years %}{value: '{{ year.mail|default(0) }}', formatted: '{{ year.mail|formatBytes }}', axisv: '{{ yr }}'},{% endfor %}],
|
||||
{% endif %}
|
||||
parsing: {
|
||||
xAxisKey: 'axisv'
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
const configC = {
|
||||
type: 'line',
|
||||
data: dataC,
|
||||
options: {
|
||||
parsing: {
|
||||
yAxisKey: 'value'
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
},
|
||||
y: {
|
||||
stacked: true
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: '{{ lng('traffic.byrange') }}'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
usePointStyle: true,
|
||||
callbacks: {
|
||||
label: (data) => {
|
||||
return data.raw.formatted
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const cChart = new Chart(document.getElementById('customersummary'), configC);
|
||||
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user