bunkerweb 1.4.0

This commit is contained in:
bunkerity
2022-06-03 17:24:14 +02:00
parent 3a078326c5
commit a9f886804a
5245 changed files with 1432051 additions and 27894 deletions

View File

@@ -1,26 +1,51 @@
{% set template_data = {"javascript": ""} %}
<!doctype html>
<html lang="en" class="h-100">
{% include "head.html" %}
<!DOCTYPE html>
<html lang="en">
{% include "head.html" %}
<body class="d-flex flex-column h-100">
<body class="hero-anime bg-light d-flex flex-column justify-content-between">
<noscript>Your browser does not support JavaScript!</noscript>
{% include "navbar.html" %}
{% include "menu.html" %}
<main class="flex-shrink-0 text-center">
<div class="container">
{% block content %}{% endblock %}
</div>
</main>
<!--<div class="flex-shrink-0 container d-flex justify-content-center align-items-center" style="height: 100%; padding-top: 50px;">
</div>-->
{% include "footer.html" %}
{% include "end.html" %}
</body>
<div class="container-fluid h-100 main-div">
<div class="position-fixed bottom-0 end-0 p-3 pt-5 toast-container">
{% with messages = get_flashed_messages(with_categories=true) %} {% if
messages %} {% for category, message in messages %}
<div
class="toast fade show"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<div class="toast-header">
<img
src="images/favicon.ico"
class="rounded me-2"
alt="BunkerWeb icon"
width="14"
height="14"
/>
<strong class="me-auto">BunkerWeb</strong>
{% if category == 'error' %}
<small style="color: rgb(168, 0, 0)">error</small>
{% else %}
<small style="color: rgb(21, 138, 21)">success</small>
{% endif %}
<button
type="button"
class="btn-close"
data-bs-dismiss="toast"
aria-label="Close"
></button>
</div>
<div class="toast-body">{{ message|safe }}</div>
</div>
{% endfor %} {% endif %} {% endwith %}
</div>
{% block content %} {% endblock %}
</div>
{% include "footer.html" %}
</body>
</html>

43
ui/templates/cache.html Normal file
View File

@@ -0,0 +1,43 @@
{% extends "base.html" %} {% block content %}
<div class="container mt-5 mb-3">
<div class="p-3 pt-4">
<div class="widget">
<div id="folders">{{ gen_folders_tree_html(folders)|safe }}</div>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-see-file"
tabindex="-1"
aria-labelledby="modal-see-file-label"
aria-hidden="true"
>
<div
class="modal-dialog modal-xl modal-fullscreen-lg-down modal-dialog-centered"
>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-see-file-label"></h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body">
<textarea
id="editor"
class="form-control"
value=""
rows="10"
readonly
></textarea>
</div>
</div>
</div>
</div>
{% endblock %}

127
ui/templates/configs.html Normal file
View File

@@ -0,0 +1,127 @@
{% extends "base.html" %} {% block content %}
<div class="container mt-5 mb-3">
<div class="p-3">
<div class="widget">
<div id="folders">{{ gen_folders_tree_html(folders)|safe }}</div>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-edit-new-file"
tabindex="-1"
aria-labelledby="modal-edit-new-file-label"
aria-hidden="true"
>
<form id="form-new-file" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" id="file-operation" value="" name="operation" />
<input type="hidden" id="file-path" value="" name="path" />
<input type="hidden" value="file" name="type" />
<div
class="modal-dialog modal-xl modal-fullscreen-lg-down modal-dialog-centered"
>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-new-file-label"></h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body">
<textarea
id="editor"
class="form-control"
value=""
placeholder="Enter your code here"
name="content"
rows="10"
></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-outline-primary">Save</button>
</div>
</div>
</div>
</form>
</div>
<div
class="modal fade"
id="modal-edit-new-folder"
tabindex="-1"
aria-labelledby="modal-edit-new-folder-label"
aria-hidden="true"
>
<form id="form-new-folder" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" id="folder-operation" value="" name="operation" />
<input type="hidden" id="folder-path" value="" name="path" />
<input type="hidden" value="folder" name="type" />
<div
class="modal-dialog modal-xl modal-fullscreen-lg-down modal-dialog-centered"
>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-new-folder-label"></h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-footer">
<button
type="reset"
class="btn btn-outline-secondary"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="submit" class="btn btn-outline-primary">Save</button>
</div>
</div>
</div>
</form>
</div>
<div
class="modal fade"
id="modal-delete"
tabindex="-1"
aria-labelledby="modal-delete-label"
aria-hidden="true"
>
<form id="form-delete" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" value="delete" name="operation" />
<input type="hidden" id="delete-path" value="" name="path" />
<div class="modal-dialog modal-md modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label"></h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body" id="modal-delete-body"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-outline-danger">Delete</button>
</div>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,5 +0,0 @@
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/custom.js"></script>
<script>
{{ template_data.javascript|safe }}
</script>

View File

@@ -1,12 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="alert alert-danger text-center">
Something went wrong...<br /><br />
{% autoescape false %}
{{ error | replace("\n", "<br/>") }}
{% endautoescape %}
</div>
{% endblock %}

View File

@@ -1,7 +1,114 @@
<footer class="footer mt-auto py-3 bg-light">
<div class="container text-center">
<span class="text-muted">
<a href="https://github.com/bunkerity/bunkerized-nginx">bunkerized-nginx</a> user interface
</span>
</div>
<footer class="footer-bs">
<div class="row">
<div class="col-lg-3 footer-brand animated fadeInLeft">
<a href="https://www.bunkerweb.io" target="_blank"
><img class="images" src="images/BUNKERWEB-print-hd-blanc.png"
/></a>
<p>Welcome to the bunker!</p>
<p>
Copyright © Bunkerity
<script>
document.write(new Date().getFullYear());
</script>
</p>
</div>
<div class="col-lg-3 footer-nav animated fadeInUp">
<h4>Links</h4>
<div class="col-lg-6">
<ul class="list-unstyled pages">
<li>
<a href="https://www.bunkerweb.io" target="_blank">BunkerWeb</a>
</li>
<li>
<a href="https://docs.bunkerweb.io" target="_blank"
>Documentation</a
>
</li>
<li>
<a
href="https://github.com/bunkerity/bunkerweb/blob/master/LICENSE"
target="_blank"
>License</a
>
</li>
<li>
<a href="https://www.bunkerweb.io/privacy-policy" target="_blank"
>Privacy Policy</a
>
</li>
</ul>
</div>
</div>
<div class="col-lg-2 footer-social animated fadeInDown">
<h4>Follow Us</h4>
<ul class="list-unstyled">
<li>
<a href="https://twitter.com/bunkerity" target="_blank"
><i class="bi bi-twitter" aria-label="Twitter"></i>Twitter</a
>
</li>
<li>
<a href="https://www.linkedin.com/company/bunkerity/" target="_blank"
><i class="bi bi-linkedin" aria-label="LinkedIn"></i>LinkedIn</a
>
</li>
<li>
<a href="https://discord.gg/fTf46FmtyD" target="_blank"
><i class="bi bi-discord" aria-label="Discord"></i>Discord</a
>
</li>
<li>
<a href="https://github.com/bunkerity" target="_blank"
><i class="bi bi-github" aria-label="GitHub"></i>GitHub</a
>
</li>
</ul>
</div>
<div class="col-lg-3 footer-ns animated fadeInRight">
<h4>Newsletter</h4>
<p>
<i class="bi bi-lock"></i> Rest assured, everything is under control.
</p>
<form
action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&amp;id=37076d9d67"
method="POST"
class="needs-validation"
id="subscribe-newsletter"
>
<div class="input-group mb-2">
<input
type="text"
id="newsletter-email"
name="EMAIL"
class="form-control"
placeholder="John.doe@example.com"
pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-z]{2,}$"
required=""
/>
<button
class="btn btn-outline-light"
type="submit"
formtarget="_blank"
>
Subscribe
</button>
</div>
<div class="input-group align-items-center">
<input
class="col-auto form-check form-switch"
type="checkbox"
id="newsletter-check"
required=""
/>
&nbsp;&nbsp;
<h6 class="col-auto h6 mb-0">
I've read and agree to the
<a href="https://www.bunkerity.com/privacy-policy/" _target="_blank"
>privacy policy</a
>
</h6>
</div>
</form>
</div>
</div>
</footer>

View File

@@ -0,0 +1,105 @@
{% extends "base.html" %} {% block content %}
<div class="container mt-3 mb-3">
<form id="form-edit-global-conf" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<div class="pb-3 flex-grow-1 d-flex flex-column flex-md-row">
<div class="row flex-grow-md-1 flex-grow-1">
<aside
class="col-md-3 flex-grow-md-1 flex-shrink-1 flex-grow-0 sticky-top pb-md-0 pb-3"
>
<div class="bg-light border rounded-3 p-1 h-100 sticky-top">
<ul
class="nav nav-pills flex-md-column flex-row mb-auto justify-content-start text-truncate"
id="pills-tab"
role="tablist"
>
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate active"
id="edit-global-conf-general-tab"
data-bs-toggle="pill"
href="#edit-global-conf-general"
role="tab"
aria-controls="edit-global-conf-general"
aria-selected="selected"
>
<span class="d-md-inline">General</span>
<div
class="d-none px-2 d-md-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="General settings of BunkerWeb"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"global") %}
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate"
id="edit-global-conf-{{ plugin['id'] }}-tab"
data-bs-toggle="pill"
href="#edit-global-conf-{{ plugin['id'] }}"
role="tab"
aria-controls="edit-global-conf-{{ plugin['id'] }}"
aria-selected=""
>
<span class="d-md-inline">{{ plugin["name"] }}</span>
<div
class="d-none px-2 d-md-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{{ plugin['description'] }}"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% endif %} {% endfor %}
</ul>
</div>
</aside>
<main class="col overflow-auto h-100">
<div class="bg-light border rounded-3 p-3">
<div class="tab-content" id="edit-global-conf-content">
<div
class="tab-pane fade show active"
id="edit-global-conf-general"
role="tabpanel"
aria-labelledby="edit-global-conf-general-tab"
>
{% set global_config = config["CONFIG"].get_config() %} {% for
setting, value in config["CONFIG"].get_settings().items() %} {%
if value["context"] == "global" and "label" in value %}
<div
class="d-flex flex-row justify-content-between align-items-center mb-3"
id="form-edit-global-conf-{{ setting['id'] }}"
>
{{ form_service_gen("form-edit-global-conf-" + value["id"],
value["help"], value["label"], value["type"],
global_config[setting], setting, value["default"],
value["select"], value["regex"])|safe }}
</div>
{% endif %} {% endfor %}
</div>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"global") %} {{ form_plugin_gen(global_config, plugin,
"edit-global-conf", context="global")|safe }} {% endif %} {%
endfor %}
</div>
</div>
</main>
</div>
</div>
<div class="col col-12 mb-3 align-items-center text-center">
<button type="submit" class="p-2 btn btn-outline-success">
Save <i class="fa-solid fa-floppy-disk"></i>
</button>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,13 +1,69 @@
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip()
%}
<head>
<base href="{{ config["ABSOLUTE_URI"] }}">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="bunkerized-nginx user interface">
<meta name="author" content="bunkerity">
<title>bunkerized-nginx-ui - {{ title }}</title>
<link rel="icon" type="image/png" href="img/favicon16.png" sizes="16x16">
<link rel="icon" type="image/png" href="img/favicon32.png" sizes="32x32">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/fa.min.css" rel="stylesheet">
<link href="css/custom.css" rel="stylesheet">
<base href="{{ config["ABSOLUTE_URI"] }}">
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="bunkerweb user interface" />
<meta name="author" content="bunkerity" />
<title>BunkerWeb UI</title>
<link rel="icon" type="image/x-icon" href="images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="css/base.css" />
<link rel="stylesheet" type="text/css" href="css/navbar.css" />
<link rel="stylesheet" type="text/css" href="css/footer.css" />
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="css/fa.all.min.css" />
<link rel="stylesheet" type="text/css" href="webfonts/bootstrap-icons.css" />
<link rel="stylesheet" type="text/css" href="webfonts/poppins.css" />
{% if current_endpoint == "home" %}
<link rel="stylesheet" type="text/css" href="css/home.css" />
{% elif current_endpoint == "instances" or current_endpoint == "services" %}
<link rel="stylesheet" type="text/css" href="css/instances&services.css" />
{% elif current_endpoint == "global_config" %}
<link rel="stylesheet" type="text/css" href="css/global-config.css" />
{% elif current_endpoint == "configs" %}
<link rel="stylesheet" type="text/css" href="css/configs&plugins&cache.css" />
<link
rel="stylesheet"
type="text/css"
href="css/jquery.numberedtextarea.css"
/>
{% elif current_endpoint == "plugins" %}
<link rel="stylesheet" type="text/css" href="css/configs&plugins&cache.css" />
{% elif current_endpoint == "cache" %}
<link rel="stylesheet" type="text/css" href="css/configs&plugins&cache.css" />
<link
rel="stylesheet"
type="text/css"
href="css/jquery.numberedtextarea.css"
/>
{% elif current_endpoint == "logs" %}
<link rel="stylesheet" type="text/css" href="css/logs.css" />
<link
rel="stylesheet"
type="text/css"
href="css/bootstrap-datepicker.min.css"
/>
{% endif %}
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="js/fa.all.min.js"></script>
<script type="text/javascript" src="js/navbar.js"></script>
<script type="text/javascript" defer src="js/darkmode.js"></script>
{% if current_endpoint == "services" or current_endpoint == "global_config" %}
<script type="text/javascript" src="js/services.js"></script>
{% elif current_endpoint == "configs" %}
<script type="text/javascript" src="js/configs.js"></script>
<script type="text/javascript" src="js/jquery.numberedtextarea.js"></script>
{% elif current_endpoint == "plugins" %}
<script type="text/javascript" defer src="js/plugins.js"></script>
{% elif current_endpoint == "cache" %}
<script type="text/javascript" src="js/cache.js"></script>
<script type="text/javascript" src="js/jquery.numberedtextarea.js"></script>
{% elif current_endpoint == "logs" %}
<script type="text/javascript" src="js/logs.js"></script>
<script type="text/javascript" src="js/bootstrap-datepicker.min.js"></script>
{% endif %}
</head>

View File

@@ -1,20 +1,225 @@
{% extends "base.html" %}
{% extends "base.html" %} {% block content %}
<div class="container-fluid px-3 py-5 p-md-5">
<div class="row">
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div
class="text-xs font-weight-bold text-primary text-uppercase mb-1"
>
BunkerWeb version
</div>
{% if check_version %}
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ version }} {% if not remote_version %}
<span class="h6 mb-0 text-warning"
>(couldn't fetch remote version)</span
>
{% endif %}
</div>
{% else %}
<div class="h5 mb-0 font-weight-bold">
<span class="text-warning">{{ version }} (your version)</span>
<i class="fa-solid fa-arrow-right-long"></i>
<span class="text-success">{{ remote_version }} (latest)</span>
</div>
{% endif %}
</div>
{% if not check_version %}
<div class="col-auto">
<a
href="https://github.com/bunkerity/bunkerweb"
class="btn btn-success"
>Update</a
>
</div>
{% endif %}
<div class="col-auto">
<i class="fa-solid fa-code-branch fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
{% block content %}
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div
class="text-xs font-weight-bold text-primary text-uppercase mb-1"
>
Number of instances
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ instances_number }}
</div>
</div>
<div class="col-auto">
<i class="fa-solid fa-hard-drive fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col col-12">
<img src="img/logo.png" style="width: 300px;" />
</div>
<div class="col col-12 mt-20">
<span class="badge bg-primary">{{ instances_number }}</span> bunkerized-nginx instances
</div>
<div class="col col-12 mt-20">
<span class="badge bg-primary">{{ services_number }}</span> web services
</div>
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div
class="text-xs font-weight-bold text-primary text-uppercase mb-1"
>
Number of web services
</div>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">
{{ services_number }}
</div>
</div>
</div>
</div>
<div class="col-auto">
<i class="fa-solid fa-globe fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div
class="text-xs font-weight-bold text-primary text-uppercase mb-1"
>
Join the community !
</div>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<a href="https://twitter.com/bunkerity" target="_blank">
<i class="fa-brands fa-twitter fa-2x text-gray-800"></i>
</a>
</div>
<div class="col-auto">
<a
href="https://www.linkedin.com/company/bunkerity/"
target="_blank"
>
<i class="fa-brands fa-linkedin fa-2x text-gray-800"></i>
</a>
</div>
<div class="col-auto">
<a href="https://discord.gg/fTf46FmtyD" target="_blank">
<i class="fa-brands fa-discord fa-2x text-gray-800"></i>
</a>
</div>
<div class="col-auto">
<a href="https://github.com/bunkerity" target="_blank">
<i class="fa-brands fa-github fa-2x text-gray-800"></i>
</a>
</div>
</div>
</div>
<div class="col-auto">
<i class="fa-solid fa-hashtag fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% if posts %}
<section class="blog-list px-3 py-5 p-md-5">
<h1>News </h1>
<div class="container single-col-max-width">
{% for post in posts %}
<div class="item mb-5">
<div class="row g-3 g-xl-0">
<div class="col-2 col-xl-3">
<a href="{{ post['link'] }}" target="_blank"
><img
class="img-fluid post-thumb"
src="{{ post['image_url'] }}"
alt="image"
/></a>
</div>
<div class="col">
<h3 class="title mb-1">
<a class="text-link" href="{{ post['link'] }}" target="_blank"
>{{ post['title'] }}</a
>
</h3>
<div class="meta mb-1">
<span class="date">{{ post['date'] }}</span
><span class="time">{{ post['reading_time'] }} read</span>
</div>
<div class="intro">{{ post['description'] }}</div>
<a class="text-link" href="{{ post['link'] }}" target="_blank"
>Read more &rarr;</a
>
</div>
<!--//col-->
</div>
<!--//row-->
</div>
<!--//item-->
{% endfor %}
<nav class="blog-nav nav nav-justified my-5">
<a
class="nav-link-next nav-item nav-link rounded"
href="https://www.bunkerity.com/blog/"
target="_blank"
>See more posts</a
>
</nav>
</div>
</section>
{% else %}
<div class="no_internet">
<div class="container-fluid my-5 d-flex justify-content-center">
<div class="row justify-content-center">
<div class="col">
<div class="card">
<div class="card-header pb-0 bg-white border-0 text-center px-sm-4">
<h6 class="text-left mt-4 font-weight-bold mb-0">
<span
><i
class="fa fa-times-circle fa-lg mr-3"
aria-hidden="true"
></i>
</span>
No internet connection
</h6>
<span class="img-1 text-center"
><img src="images/no_internet.png" class="img-fluid my-4"
/></span>
</div>
<div class="card-body px-sm-4 mb-3">
<ul class="list-unstyled text-muted">
<li>
Please re-connect to the internet to show the latest news.
</li>
<li>If you encounter problems:</li>
<ul class="mt-2 inner">
<li>Try restarting wireless connection on this device.</li>
<li>Move closer to your wireless access point.</li>
</ul>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
{% endif %} {% endblock %}

View File

@@ -1,68 +1,153 @@
{% extends "base.html" %}
{% block content %}
<div class="row justify-content-center">
{% if operation != "" %}
<div class="col col-12">
<div class="row justify-content-center">
<div class="col col-12 col-lg-4">
<div class="alert alert-primary alert-dismissible fade show text-break" role="alert">
{{ operation }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
</div>
</div>
{% endif %}
{% if instances|length == 0 %}
<div class="col col-12 alert alert-primary">
No instance to show...
</div>
{% endif %}
{% for instance in instances %}
{% set color = "dark" %}
{% if instance["status"] == "up" %}
{% set color = "success" %}
{% elif instance["status"] == "down" %}
{% set color = "danger" %}
{% endif %}
<div class="col col-12 col-lg-6">
<form id="form-instance-{{ instance["id"] }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="INSTANCE_ID" value="{{ instance["id"] }}">
</form>
<div class="card border-{{ color }} mb-3" style="max-width: 80rem;">
<div class="card-header border-{{ color }} bg-{{ color }} text-white">
{{ instance["name"] }}
<div class="btn-group mx-2 float-end" role="group">
<button id="btnGroupDrop1" class="btn btn-sm dropdown-toggle btn-light" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-cogs"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<li><a class="dropdown-item" href="#" onClick="return reloadInstance('{{ instance["id"] }}');">Reload</a></li>
{% if instance["type"] == "local" %}<li><a class="dropdown-item" href="#" onClick="return startInstance('{{ instance["id"] }}');">Start</a></li>{% endif %}
<li><a class="dropdown-item" href="#" onClick="return stopInstance('{{ instance["id"] }}');">Stop</a></li>
{% if instance["type"] == "local" %}<li><a class="dropdown-item" href="#" onClick="return restartInstance('{{ instance["id"] }}');">Restart</a></li>{% endif %}
</ul>
</div>
</div>
<div class="card-body text-dark text-center">
<h5 class="card-title">
Status : {{ instance["status"] }}<br>
Type : {{ instance["type"] }}
</h5>
<span class="card-text">
</span>
</div>
</div>
</div>
{% endfor %}
{% extends "base.html" %} {% block content %}
<div class="container mt-5 mb-3">
{% if instances|length == 0 %}
<div class="row justify-content-center">
<div class="col col-12 alert alert-primary text-center">
No instance to show...
</div>
</div>
{% else %} {% for instances_batched in instances|batch(2) %}
<div class="row">
{% for instance in instances_batched %}
<div class="col-lg-6">
<form id="form-instance-{{ instance._id }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="INSTANCE_ID" value="{{ instance._id }}" />
<div class="card p-3 mb-2">
<div class="d-flex justify-content-between">
<div class="d-flex flex-row align-items-center">
{% if instance._type == "local" %} {% if instance.health %}
<button
class="state-button icon {{ instance.health }}"
type="submit"
name="operation"
value="stop"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Stop"
>
<i class="fa-solid fa-power-off"></i>
</button>
{% else %}
<button
class="state-button icon {{ instance.health }}"
type="submit"
name="operation"
value="start"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Start"
>
<i class="fa-solid fa-power-off"></i>
</button>
{% endif %} {% else %}
<button
class="state-button icon {{ instance.health }}"
type="submit"
name="operation"
value="reload"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Reload"
>
<i class="fa-solid fa-power-off"></i>
</button>
{% endif %}
<div class="ms-2 c-details">
<h6 class="mb-0">{{ instance.name }}</h6>
</div>
</div>
<div class="d-flex flex-row align-items-center">
<div class="badge dropdown">
<button
type="button"
class="btn btn-outline-secondary"
id="dropdownInfoButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="fa-solid fa-circle-info"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownInfoButton">
<li>
<a class="dropdown-item"
><b>Hostname</b>: <i>{{ instance.hostname }}</i></a
>
</li>
<li>
<a class="dropdown-item"
><b>Type</b>: <i>{{ instance._type }}</i></a
>
</li>
</ul>
</div>
<div class="badge dropdown">
<button
type="button"
class="btn btn-outline-secondary"
id="dropdownSettingsButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="fa-solid fa-sliders fa-rotate-90"></i>
</button>
<ul
class="dropdown-menu"
aria-labelledby="dropdownSettingsButton"
>
<li>
<button
class="dropdown-item"
type="submit"
name="operation"
value="reload"
>
Reload
</button>
</li>
{% if instance._type == "local" and not instance.health %}
<li>
<button
class="dropdown-item"
type="submit"
name="operation"
value="start"
>
Start
</button>
</li>
{% endif %} {% if instance.health %}
<li>
<button
class="dropdown-item"
type="submit"
name="operation"
value="stop"
>
Stop
</button>
</li>
{% endif %} {% if instance._type == "local" %}
<li>
<button
class="dropdown-item"
type="submit"
name="operation"
value="restart"
>
Restart
</button>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</form>
</div>
{% endfor %}
</div>
{% endfor %} {% endif %}
</div>
{% endblock %}

28
ui/templates/loading.html Normal file

File diff suppressed because one or more lines are too long

174
ui/templates/login.html Normal file → Executable file
View File

@@ -1,31 +1,149 @@
{% extends "base.html" %}
<!DOCTYPE html>
{% block content %}
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>BunkerWeb UI</title>
<link href="images/favicon.ico" rel="icon" type="image/x-icon" />
<link href="webfonts/karla.css" rel="stylesheet" />
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/login.css" />
</head>
<body>
<div class="position-fixed bottom-0 end-0 p-3 pt-5 toast-container">
{% if error %}
<div
class="toast fade show"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<div class="toast-header">
<img
src="images/favicon.ico"
class="rounded me-2"
alt="BunkerWeb icon"
width="14"
height="14"
/>
<strong class="me-auto">BunkerWeb</strong>
<small style="color: rgb(168, 0, 0)">error</small>
<button
type="button"
class="btn-close"
data-bs-dismiss="toast"
aria-label="Close"
></button>
</div>
<div class="toast-body">{{ error }}</div>
</div>
{% endif %} {% with messages = get_flashed_messages(with_categories=true)
%} {% if messages %} {% for category, message in messages %}
<div
class="toast fade show"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<div class="toast-header">
<img
src="images/favicon.ico"
class="rounded me-2"
alt="BunkerWeb icon"
width="14"
height="14"
/>
<strong class="me-auto">BunkerWeb</strong>
<small style="color: rgb(168, 0, 0)">error</small>
<button
type="button"
class="btn-close"
data-bs-dismiss="toast"
aria-label="Close"
></button>
</div>
<div class="toast-body">{{ message|safe }}</div>
</div>
{% endfor %} {% endif %} {% endwith %}
</div>
<main>
<div class="container-fluid">
<div class="row">
<div class="col-sm-6 login-section-wrapper">
<div class="brand-wrapper d-sm-none">
<img
src="images/BUNKERWEB-print-hd.png"
alt="logo"
class="logo"
/>
</div>
<div class="login-wrapper my-auto">
<h1 class="login-title">Log in</h1>
<form action="login" method="POST" autocomplete="off">
<input
type="hidden"
name="csrf_token"
value="{{ csrf_token() }}"
/>
<input
type="hidden"
name="next"
value="{{ request.values.get('next', '') }}"
/>
<div class="form-group">
<label for="username">Username</label>
<input
type="username"
name="username"
id="username"
class="form-control"
placeholder="Username"
required=""
/>
</div>
<div class="form-group mb-4">
<label for="password">Password</label>
<input
type="password"
name="password"
id="password"
class="form-control"
placeholder="enter your password"
required=""
/>
</div>
<input
name="login"
id="login"
class="btn btn-block login-btn"
type="submit"
value="Login"
/>
</form>
</div>
</div>
<div class="col-sm-6 px-0 d-none d-sm-block">
<div id="particles-js" class="login-img"></div>
<img
src="images/BUNKERWEB-print-hd-blanc.png"
alt="logo"
class="images login-logo"
/>
</div>
</div>
</div>
</main>
<script src="js/tsparticles.bundle.min.js"></script>
<script src="js/jquery.min.js"></script>
<script src="js/popper.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script>
tsParticles.loadJSON("particles-js", "json/particles.json");
</script>
</body>
</html>
<div class="form-signin">
<div class="text-center">
<img src="img/logo.png" class="mb-4" style="max-width: 200px;">
</div>
<h1 class="h3 mb-3 fw-normal">Authentication required</h1>
{% if fail %}
<div class="alert alert-danger fade show text-break" role="alert">
Wrong username and/or password...
</div>
{% endif %}
<form action="login" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="form-floating">
<input type="text" id="username" class="form-control" name="username" placeholder="user">
<label for="username">Username</label>
</div>
<div class="form-floating">
<input type="password" id="password" class="form-control" name="password" placeholder="p@ssw0rd">
<label for="password">Password</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
</form>
</div>
{% endblock %}
{% endblock %}

75
ui/templates/logs.html Normal file
View File

@@ -0,0 +1,75 @@
{% extends "base.html" %} {% block content %}
<div class="container mt-5 mb-3">
<div class="p-md-2 pt-1 pt-sm-4">
<div class="search-area d-sm-flex">
<div class="search-bar flex-grow-1">
<form>
<input type="search" id="filter-input" placeholder="Filter..." required />
<i class="fa-solid fa-search"></i>
</form>
</div>
<div class="d-flex align-items-center">
<div class="input-group">
<input
type="text"
id="date-input"
class="form-control"
placeholder="Pick a date"
aria-label="Date filter"
aria-describedby="date-picker"
value=""
disabled
/>
<button
type="button"
id="date-picker"
class="btn btn-outline-primary"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Filter from date"
{% if first_instance and first_instance.get_id() == 'linux' %} disabled {% endif %}
>
<i class="fa-solid fa-calendar-alt"></i>
</button>
</div>
<div class="badge px-1">
<button
type="button"
id="date-clear"
class="btn btn-outline-danger"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Clear filters"
>
<i class="fa-solid fa-eraser"></i>
</button>
</div>
<div class="badge px-1">
<button
type="button"
id="refresh-logs"
class="btn btn-outline-secondary"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Enable/Disable auto refresh"
>
<i id="rotate-icon" class="fa-solid fa-arrows-rotate rotate"></i>
</button>
</div>
</div>
</div>
<div class="pt-4">
<div class="widget">
<ul class="nav nav-tabs">
{% for instance in instances %}
<li class="nav-item">
<a class="nav-link container-selector {% if instance.get_id() == first_instance.get_id() %}active{% endif %}" href="javascript:void(0)" {% if instance.get_id() == first_instance.get_id() %}aria-current="page"{% endif %} id="active-nav" data-container-id="{{ instance.get_id() }}">{{ instance.name }}</a>
</li>
{% endfor %}
</ul>
<ul class="list-group pt-1" id="logs-list"></ul>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,26 +0,0 @@
<header>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">bunkerized-nginx-ui</a>
{% if current_user.is_authenticated %}
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link" href="home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="instances">Instances</a>
</li>
<li class="nav-item">
<a class="nav-link" href="services">Services</a>
</li>
</ul>
<a class="btn btn-light" href="logout" role="button">Logout</a>
</div>
{% endif %}
</div>
</nav>
</header>

125
ui/templates/navbar.html Normal file
View File

@@ -0,0 +1,125 @@
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip()
%}
<div class="navigation-wrap bg-custom start-header start-style">
<div class="container">
<div class="row">
<div class="col-12">
<nav class="navbar navbar-expand-xl navbar-light">
<a
class="navbar-brand"
href="https://www.bunkerweb.io"
target="_blank"
><img
src="images/BUNKERWEB-print-hd-blanc.png"
alt="logo bunkerweb"
/>
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto py-4 py-md-0">
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'home' %}active{% endif %}"
>
<a
class="nav-link"
aria-current="page"
href="{% if current_endpoint == 'home' %}javascript:void(0){% else %}loading?next={{ url_for('home') }}{% endif %}"
>Home</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'instances' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'instances' %}javascript:void(0){% else %}loading?next={{ url_for('instances') }}{% endif %}"
>Instances</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'global_config' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'global_config' %}javascript:void(0){% else %}loading?next={{ url_for('global_config') }}{% endif %}"
>Global config</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'services' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'services' %}javascript:void(0){% else %}loading?next={{ url_for('services') }}{% endif %}"
>Services</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'configs' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'configs' %}javascript:void(0){% else %}loading?next={{ url_for('configs') }}{% endif %}"
>Configs</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'plugins' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'plugins' %}javascript:void(0){% else %}loading?next={{ url_for('plugins') }}{% endif %}"
>Plugins</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'cache' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'cache' %}javascript:void(0){% else %}loading?next={{ url_for('cache') }}{% endif %}"
>Cache</a
>
</li>
<li
class="nav-item pl-4 pl-md-0 ml-0 ml-md-4 {% if current_endpoint == 'logs' %}active{% endif %}"
>
<a
class="nav-link"
href="{% if current_endpoint == 'logs' %}javascript:void(0){% else %}loading?next={{ url_for('logs') }}{% endif %}"
>Logs</a
>
</li>
<li class="nav-item pl-4 pl-md-0 ml-0 ml-md-4">
<a class="nav-link" href="logout">Logout</a>
</li>
<li class="nav-item-switch pl-4 pl-md-0 ml-0 ml-md-4">
<div class="form-check form-switch pull-right nav-switch">
<input
class="form-check-input"
type="checkbox"
id="dark-mode-switch"
/>
<i class="bi" id="darkModeIcon" for="dark-mode-switch"></i>
</div>
</li>
</ul>
</div>
</nav>
</div>
</div>
</div>
</div>

73
ui/templates/plugins.html Normal file
View File

@@ -0,0 +1,73 @@
{% extends "base.html" %} {% block content %}
<div class="container mt-5 mb-3">
<div class="uploader">
<div class="wrapper">
<header>Upload a new plugin</header>
<form action="#" class="drop-zone">
<input
type="hidden"
id="csrf_token"
name="csrf_token"
value="{{ csrf_token() }}"
/>
<input
class="file-input drop-zone__input"
type="file"
name="file"
multiple="multiple"
hidden
/>
<i class="fa-solid fa-cloud-upload-alt"></i>
<p>Browse File to Upload</p>
</form>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
<header>
<form method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<button type="submit" class="btn btn-outline-primary btn-block mt-2">
Reload plugins
</button>
</form>
</header>
</div>
</div>
<div class="p-3 pt-4">
<div class="widget">
<div id="folders">{{ gen_folders_tree_html(folders)|safe }}</div>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-delete"
tabindex="-1"
aria-labelledby="modal-delete-label"
aria-hidden="true"
>
<form id="form-delete" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" value="delete" name="operation" />
<input type="hidden" id="delete-path" value="" name="path" />
<div class="modal-dialog modal-md modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label"></h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body" id="modal-delete-body"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,21 +1,38 @@
<div class="modal fade" id="modal-delete-id-{{ id_server_name }}" tabindex="-1" aria-labelledby="modal-delete-label-{{ id_server_name }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label-{{ id_server_name }}">Delete {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the configuration of {{ service["SERVER_NAME"] }} ?
<form id="form-delete-{{ id_server_name }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" value="{{ service["SERVER_NAME"] }}" name="SERVER_NAME">
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger" onClick="deleteService('{{ id_server_name }}');">Delete</button>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-delete-id-{{ id_server_name }}"
tabindex="-1"
aria-labelledby="modal-delete-label-{{ id_server_name }}"
aria-hidden="true"
>
<form id="form-delete-{{ id_server_name }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" value="{{ service["SERVER_NAME"] }}"
name="SERVER_NAME">
<input type="hidden" value="delete" name="operation" />
<div class="modal-dialog modal-md modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label-{{ id_server_name }}">
Delete <i>{{ service["SERVER_NAME"] }}</i> configuration
</h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body">
Are you sure you want to delete the configuration of
<b>{{ service["SERVER_NAME"] }}</b> ?
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-outline-danger">Delete</button>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,60 +1,144 @@
<div class="modal fade" id="modal-edit-id-{{ id_server_name }}" tabindex="-1" aria-labelledby="modal-edit-label-{{ id_server_name }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-label-{{ id_server_name }}">View/edit {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ul class="nav nav-pills mb-3" id="pills-tab-edit" role="tablist">
{% set check = {"active": "active", "selected": "true"} %}
{% for k, v in config["CONFIG"].get_settings().items() %}
<li class="nav-item" role="presentation">
<a class="nav-link {{ check.active }}" id="edit-{{ v["id"] }}-{{ id_server_name }}-tab" data-bs-toggle="pill" href="#edit-{{ v["id"] }}-{{ id_server_name }}" role="tab" aria-controls="edit-{{ v["id"] }}-{{ id_server_name }}" aria-selected="{{ check.selected }}">{{ k }}</a>
</li>
{% if check.update({"active": "", "selected": "false"}) %}
{% endif %}
{% endfor %}
</ul>
<form id="form-edit-{{ id_server_name }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" value="{{ service["SERVER_NAME"] }}" name="OLD_SERVER_NAME">
<div class="tab-content" id="edit-content-{{ id_server_name }}">
{% set check = {"class": "show active"} %}
{% for k, v in config["CONFIG"].get_settings().items() %}
<div class="tab-pane fade {{ check.class }}" id="edit-{{ v["id"] }}-{{ id_server_name }}" role="tabpanel" aria-labelledby="edit-{{ v["id"] }}-{{ id_server_name }}-tab">
{% for param in v["params"] %}
{% if param["type"] != "multiple" and param["context"] == "multisite" %}
<div class="row mb-3" id="form-edit-{{ id_server_name }}-{{ param["id"] }}">
{{ form_service_gen("form-edit-" + id_server_name + "-" + param["id"], param["label"], param["type"], service[param["env"]], param["env"])|safe }}
</div>
{% elif param["type"] == "multiple" %}
{% set gen = {"value": False} %}
{% for param2 in param["params"] %}
{% if param2["context"] == "multisite" %}
{% set x = gen.update({"value": True}) %}
{% endif %}
{% endfor %}
{% if gen["value"] %}
<div class="row mb-3" id="form-edit-{{ id_server_name }}-{{ param["id"] }}">
{{ form_service_gen_multiple("form-edit-" + id_server_name + "-" + param["id"], param["label"], param["params"])|safe }}
{% if template_data.update({"javascript": template_data.javascript + form_service_gen_multiple_values("form-edit-" + id_server_name + "-" + param["id"], param["params"], service)}) %}
{% endif %}
</div>
{% endif %}
{% endif %}
{% endfor %}
</div>
{% if check.update({"class": ""}) %}
{% endif %}
{% endfor %}
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onClick="editService('{{ id_server_name }}');">Save</button>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-edit-id-{{ id_server_name }}"
tabindex="-1"
aria-labelledby="modal-edit-label-{{ id_server_name }}"
aria-hidden="true"
>
<form id="form-edit-{{ id_server_name }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input
type="hidden"
value="{{ service['SERVER_NAME'] }}"
name="OLD_SERVER_NAME"
/>
<input type="hidden" value="edit" name="operation" />
<div
class="modal-dialog modal-xl modal-fullscreen-lg-down modal-dialog-centered modal-dialog-scrollable"
>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-label-{{ id_server_name }}">
View/edit <i>{{ service["SERVER_NAME"] }}</i> configuration
</h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body">
<div class="pb-3 flex-grow-1 d-flex flex-column flex-sm-row">
<div class="row flex-grow-sm-1 flex-grow-1">
<aside
class="col-sm-3 flex-grow-md-1 flex-shrink-1 flex-grow-0 sticky-top pb-md-0 pb-3"
>
<div class="bg-light border rounded-3 p-1 h-100 sticky-top">
<ul
class="nav nav-pills flex-sm-column flex-row mb-auto justify-content-start text-truncate"
id="pills-tab"
role="tablist"
>
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate active"
id="edit-general-{{ id_server_name }}-tab"
data-bs-toggle="pill"
href="#edit-general-{{ id_server_name }}"
role="tab"
aria-controls="edit-general-{{ id_server_name }}"
aria-selected="selected"
>
<span class="d-sm-inline">General</span>
<div
class="d-none px-2 d-sm-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="General settings of BunkerWeb"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"multisite") %}
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate"
id="edit-{{ plugin['id'] }}-{{ id_server_name }}-tab"
data-bs-toggle="pill"
href="#edit-{{ plugin['id'] }}-{{ id_server_name }}"
role="tab"
aria-controls="edit-{{ plugin['id'] }}-{{ id_server_name }}"
aria-selected=""
>
<span class="d-sm-inline">{{ plugin["name"] }}</span>
<div
class="d-none px-2 d-sm-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{{ plugin['description'] }}"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% endif %} {% endfor %}
</ul>
</div>
</aside>
<main class="col overflow-auto h-100">
<div class="bg-light border rounded-3 p-3">
<div
class="tab-content"
id="edit-content-{{ id_server_name }}"
>
<div
class="tab-pane fade show active"
id="edit-general-{{ id_server_name }}"
role="tabpanel"
aria-labelledby="edit-general-{{ id_server_name }}-tab"
>
{% for setting, value in
config["CONFIG"].get_settings().items() %} {% if
value["context"] == "multisite" %}
<div
class="d-flex flex-row justify-content-between align-items-center mb-3"
id="form-edit-{{ id_server_name }}-{{ setting['id'] }}"
>
{{ form_service_gen("form-edit-" + id_server_name + "-"
+ value["id"], value["help"], value["label"],
value["type"], service[setting], setting,
value["default"], value["select"], value["regex"])|safe
}}
</div>
{% endif %} {% endfor %}
</div>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"multisite") %} {{ form_plugin_gen(service, plugin, "edit",
id_server_name)|safe }} {% endif %} {% endfor %}
</div>
</div>
</main>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="reset"
class="btn btn-outline-secondary"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="submit" class="btn btn-outline-primary">Save</button>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,61 +1,133 @@
<div class="modal fade" id="modal-new" tabindex="-1" aria-labelledby="modal-new-label" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-new-label">New configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ul class="nav nav-pills mb-3" id="pills-tab-new" role="tablist">
{% set check = {"active": "active", "selected": "true"} %}
{% for k, v in config["CONFIG"].get_settings().items() %}
<li class="nav-item" role="presentation">
<a class="nav-link {{ check.active }}" id="new-{{ v["id"] }}-tab" data-bs-toggle="pill" href="#new-{{ v["id"] }}" role="tab" aria-controls="new-{{ v["id"] }}" aria-selected="{{ check.selected }}">{{ k }}</a>
</li>
{% if check.update({"active": "", "selected": "false"}) %}
{% endif %}
{% endfor %}
</ul>
<form id="form-new">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="tab-content" id="new-content">
{% set check = {"class": "show active"} %}
{% for k, v in config["CONFIG"].get_settings().items() %}
<div class="tab-pane fade {{ check.class }}" id="new-{{ v["id"] }}" role="tabpanel" aria-labelledby="new-{{ v["id"] }}-tab">
{% for param in v["params"] %}
{% if param["type"] != "multiple" and param["context"] == "multisite" %}
<div class="row mb-3" id="form-new-{{ param["id"] }}">
{% set default = {"value": param["default"]} %}
{% if param["env"] in config["CONFIG"].get_config() and param["env"] != "SERVER_NAME" %}
{% set x = default.update({"value": config["CONFIG"].get_config()[param["env"]]}) %}
{% endif %}
{{ form_service_gen("form-new-" + param["id"], param["label"], param["type"], default["value"], param["env"])|safe }}
</div>
{% elif param["type"] == "multiple" %}
{% set gen = {"value": False} %}
{% for param2 in param["params"] %}
{% if param2["context"] == "multisite" %}
{% set x = gen.update({"value": True}) %}
{% endif %}
{% endfor %}
{% if gen["value"] %}
<div class="row mb-3" id="form-new-{{ param["id"] }}">
{{ form_service_gen_multiple("form-new-" + param["id"], param["label"], param["params"])|safe }}
</div>
{% endif %}
{% endif %}
{% endfor %}
</div>
{% if check.update({"class": ""}) %}
{% endif %}
{% endfor %}
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onClick="newService();">Save</button>
</div>
</div>
</div>
<div
class="modal fade"
id="modal-new"
tabindex="-1"
aria-labelledby="modal-new-label"
aria-hidden="true"
>
<form id="form-new" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" value="new" name="operation" />
<div
class="modal-dialog modal-xl modal-fullscreen-lg-down modal-dialog-centered modal-dialog-scrollable"
>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-new-label">New configuration</h5>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
data-bs-dismiss="modal"
aria-label="Close"
>
<i class="fa-solid fa-close fa-lg"></i>
</button>
</div>
<div class="modal-body">
<div class="pb-3 flex-grow-1 d-flex flex-column flex-sm-row">
<div class="row flex-grow-sm-1 flex-grow-1">
<aside
class="col-sm-3 flex-grow-md-1 flex-shrink-1 flex-grow-0 sticky-top pb-md-0 pb-3"
>
<div class="bg-light border rounded-3 p-1 h-100 sticky-top">
<ul
class="nav nav-pills flex-sm-column flex-row mb-auto justify-content-start text-truncate"
id="pills-tab"
role="tablist"
>
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate active"
id="new-general-tab"
data-bs-toggle="pill"
href="#new-general"
role="tab"
aria-controls="new-general"
aria-selected="selected"
>
<span class="d-sm-inline">General</span>
<div
class="d-none px-2 d-sm-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="General settings of BunkerWeb"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"multisite") %}
<li class="nav-item">
<a
class="nav-link d-flex flex-row justify-content-between align-items-center px-2 text-truncate"
id="new-{{ plugin['id'] }}-tab"
data-bs-toggle="pill"
href="#new-{{ plugin['id'] }}"
role="tab"
aria-controls="new-{{ plugin['id'] }}"
aria-selected=""
>
<span class="d-sm-inline">{{ plugin["name"] }}</span>
<div
class="d-none px-2 d-sm-inline"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{{ plugin['description'] }}"
>
<i class="fa-solid fa-circle-info"></i>
</div>
</a>
</li>
{% endif %} {% endfor %}
</ul>
</div>
</aside>
<main class="col overflow-auto h-100">
<div class="bg-light border rounded-3 p-3">
<div class="tab-content" id="new-content">
<div
class="tab-pane fade show active"
id="new-general"
role="tabpanel"
aria-labelledby="new-general-tab"
>
{% for setting, value in
config["CONFIG"].get_settings().items() %} {% if
value["context"] == "multisite" %}
<div
class="d-flex flex-row justify-content-between align-items-center mb-3"
id="form-new-{{ setting['id'] }}"
>
{{ form_service_gen("form-new-" + value["id"],
value["help"], value["label"], value["type"],
value["default"], setting, value["default"],
value["select"], value["regex"])|safe }}
</div>
{% endif %} {% endfor %}
</div>
{% for plugin in config["CONFIG"].get_plugins() %} {% if
plugin["settings"] and check_settings(plugin["settings"],
"multisite") %} {{ form_plugin_gen({}, plugin, "new")|safe
}} {% endif %} {% endfor %}
</div>
</div>
</main>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="reset"
class="btn btn-outline-secondary"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="submit" class="btn btn-outline-primary">Create</button>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,77 +1,130 @@
{% extends "base.html" %}
{% block content %}
<div class="row justify-content-center">
{% if operation != "" %}
<div class="col col-12">
<div class="row justify-content-center">
<div class="col col-12 col-lg-4">
<div class="alert alert-primary alert-dismissible fade show text-break" role="alert">
{{ operation }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
</div>
</div>
{% endif %}
<div class="col col-12 mb-3">
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modal-new"><i class="fas fa-plus"></i> New</button>
</div>
{% if services|length == 0 %}
<div class="col col-12 alert alert-primary text-center">
No service to show...
</div>
{% endif %}
{% for service in services %}
{% set id_server_name = service["SERVER_NAME"].replace(".", "-") %}
<div class="col col-12 col-lg-6">
<div class="card border-primary mb-3" style="max-width: 80rem;">
<div class="card-header border-primary bg-primary text-white">
{{ service["SERVER_NAME"] }}
<button class="btn btn-sm ms-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-delete-id-{{ id_server_name }}"><i class="fas fa-trash-alt"></i></button>
<button class="btn btn-sm mx-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-edit-id-{{ id_server_name }}"><i class="fas fa-edit"></i></button>
<a class="btn btn-sm mx-2 float-end btn-light" href="http://{{ service["SERVER_NAME"] }}" target="_blank"><i class="fas fa-eye"></i></a>
</div>
<div class="card-body text-dark">
<h5 class="card-title">Summary</h5>
<span class="card-text">
<div class="row justify-content-center">
<div class="col col-6">Reverse proxy</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_REVERSE_PROXY"], "yes") }}"></i></div>
<div class="col col-6">Serve files</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["SERVE_FILES"], "yes") }}"></i></div>
<div class="col col-6">Remote PHP</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["REMOTE_PHP"], ".+") }}"></i></div>
<div class="col col-6">HTTPS</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class([service["AUTO_LETS_ENCRYPT"], service["USE_CUSTOM_HTTPS"], service["GENERATE_SELF_SIGNED_SSL"]], ["yes", "yes", "yes"]) }}"></i></div>
<div class="col col-6">ModSecurity</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_MODSECURITY"], "yes") }}"></i></div>
<div class="col col-6">Bad behavior</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_BAD_BEHAVIOR"], "yes") }}"></i></div>
<div class="col col-6">Limit req</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_LIMIT_REQ"], "yes") }}"></i></div>
<div class="col col-6">DNSBL</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_DNSBL"], "yes") }}"></i></div>
</div>
</span>
</div>
</div>
</div>
{% include "services-edit.html" %}
{% include "services-delete.html" %}
{% endfor %}
{% include "services-new.html" %}
{% extends "base.html" %} {% block content %}
<div class="container mt-3 mb-3">
<div class="col col-12 mb-3 align-items-center text-center">
<button
class="btn btn-outline-success"
data-bs-toggle="modal"
data-bs-target="#modal-new"
>
New <i class="fa-solid fa-plus"></i>
</button>
</div>
{% if services|length == 0 %}
<div class="row justify-content-center">
<div class="col col-12 alert alert-primary text-center">
No service to show...
</div>
</div>
<div class="my-5 py-5"></div>
{% else %} {% for services_batched in services|batch(3) %}
<div class="row">
{% for service in services_batched %} {% set id_server_name =
service["SERVER_NAME"].replace(".", "-") %}
<div class="col-lg-6 mb-2 px-2">
<div class="card mb-2">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="ms-2 c-details">
<h6 class="mb-0">{{ service["SERVER_NAME"] }}</h6>
</div>
</div>
<div class="d-sm-flex align-items-center">
<div class="badge dropdown px-1">
<button
type="button"
class="btn btn-outline-secondary"
id="dropdownInfoButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="fa-solid fa-circle-info"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownInfoButton">
<li>
Reverse proxy
<i
class="fas fa-{{ env_to_summary_class(service['USE_REVERSE_PROXY'], 'yes') }} float-end"
></i>
</li>
<li>
Serve files
<i
class="fas fa-{{ env_to_summary_class(service['SERVE_FILES'], 'yes') }} float-end"
></i>
</li>
<li>
Remote PHP
<i
class="fas fa-{{ env_to_summary_class(service['REMOTE_PHP'], '.+') }} float-end"
></i>
</li>
<li>
HTTPS
<i
class="fas fa-{{ env_to_summary_class([service['AUTO_LETS_ENCRYPT'], service['USE_CUSTOM_HTTPS'], service['GENERATE_SELF_SIGNED_SSL']], ['yes', 'yes', 'yes']) }} float-end"
></i>
</li>
<li>
ModSecurity
<i
class="fas fa-{{ env_to_summary_class(service['USE_MODSECURITY'], 'yes') }} float-end"
></i>
</li>
<li>
Bad Behavior
<i
class="fas fa-{{ env_to_summary_class(service['USE_BAD_BEHAVIOR'], 'yes') }} float-end"
></i>
</li>
<li>
Limit req
<i
class="fas fa-{{ env_to_summary_class(service['USE_LIMIT_REQ'], 'yes') }} float-end"
></i>
</li>
<li>
DNSBL
<i
class="fas fa-{{ env_to_summary_class(service['USE_DNSBL'], 'yes') }} float-end"
></i>
</li>
</ul>
</div>
<div class="badge px-1">
<a href="http://{{ service['SERVER_NAME'] }}" target="_blank">
<button type="button" class="btn btn-outline-primary">
<i class="fa-solid fa-arrow-up-right-from-square"></i>
</button>
</a>
</div>
<div class="badge px-1">
<button
type="button"
class="btn btn-outline-secondary"
data-bs-toggle="modal"
data-bs-target="#modal-edit-id-{{ id_server_name }}"
>
<i class="fa-solid fa-sliders fa-rotate-90"></i>
</button>
</div>
<div class="badge px-1">
<button
type="button"
class="btn btn-outline-danger"
data-bs-toggle="modal"
data-bs-target="#modal-delete-id-{{ id_server_name }}"
>
<i class="fa-solid fa-trash-can"></i>
</button>
</div>
</div>
</div>
</div>
</div>
{% include "services-edit.html" %} {% include "services-delete.html" %} {%
endfor %}
</div>
{% endfor %} {% endif %} {% include "services-new.html" %}
</div>
{% endblock %}