mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
Brand new switch button and toast UI
This commit is contained in:
parent
2d3dffe5fc
commit
bdd984a887
@ -537,4 +537,3 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
|
2
src/api.py
Normal file
2
src/api.py
Normal file
@ -0,0 +1,2 @@
|
||||
from dashboard import request, jsonify, app
|
||||
|
@ -28,8 +28,7 @@ from icmplib import ping, traceroute
|
||||
from flask_socketio import SocketIO
|
||||
|
||||
# Import other python files
|
||||
from util import regex_match, check_DNS, check_Allowed_IPs, check_remote_endpoint, \
|
||||
check_IP_with_range, clean_IP_with_range
|
||||
from util import *
|
||||
|
||||
# Dashboard Version
|
||||
DASHBOARD_VERSION = 'v3.0.5'
|
||||
@ -375,6 +374,12 @@ def get_all_peers_data(config_name):
|
||||
get_endpoint(config_name)
|
||||
get_allowed_ip(conf_peer_data, config_name)
|
||||
|
||||
def getLockAccessPeers(config_name):
|
||||
col = g.cur.execute(f"PRAGMA table_info({config_name}_restrict_access)").fetchall()
|
||||
col = [a[1] for a in col]
|
||||
data = g.cur.execute(f"SELECT * FROM {config_name}_restrict_access").fetchall()
|
||||
result = [{col[i]: data[k][i] for i in range(len(col))} for k in range(len(data))]
|
||||
return result
|
||||
|
||||
def get_peers(config_name, search, sort_t):
|
||||
"""
|
||||
@ -504,6 +509,18 @@ def get_conf_list():
|
||||
)
|
||||
"""
|
||||
g.cur.execute(create_table)
|
||||
create_table = f"""
|
||||
CREATE TABLE IF NOT EXISTS {i}_restrict_access (
|
||||
id VARCHAR NOT NULL, private_key VARCHAR NULL, DNS VARCHAR NULL,
|
||||
endpoint_allowed_ip VARCHAR NULL, name VARCHAR NULL, total_receive FLOAT NULL,
|
||||
total_sent FLOAT NULL, total_data FLOAT NULL, endpoint VARCHAR NULL,
|
||||
status VARCHAR NULL, latest_handshake VARCHAR NULL, allowed_ip VARCHAR NULL,
|
||||
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, mtu INT NULL,
|
||||
keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL,
|
||||
PRIMARY KEY (id)
|
||||
)
|
||||
"""
|
||||
g.cur.execute(create_table)
|
||||
temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)}
|
||||
if temp['status'] == "running":
|
||||
temp['checked'] = 'checked'
|
||||
@ -620,7 +637,6 @@ def f_available_ips(config_name):
|
||||
Flask Functions
|
||||
"""
|
||||
|
||||
|
||||
@app.teardown_request
|
||||
def close_DB(exception):
|
||||
"""
|
||||
@ -1056,7 +1072,8 @@ def get_conf(config_name):
|
||||
"wg_ip": wg_ip,
|
||||
"sort_tag": sort,
|
||||
"dashboard_refresh_interval": int(config.get("Server", "dashboard_refresh_interval")),
|
||||
"peer_display_mode": peer_display_mode
|
||||
"peer_display_mode": peer_display_mode,
|
||||
"lock_access_peers": getLockAccessPeers(config_name)
|
||||
}
|
||||
if result['data']['status'] == "stopped":
|
||||
result['data']['checked'] = "nope"
|
||||
@ -1087,16 +1104,15 @@ def switch(config_name):
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||
return redirect('/')
|
||||
return jsonify({"status": False, "reason":"Can't stop peer"})
|
||||
elif status == "stopped":
|
||||
try:
|
||||
subprocess.check_output("wg-quick up " + config_name,
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||
return redirect('/')
|
||||
return redirect(request.referrer)
|
||||
|
||||
return jsonify({"status": False, "reason":"Can't turn on peer"})
|
||||
return jsonify({"status": True, "reason":""})
|
||||
|
||||
@app.route('/add_peer_bulk/<config_name>', methods=['POST'])
|
||||
def add_peer_bulk(config_name):
|
||||
@ -1240,24 +1256,7 @@ def remove_peer(config_name):
|
||||
if not isinstance(keys, list):
|
||||
return config_name + " is not running."
|
||||
else:
|
||||
sql_command = []
|
||||
wg_command = ["wg", "set", config_name]
|
||||
for delete_key in delete_keys:
|
||||
if delete_key not in keys:
|
||||
return "This key does not exist"
|
||||
sql_command.append("DELETE FROM " + config_name + " WHERE id = '" + delete_key + "';")
|
||||
wg_command.append("peer")
|
||||
wg_command.append(delete_key)
|
||||
wg_command.append("remove")
|
||||
try:
|
||||
remove_wg = subprocess.check_output(" ".join(wg_command),
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
save_wg = subprocess.check_output(f"wg-quick save {config_name}", shell=True, stderr=subprocess.STDOUT)
|
||||
g.cur.executescript(' '.join(sql_command))
|
||||
g.db.commit()
|
||||
except subprocess.CalledProcessError as exc:
|
||||
return exc.output.strip()
|
||||
return "true"
|
||||
return deletePeers(config_name, delete_keys, g.cur, g.db)
|
||||
|
||||
|
||||
@app.route('/save_peer_setting/<config_name>', methods=['POST'])
|
||||
@ -1530,6 +1529,51 @@ def switch_display_mode(mode):
|
||||
return "false"
|
||||
|
||||
|
||||
# APIs
|
||||
@app.route('/api/togglePeerAccess', methods=['POST'])
|
||||
def togglePeerAccess():
|
||||
data = request.get_json()
|
||||
print(data['peerID'])
|
||||
returnData = {"status": True, "reason": ""}
|
||||
required = ['peerID', 'config']
|
||||
if checkJSONAllParameter(required, data):
|
||||
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
||||
if checkUnlock:
|
||||
moveUnlockToLock = g.cur.execute(f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
||||
if g.cur.rowcount == 1:
|
||||
print(g.cur.rowcount)
|
||||
print(deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
||||
else:
|
||||
moveLockToUnlock = g.cur.execute(f"SELECT * FROM {data['config']}_restrict_access WHERE id='{data['peerID']}'").fetchone()
|
||||
try:
|
||||
if len(moveLockToUnlock[-1]) == 0:
|
||||
status = subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
else:
|
||||
now = str(datetime.now().strftime("%m%d%Y%H%M%S"))
|
||||
f_name = now + "_tmp_psk.txt"
|
||||
f = open(f_name, "w+")
|
||||
f.write(moveLockToUnlock[-1])
|
||||
f.close()
|
||||
subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]} preshared-key {f_name}",
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
os.remove(f_name)
|
||||
status = subprocess.check_output(f"wg-quick save {data['config']}", shell=True, stderr=subprocess.STDOUT)
|
||||
g.cur.execute(f"INSERT INTO {data['config']} SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||
if g.cur.rowcount == 1:
|
||||
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||
|
||||
except subprocess.CalledProcessError as exc:
|
||||
returnData["status"] = False
|
||||
returnData["reason"] = exc.output.strip()
|
||||
else:
|
||||
returnData["status"] = False
|
||||
returnData["reason"] = "Please provide all required parameters."
|
||||
|
||||
return jsonify(returnData)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Dashboard Tools Related
|
||||
"""
|
||||
@ -1625,6 +1669,7 @@ def init_dashboard():
|
||||
Create dashboard default configuration.
|
||||
"""
|
||||
|
||||
|
||||
# Set Default INI File
|
||||
if not os.path.isfile(DASHBOARD_CONF):
|
||||
open(DASHBOARD_CONF, "w+").close()
|
||||
|
@ -22,8 +22,10 @@ body {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100; /* Behind the navbar */
|
||||
padding: 48px 0 0; /* Height of navbar */
|
||||
z-index: 100;
|
||||
/* Behind the navbar */
|
||||
padding: 48px 0 0;
|
||||
/* Height of navbar */
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
@ -33,7 +35,8 @@ body {
|
||||
height: calc(100vh - 48px);
|
||||
padding-top: .5rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||
overflow-y: auto;
|
||||
/* Scrollable contents if viewport is shorter than content. */
|
||||
}
|
||||
|
||||
@supports ((position: -webkit-sticky) or (position: sticky)) {
|
||||
@ -73,6 +76,7 @@ body {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Navbar
|
||||
*/
|
||||
@ -142,7 +146,8 @@ body {
|
||||
|
||||
.info h6 {
|
||||
line-break: anywhere;
|
||||
transition: 0.2s ease-in-out;
|
||||
transition: all 0.4s cubic-bezier(0.96, -0.07, 0.34, 1.01);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.info .row .col-sm {
|
||||
@ -152,7 +157,6 @@ body {
|
||||
|
||||
.info .row .col-sm small {
|
||||
display: flex;
|
||||
|
||||
}
|
||||
|
||||
.info .row .col-sm small strong:last-child(1) {
|
||||
@ -164,7 +168,8 @@ body {
|
||||
padding: 0 1rem 0 0;
|
||||
}
|
||||
|
||||
.btn-control:active, .btn-control:focus{
|
||||
.btn-control:active,
|
||||
.btn-control:focus {
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none;
|
||||
@ -174,12 +179,14 @@ body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.btn-qrcode-peer:active, .btn-qrcode-peer:hover{
|
||||
.btn-qrcode-peer:active,
|
||||
.btn-qrcode-peer:hover {
|
||||
transform: scale(0.9) rotate(180deg);
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.btn-download-peer:active, .btn-download-peer:hover{
|
||||
.btn-download-peer:active,
|
||||
.btn-download-peer:hover {
|
||||
color: #17a2b8 !important;
|
||||
transform: translateY(5px);
|
||||
}
|
||||
@ -199,7 +206,15 @@ body {
|
||||
}
|
||||
|
||||
.btn-lock-peer:hover {
|
||||
color: #6c757d;
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.btn-lock-peer.lock{
|
||||
color: #6c757d
|
||||
}
|
||||
|
||||
.btn-lock-peer.lock:hover{
|
||||
color: #6c757d
|
||||
}
|
||||
|
||||
.btn-setting-peer:hover {
|
||||
@ -223,6 +238,7 @@ body {
|
||||
.switch {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.switch:hover {
|
||||
text-decoration: none
|
||||
}
|
||||
@ -253,6 +269,9 @@ body {
|
||||
|
||||
.index-switch {
|
||||
text-align: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
main {
|
||||
@ -267,7 +286,6 @@ main{
|
||||
.add_btn {
|
||||
bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
.peer_list {
|
||||
margin-bottom: 7rem !important;
|
||||
}
|
||||
@ -342,8 +360,10 @@ main{
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotating
|
||||
/* Safari and Chrome */
|
||||
|
||||
@-webkit-keyframes rotating /* Safari and Chrome */ {
|
||||
{
|
||||
from {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
@ -355,6 +375,7 @@ main{
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotating {
|
||||
from {
|
||||
-ms-transform: rotate(0deg);
|
||||
@ -388,7 +409,10 @@ main{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#peer_private_key_textbox, #private_key, #public_key, #peer_preshared_key_textbox{
|
||||
#peer_private_key_textbox,
|
||||
#private_key,
|
||||
#public_key,
|
||||
#peer_preshared_key_textbox {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
@ -422,22 +446,28 @@ main{
|
||||
/*padding: 0.6rem 0.9em;*/
|
||||
}
|
||||
|
||||
#username, #password{
|
||||
#username,
|
||||
#password {
|
||||
padding: 0.6rem calc( 0.9rem + 32px);
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
label[for="username"], label[for="password"]{
|
||||
label[for="username"],
|
||||
label[for="password"] {
|
||||
font-size: 1rem;
|
||||
margin: 0 !important;
|
||||
transform: translateY(30px) translateX(16px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*label[for="password"]{*/
|
||||
/* transform: translateY(32px) translateX(16px);*/
|
||||
/*}*/
|
||||
|
||||
/*label[for="password"]{*/
|
||||
|
||||
|
||||
/* transform: translateY(32px) translateX(16px);*/
|
||||
|
||||
|
||||
/*}*/
|
||||
|
||||
.modal-content {
|
||||
border-radius: 10px;
|
||||
@ -458,6 +488,7 @@ label[for="username"], label[for="password"]{
|
||||
background-color: #dfdfdf;
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes loading {
|
||||
0% {
|
||||
background-color: #dfdfdf;
|
||||
@ -480,10 +511,13 @@ label[for="username"], label[for="password"]{
|
||||
}
|
||||
|
||||
.info_loading {
|
||||
animation: loading 2s infinite ease-in-out;
|
||||
border-radius: 5px;
|
||||
height: 19px;
|
||||
transition: 0.3s ease-in-out;
|
||||
/* animation: loading 2s infinite ease-in-out;
|
||||
/* border-radius: 5px; */
|
||||
height: 19.19px;
|
||||
/* transition: 0.3s ease-in-out; */
|
||||
|
||||
/* transform: translateX(40px); */
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
#conf_status_btn {
|
||||
@ -500,7 +534,8 @@ label[for="username"], label[for="password"]{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#selected_ip_list .badge, #selected_peer_list .badge{
|
||||
#selected_ip_list .badge,
|
||||
#selected_peer_list .badge {
|
||||
margin: 0.1rem
|
||||
}
|
||||
|
||||
@ -568,14 +603,20 @@ pre.index-alert{
|
||||
}
|
||||
|
||||
.peerName {
|
||||
margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.peerLightContainer {
|
||||
text-transform: uppercase; margin: 0; margin-left: auto !important;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.conf_card .dot, .info .dot {
|
||||
.conf_card .dot,
|
||||
.info .dot {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
|
||||
@ -624,3 +665,99 @@ pre.index-alert{
|
||||
height: calc( 100% - 47px) !important;
|
||||
max-height: calc( 100% - 47px) !important;
|
||||
}
|
||||
|
||||
#switch{
|
||||
transition: all 350ms ease-in;
|
||||
}
|
||||
|
||||
.toggle--switch{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggleLabel{
|
||||
width: 64px;
|
||||
height: 32px;
|
||||
background-color: #6c757d17;
|
||||
display: flex;
|
||||
position: relative;
|
||||
border: 2px solid #6c757d8c;
|
||||
border-radius: 100px;
|
||||
transition: all 350ms ease-in;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toggle--switch.waiting + .toggleLabel{
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.toggleLabel::before{
|
||||
background-color: #6c757d;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
content: "";
|
||||
border-radius: 100px;
|
||||
margin: 1px;
|
||||
position: absolute;
|
||||
animation-name: off;
|
||||
animation-duration: 350ms;
|
||||
animation-fill-mode: forwards;
|
||||
transition: all 350ms ease-in;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggle--switch:checked + .toggleLabel{
|
||||
background-color: #007bff17 !important;
|
||||
border: 2px solid #007bff8c;
|
||||
}
|
||||
|
||||
.toggle--switch:checked + .toggleLabel::before{
|
||||
background-color: #007bff;
|
||||
animation-name: on;
|
||||
animation-duration: 350ms;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes on {
|
||||
0%{
|
||||
left: 0px;
|
||||
}
|
||||
60%{
|
||||
left: 0px;
|
||||
width: 40px;
|
||||
}
|
||||
100%{
|
||||
left: 32px;
|
||||
width: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes off {
|
||||
0%{
|
||||
left: 32px;
|
||||
}
|
||||
60%{
|
||||
left: 18px;
|
||||
width: 40px;
|
||||
}
|
||||
100%{
|
||||
left: 0px;
|
||||
width: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
.toast{
|
||||
min-width: 300px;
|
||||
background-color: rgba(255,255,255,1);
|
||||
}
|
||||
|
||||
.toast-header{
|
||||
background-color: rgba(255,255,255);
|
||||
}
|
||||
|
||||
.toast-progressbar{
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: #007bff;
|
||||
border-bottom-left-radius: .25rem;
|
||||
}
|
2
src/static/css/dashboard.min.css
vendored
2
src/static/css/dashboard.min.css
vendored
File diff suppressed because one or more lines are too long
@ -9,7 +9,6 @@
|
||||
/**
|
||||
* Definitions
|
||||
*/
|
||||
|
||||
let peers = [];
|
||||
let configuration_name;
|
||||
let configuration_interval;
|
||||
@ -63,8 +62,7 @@
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
datasets: [{
|
||||
label: 'Data Sent',
|
||||
data: [],
|
||||
stroke: '#FFFFFF',
|
||||
@ -224,17 +222,19 @@
|
||||
* @param response
|
||||
*/
|
||||
function configurationHeader(response) {
|
||||
let $conf_status_btn = document.getElementById("conf_status_btn");
|
||||
let $conf_status_btn = $(".toggle--switch");
|
||||
|
||||
if (response.checked === "checked") {
|
||||
$conf_status_btn.innerHTML = `<a href="#" id="${response.name}" ${response.checked} class="switch text-primary"><i class="bi bi-toggle2-on"></i> ON</a>`;
|
||||
$conf_status_btn.prop("checked", true)
|
||||
}else{
|
||||
$conf_status_btn.innerHTML = `<a href="#" id="${response.name}" ${response.checked} class="switch text-primary"><i class="bi bi-toggle2-off"></i> OFF</a>`;
|
||||
$conf_status_btn.prop("checked", false)
|
||||
}
|
||||
$conf_status_btn.data("conf-id", configuration_name)
|
||||
|
||||
|
||||
if (response.running_peer > 0) {
|
||||
let d = new Date();
|
||||
let time = d.toLocaleString("en-us",
|
||||
{hour: '2-digit', minute: '2-digit', second: "2-digit", hourCycle: 'h23'});
|
||||
let time = d.toLocaleString("en-us", { hour: '2-digit', minute: '2-digit', second: "2-digit", hourCycle: 'h23' });
|
||||
totalDataUsageChartObj.data.labels.push(`${time}`);
|
||||
|
||||
if (totalDataUsageChartObj.data.datasets[0].data.length === 0) {
|
||||
@ -254,8 +254,7 @@
|
||||
let k = 0;
|
||||
if (chartUnit === "MB") {
|
||||
k = 1024;
|
||||
}
|
||||
else if (chartUnit === "KB"){
|
||||
} else if (chartUnit === "KB") {
|
||||
k = 1048576;
|
||||
} else {
|
||||
k = 1;
|
||||
@ -270,11 +269,9 @@
|
||||
}
|
||||
|
||||
document.querySelector("#conf_name").textContent = configuration_name;
|
||||
$conf_status_btn.classList.remove("info_loading");
|
||||
$("#switch").removeClass("info_loading");
|
||||
document.querySelectorAll("#sort_by_dropdown option").forEach(ele => ele.removeAttribute("selected"));
|
||||
document.querySelector(`#sort_by_dropdown option[value="${response.sort_tag}"]`).setAttribute("selected", "selected");
|
||||
// document.querySelectorAll(".interval-btn-group button").forEach(ele => ele.classList.remove("active"));
|
||||
// document.querySelector(`button[data-refresh-interval="${response.dashboard_refresh_interval}"]`).classList.add("active");
|
||||
document.querySelector("#conf_status").innerHTML = `${response.status}<span class="dot dot-${response.status}"></span>`;
|
||||
document.querySelector("#conf_connected_peers").innerHTML = response.running_peer;
|
||||
document.querySelector("#conf_total_data_usage").innerHTML = `${response.total_data_usage[0]} GB`;
|
||||
@ -283,9 +280,15 @@
|
||||
document.querySelector("#conf_public_key").innerHTML = response.public_key;
|
||||
document.querySelector("#conf_listen_port").innerHTML = response.listen_port === "" ? "N/A" : response.listen_port;
|
||||
document.querySelector("#conf_address").innerHTML = response.conf_address;
|
||||
document.querySelectorAll(".info h6").forEach(ele => ele.classList.remove("info_loading"));
|
||||
let delay = 0;
|
||||
let h6 = $(".info h6");
|
||||
for (let i = 0; i < h6.length; i++){
|
||||
setTimeout(function(){
|
||||
$(h6[i]).removeClass("info_loading");
|
||||
}, delay)
|
||||
delay += 40
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all responded information onto the peers list
|
||||
* @param response
|
||||
@ -324,14 +327,14 @@
|
||||
<div class="col-sm">
|
||||
<hr>
|
||||
<div class="button-group" style="display:flex">
|
||||
<button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" id="${peer.id}" data-toggle="modal">
|
||||
<button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" data-peer-id="${peer.id}" data-toggle="modal">
|
||||
<i class="bi bi-gear-fill" data-toggle="tooltip" data-placement="bottom" title="Peer Settings"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="${peer.id}" data-toggle="modal">
|
||||
<button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" data-peer-id="${peer.id}" data-toggle="modal">
|
||||
<i class="bi bi-x-circle-fill" data-toggle="tooltip" data-placement="bottom" title="Delete Peer"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-lock-peer btn-control" id="${peer.id}" data-toggle="modal">
|
||||
<i class="bi bi-lock-fill" data-toggle="tooltip" data-placement="bottom" title=""></i>
|
||||
<button type="button" class="btn btn-outline-success btn-lock-peer btn-control" data-peer-id="${peer.id}" data-toggle="modal">
|
||||
<i class="bi bi-ethernet" data-toggle="tooltip" data-placement="bottom" data-original-title='Peer enabled. Click to disable peer.' data-peer-name="${peer.name}"></i>
|
||||
</button>`;
|
||||
if (peer.private_key !== "") {
|
||||
peer_control += '<div class="share_peer_btn_group" style="margin-left: auto !important; display: inline"><button type="button" class="btn btn-outline-success btn-qrcode-peer btn-control" data-imgsrc="/qrcode/' + response.name + '?id=' + encodeURIComponent(peer.id) + '"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 19px;" fill="#28a745"><path d="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zM13 3v8h8V3h-8zm6 6h-4V5h4v4zM13 13h2v2h-2zM15 15h2v2h-2zM13 17h2v2h-2zM17 17h2v2h-2zM19 19h2v2h-2zM15 19h2v2h-2zM17 13h2v2h-2zM19 15h2v2h-2z"/></svg></button><a href="/download/' + response.name + '?id=' + encodeURIComponent(peer.id) + '" class="btn btn-outline-info btn-download-peer btn-control"><i class="bi bi-download"></i></a></div>';
|
||||
@ -357,6 +360,59 @@
|
||||
'</div></div>';
|
||||
result += html;
|
||||
});
|
||||
response.lock_access_peers.forEach(function(peer) {
|
||||
let total_r = 0;
|
||||
let total_s = 0;
|
||||
total_r += peer.cumu_receive;
|
||||
total_s += peer.cumu_sent;
|
||||
let spliter = '<div class="w-100"></div>';
|
||||
let peer_name =
|
||||
`<div class="col-sm peerNameCol">
|
||||
<h5 class="peerName">${peer.name === "" ? "Untitled" : peer.name}</h5>
|
||||
<h6 class="peerLightContainer"><span class="dot dot-${peer.status}" style="margin-left: auto !important;" data-toggle="tooltip" data-placement="left"></span></h6>
|
||||
</div>`;
|
||||
let peer_transfer =
|
||||
`<div class="col-12 peer_data_group" style="">
|
||||
<p class="text-primary" style="">
|
||||
<small><i class="bi bi-arrow-down-right"></i> ${roundN(peer.total_receive + total_r, 4)} GB</small>
|
||||
</p>
|
||||
<p class="text-success">
|
||||
<small><i class="bi bi-arrow-up-right"></i> ${roundN(peer.total_sent + total_s, 4)} GB</small>
|
||||
</p>
|
||||
</div>`;
|
||||
let peer_key = '<div class="col-sm"><small class="text-muted" style="display: flex"><strong>PEER</strong><strong style="margin-left: auto!important; opacity: 0; transition: 0.2s ease-in-out" class="text-primary">CLICK TO COPY</strong></small> <h6><samp class="ml-auto key">' + peer.id + '</samp></h6></div>';
|
||||
let peer_allowed_ip = '<div class="col-sm"><small class="text-muted"><strong>ALLOWED IP</strong></small><h6 style="text-transform: uppercase;">' + peer.allowed_ip + '</h6></div>';
|
||||
let peer_latest_handshake = '<div class="col-sm"> <small class="text-muted"><strong>LATEST HANDSHAKE</strong></small> <h6 style="text-transform: uppercase;">' + peer.latest_handshake + '</h6> </div>';
|
||||
let peer_endpoint = '<div class="col-sm"><small class="text-muted"><strong>END POINT</strong></small><h6 style="text-transform: uppercase;">' + peer.endpoint + '</h6></div>';
|
||||
let peer_control = `
|
||||
<div class="col-sm">
|
||||
<hr>
|
||||
<div class="button-group" style="display:flex; align-items: center;">
|
||||
<button type="button" class="btn btn-outline-success btn-lock-peer btn-control lock" data-peer-id="${peer.id}" data-toggle="modal">
|
||||
<i class="bi bi-ethernet" data-toggle="tooltip" data-placement="bottom" data-original-title='Peer disabled. Click to enable peer.' data-peer-name="${peer.name}"></i>
|
||||
</button>
|
||||
<small class="text-muted" style="margin-left: auto">Peer Disabled</small>
|
||||
</div>`;
|
||||
let html = '<div class="' + mode + '" data-id="' + peer.id + '">' +
|
||||
'<div class="card mb-3 card-' + peer.status + '">' +
|
||||
'<div class="card-body">' +
|
||||
'<div class="row">' +
|
||||
peer_name +
|
||||
spliter +
|
||||
peer_transfer +
|
||||
peer_key +
|
||||
peer_allowed_ip +
|
||||
peer_latest_handshake +
|
||||
spliter +
|
||||
peer_endpoint +
|
||||
spliter +
|
||||
peer_control +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div></div>';
|
||||
result += html;
|
||||
});
|
||||
document.querySelector(".peer_list").innerHTML = result;
|
||||
if (configuration_interval === undefined) {
|
||||
setConfigurationInterval();
|
||||
@ -407,8 +463,7 @@
|
||||
data_list.forEach((ele) => ele.removeAttr("disabled"));
|
||||
$add_peer.removeAttribute("disabled");
|
||||
$add_peer.innerHTML = "Save";
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
window.configurations.loadPeers("");
|
||||
data_list.forEach((ele) => ele.removeAttr("disabled"));
|
||||
$("#add_peer_form").trigger("reset");
|
||||
@ -456,8 +511,7 @@
|
||||
.removeClass("d-none");
|
||||
$("#confirm_delete_bulk_peers").removeAttr("disabled").html("Delete");
|
||||
}
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
if (window.configurations.deleteModal()._isShown) {
|
||||
window.configurations.deleteModal().toggle();
|
||||
}
|
||||
@ -468,8 +522,7 @@
|
||||
window.configurations.deleteBulkModal().toggle();
|
||||
}
|
||||
window.configurations.loadPeers($('#search_peer_textbox').val());
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html("Peer deleted!");
|
||||
window.configurations.showToast(`Deleted ${peer_ids.length} peers`)
|
||||
$("#delete_peer").removeAttr("disabled").html("Delete");
|
||||
}
|
||||
}
|
||||
@ -567,6 +620,7 @@
|
||||
let time = 0;
|
||||
let count = 0;
|
||||
let d1 = new Date();
|
||||
|
||||
function loadPeers(searchString) {
|
||||
d1 = new Date();
|
||||
let good = true;
|
||||
@ -586,6 +640,7 @@
|
||||
|
||||
function parsePeers(response) {
|
||||
if (response.status) {
|
||||
removeAllTooltips();
|
||||
let d2 = new Date();
|
||||
let seconds = (d2 - d1);
|
||||
time += seconds;
|
||||
@ -612,6 +667,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
function removeAllTooltips(){
|
||||
$(".tooltip").remove()
|
||||
}
|
||||
|
||||
function toggleAccess(peerID){
|
||||
$.ajax({
|
||||
url: "/api/togglePeerAccess",
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
data: JSON.stringify({"peerID": peerID, "config": configuration_name})
|
||||
}).done(function(res){
|
||||
if(res.status){
|
||||
loadPeers($('#search_peer_textbox').val());
|
||||
}else{
|
||||
showToast(res.reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Private and Public key for a new peer
|
||||
*/
|
||||
@ -628,9 +702,24 @@
|
||||
* Show toast
|
||||
* @param msg
|
||||
*/
|
||||
let numberToast = 0;
|
||||
function showToast(msg) {
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html(msg);
|
||||
$(".toastContainer").append(
|
||||
`<div id="${numberToast}-toast" class="toast hide" role="alert" data-delay="5000">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">WGDashboard</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">${msg}</div>
|
||||
<div class="toast-progressbar"></div>
|
||||
</div>` )
|
||||
$(`#${numberToast}-toast`).toast('show');
|
||||
$(`#${numberToast}-toast .toast-body`).html(msg);
|
||||
$(`#${numberToast}-toast .toast-progressbar`).css("transition", `width ${$(`#${numberToast}-toast .toast-progressbar`).parent().data('delay')}ms cubic-bezier(0, 0, 0, 0)`);
|
||||
$(`#${numberToast}-toast .toast-progressbar`).css("width", "0px");
|
||||
numberToast++;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -754,6 +843,8 @@
|
||||
addPeersByBulk: () => { addPeersByBulk(); },
|
||||
deletePeers: (config, peers_ids) => { deletePeers(config, peers_ids); },
|
||||
parsePeers: (response) => { parsePeers(response); },
|
||||
toggleAccess: (peerID) => { toggleAccess(peerID) },
|
||||
|
||||
|
||||
setConfigurationName: (confName) => { configuration_name = confName; },
|
||||
getConfigurationName: () => { return configuration_name; },
|
||||
@ -793,13 +884,33 @@ document.querySelector(".add_btn").addEventListener("click", () => {
|
||||
/**
|
||||
* When configuration switch got click
|
||||
*/
|
||||
document.querySelector(".info").addEventListener("click", (event) => {
|
||||
let selector = document.querySelector(".switch");
|
||||
if (selector.contains(event.target)){
|
||||
selector.style.display = "none";
|
||||
document.querySelector('div[role=status]').style.display = "inline-block";
|
||||
location.replace(`/switch/${selector.getAttribute("id")}`);
|
||||
$(".toggle--switch").on("click", function(){
|
||||
$(this).addClass("waiting").attr("disabled", "disabled");
|
||||
let id = window.configurations.getConfigurationName();
|
||||
let status = $(this).prop("checked");
|
||||
let ele = $(this);
|
||||
$.ajax({
|
||||
url: `/switch/${id}`
|
||||
}).done(function(res){
|
||||
console.log();
|
||||
if (res){
|
||||
if (status){
|
||||
window.configurations.showToast(`${id} is running.`)
|
||||
}else{
|
||||
window.configurations.showToast(`${id} is stopped.`)
|
||||
}
|
||||
ele.removeClass("waiting");
|
||||
ele.removeAttr("disabled");
|
||||
}else{
|
||||
if (status){
|
||||
$(this).prop("checked", false)
|
||||
}else{
|
||||
$(this).prop("checked", true)
|
||||
}
|
||||
}
|
||||
window.configurations.loadPeers($('#search_peer_textbox').val())
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
@ -909,8 +1020,7 @@ $add_peer.addEventListener("click",function(){
|
||||
data_list.forEach((ele) => ele.removeAttr("disabled"));
|
||||
$add_peer.removeAttribute("disabled");
|
||||
$add_peer.innerHTML = "Save";
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
window.configurations.loadPeers("");
|
||||
data_list.forEach((ele) => ele.removeAttr("disabled"));
|
||||
$("#add_peer_form").trigger("reset");
|
||||
@ -965,8 +1075,7 @@ $("#bulk_add").on("change", function (){
|
||||
$(hide[i]).attr("disabled", "disabled");
|
||||
}
|
||||
amount.removeAttr("disabled");
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
for (let i = 0; i < hide.length; i++) {
|
||||
if ($(hide[i]).attr('id') !== "public_key") {
|
||||
$(hide[i]).removeAttr("disabled");
|
||||
@ -1072,21 +1181,23 @@ $body.on("click", ".btn-qrcode-peer", function (){
|
||||
* When the delete button got clicked on each peer
|
||||
*/
|
||||
$body.on("click", ".btn-delete-peer", function() {
|
||||
let peer_id = $(this).attr("id");
|
||||
let peer_id = $(this).data('peer-id')
|
||||
$("#delete_peer").data("peer-id", peer_id);
|
||||
window.configurations.deleteModal().toggle();
|
||||
});
|
||||
|
||||
$body.on("click", ".btn-lock-peer", function() {
|
||||
let $lockGlyph = "bi-lock-fill";
|
||||
let $unlockGlyph = "bi-unlock-fill";
|
||||
|
||||
if ($(this).children().hasClass($lockGlyph)){
|
||||
$(this).children().removeClass($lockGlyph).addClass($unlockGlyph);
|
||||
$(this).children().tooltip('hide').attr('data-original-title', 'Lock Peer').tooltip('show');
|
||||
window.configurations.toggleAccess($(this).data('peer-id'), window.configurations.getConfigurationName());
|
||||
if ($(this).hasClass("lock")) {
|
||||
console.log($(this).data("peer-name"))
|
||||
window.configurations.showToast(`Enabled ${$(this).children().data("peer-name")}`)
|
||||
$(this).removeClass("lock")
|
||||
$(this).children().tooltip('hide').attr('data-original-title', 'Peer enabled. Click to disable peer.').tooltip('show');
|
||||
} else {
|
||||
$(this).children().removeClass($unlockGlyph).addClass($lockGlyph);
|
||||
$(this).children().tooltip('hide').attr('data-original-title', 'Unlock Peer').tooltip('show');
|
||||
// Currently unlocked
|
||||
window.configurations.showToast(`Disabled ${$(this).children().data("peer-name")}`)
|
||||
$(this).addClass("lock");
|
||||
$(this).children().tooltip('hide').attr('data-original-title', 'Peer disabled. Click to enable peer.').tooltip('show');
|
||||
}
|
||||
});
|
||||
|
||||
@ -1112,7 +1223,7 @@ $("#delete_peer").on("click",function(){
|
||||
*/
|
||||
$body.on("click", ".btn-setting-peer", function() {
|
||||
// window.configurations.startProgressBar();
|
||||
let peer_id = $(this).attr("id");
|
||||
let peer_id = $(this).data("peer-id");
|
||||
$("#save_peer_setting").attr("peer_id", peer_id);
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
@ -1405,8 +1516,7 @@ $("#delete_peers_by_bulk_btn").on("click", () => {
|
||||
$delete_bulk_modal_list.html('');
|
||||
peers.forEach((peer) => {
|
||||
let name;
|
||||
if (peer.name === "") { name = "Untitled Peer"; }
|
||||
else { name = peer.name; }
|
||||
if (peer.name === "") { name = "Untitled Peer"; } else { name = peer.name; }
|
||||
$delete_bulk_modal_list.append('<a class="list-group-item list-group-item-action delete-bulk-peer-item" style="cursor: pointer" data-id="' +
|
||||
peer.id + '" data-name="' + name + '">' + name + '<br><code>' + peer.id + '</code></a>');
|
||||
});
|
||||
|
24
src/static/js/configuration.min.js
vendored
24
src/static/js/configuration.min.js
vendored
File diff suppressed because one or more lines are too long
@ -27,9 +27,10 @@
|
||||
</div>
|
||||
<div class="col">
|
||||
<small class="text-muted"><strong>SWITCH</strong></small><br>
|
||||
<div id="conf_status_btn" class="info_loading"></div>
|
||||
<div class="spinner-border text-primary" role="status" style="display: none; margin-top: 10px">
|
||||
<span class="sr-only">Loading...</span>
|
||||
<!-- <div id="conf_status_btn" class="info_loading"></div> -->
|
||||
<div id="switch" class="info_loading">
|
||||
<input type="checkbox" class="toggle--switch" id="switch">
|
||||
<label for="switch" class="toggleLabel"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100"></div>
|
||||
@ -424,8 +425,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="position-fixed top-0 right-0 p-3" style="z-index: 5; right: 0; top: 50px;">
|
||||
<div id="alertToast" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
|
||||
<div class="position-fixed top-0 right-0 p-3 toastContainer" style="z-index: 5; right: 0; top: 50px;">
|
||||
<!-- <div id="alertToast" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">WGDashboard</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
@ -434,12 +435,13 @@
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
{% include "tools.html" %}
|
||||
</body>
|
||||
{% include "footer.html" %}
|
||||
<script src="{{ url_for('static',filename='js/configuration.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/wireguard.min.js') }}"></script>
|
||||
<script>
|
||||
configurations.setConfigurationName("{{ conf_data['name'] }}");
|
||||
configurations.setActiveConfigurationName();
|
||||
|
@ -23,8 +23,10 @@
|
||||
{% if conf == [] %}
|
||||
<p class="text-muted">You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% for i in conf%}
|
||||
<div class="card mt-3 conf_card">
|
||||
<div class="card mt-3 conf_card" data-conf-id="{{i['conf']}}">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col card-col">
|
||||
@ -35,21 +37,25 @@
|
||||
</div>
|
||||
<div class="col card-col">
|
||||
<small class="text-muted"><strong>STATUS</strong></small>
|
||||
<h6 style="text-transform: uppercase; margin:0 !important;">{{i['status']}}<span class="dot dot-{{i['status']}}"></span></h6>
|
||||
<h6 style="text-transform: uppercase; margin:0 !important;"><span>{{i['status']}}</span><span class="dot dot-{{i['status']}}"></span></h6>
|
||||
</div>
|
||||
<div class="col-md card-col">
|
||||
<div class="col-sm card-col">
|
||||
<small class="text-muted"><strong>PUBLIC KEY</strong></small>
|
||||
<h6 style="margin:0 !important;"><samp>{{i['public_key']}}</samp></h6>
|
||||
</div>
|
||||
<div class="col-md index-switch">
|
||||
{% if i['checked'] == "checked" %}
|
||||
<a href="#" id="{{i['conf']}}" {{i['checked']}} class="switch text-primary tt"><i class="bi bi-toggle2-on"></i></a>
|
||||
<div class="col-sm index-switch">
|
||||
<div class="switch-test">
|
||||
<input type="checkbox" class="toggle--switch" id="{{i['conf']}}-switch" {{i['checked']}} data-conf-id="{{i['conf']}}">
|
||||
<label for="{{i['conf']}}-switch" class="toggleLabel"></label>
|
||||
</div>
|
||||
<!-- {% if i['checked'] == "checked" %}
|
||||
<a href="#" id="{{i['conf']}}" class="switch text-primary tt"><i class="bi bi-toggle2-on"></i></a>
|
||||
{% else %}
|
||||
<a href="#" id="{{i['conf']}}" {{i['checked']}} class="switch text-secondary"><i class="bi bi-toggle2-off"></i></a>
|
||||
{% endif %}
|
||||
<div class="spinner-border text-primary" role="status" style="display: none">
|
||||
{% endif %} -->
|
||||
<!-- <div class="spinner-border text-primary" role="status" style="display: none">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,10 +63,69 @@
|
||||
{%endfor%}
|
||||
</main>
|
||||
</div>
|
||||
<div class="position-fixed top-0 right-0 p-3 toastContainer" style="z-index: 5; right: 0; top: 50px;">
|
||||
|
||||
</div>
|
||||
{% include "tools.html" %}
|
||||
</body>
|
||||
{% include "footer.html" %}
|
||||
<script>
|
||||
let numberToast = 0;
|
||||
|
||||
|
||||
function showToast(msg){
|
||||
$(".toastContainer").append(
|
||||
`<div id="${numberToast}-toast" class="toast hide" role="alert" data-delay="5000">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">WGDashboard</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">${msg}</div>
|
||||
<div class="toast-progressbar"></div>
|
||||
</div>` )
|
||||
$(`#${numberToast}-toast`).toast('show');
|
||||
$(`#${numberToast}-toast .toast-body`).html(msg);
|
||||
$(`#${numberToast}-toast .toast-progressbar`).css("transition", `width ${$(`#${numberToast}-toast .toast-progressbar`).parent().data('delay')}ms cubic-bezier(0, 0, 0, 0)`);
|
||||
$(`#${numberToast}-toast .toast-progressbar`).css("width", "0px");
|
||||
numberToast++;
|
||||
}
|
||||
|
||||
|
||||
$(".toggle--switch").on("change", function(){
|
||||
$(this).addClass("waiting").attr("disabled", "disabled");
|
||||
let id = $(this).data("conf-id");
|
||||
let status = $(this).prop("checked");
|
||||
let ele = $(this);
|
||||
let label = $(this).siblings("label");
|
||||
$.ajax({
|
||||
url: `/switch/${id}`
|
||||
}).done(function(res){
|
||||
let dot = $(`div[data-conf-id="${id}"] .dot`);
|
||||
console.log();
|
||||
if (res){
|
||||
if (status){
|
||||
dot.removeClass("dot-stopped").addClass("dot-running");
|
||||
dot.siblings().text("Running");
|
||||
showToast(`${id} is running.`)
|
||||
}else{
|
||||
dot.removeClass("dot-running").addClass("dot-stopped");
|
||||
showToast(`${id} is stopped.`)
|
||||
}
|
||||
ele.removeClass("waiting");
|
||||
ele.removeAttr("disabled");
|
||||
}else{
|
||||
if (status){
|
||||
$(this).prop("checked", false)
|
||||
}else{
|
||||
$(this).prop("checked", true)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
$('.switch').on("click", function() {
|
||||
$(this).siblings($(".spinner-border")).css("display", "inline-block")
|
||||
@ -70,7 +135,7 @@
|
||||
$(".sb-home-url").addClass("active");
|
||||
|
||||
$(".card-body").on("click", function(handle){
|
||||
if ($(handle.target).attr("class") !== "bi bi-toggle2-off" && $(handle.target).attr("class") !== "bi bi-toggle2-on") {
|
||||
if ($(handle.target).attr("class") !== "toggleLabel" && $(handle.target).attr("class") !== "toggle--switch") {
|
||||
window.open($(this).find("a").attr("href"), "_self");
|
||||
}
|
||||
});
|
||||
|
33
src/util.py
33
src/util.py
@ -1,5 +1,6 @@
|
||||
import re
|
||||
|
||||
import subprocess
|
||||
import dashboard
|
||||
"""
|
||||
Helper Functions
|
||||
"""
|
||||
@ -79,3 +80,33 @@ def check_remote_endpoint(address):
|
||||
return (check_IP(address) or regex_match("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]",
|
||||
address))
|
||||
|
||||
|
||||
def deletePeers(config_name, delete_keys, cur, db):
|
||||
sql_command = []
|
||||
wg_command = ["wg", "set", config_name]
|
||||
for delete_key in delete_keys:
|
||||
if delete_key not in dashboard.get_conf_peer_key(config_name):
|
||||
return "This key does not exist"
|
||||
sql_command.append("DELETE FROM " + config_name + " WHERE id = '" + delete_key + "';")
|
||||
wg_command.append("peer")
|
||||
wg_command.append(delete_key)
|
||||
wg_command.append("remove")
|
||||
try:
|
||||
print("deleting...")
|
||||
remove_wg = subprocess.check_output(" ".join(wg_command),
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
save_wg = subprocess.check_output(f"wg-quick save {config_name}", shell=True, stderr=subprocess.STDOUT)
|
||||
cur.executescript(' '.join(sql_command))
|
||||
db.commit()
|
||||
except subprocess.CalledProcessError as exc:
|
||||
return exc.output.strip()
|
||||
return "true"
|
||||
|
||||
def checkJSONAllParameter(required, data):
|
||||
if len(data) == 0:
|
||||
print("length 0")
|
||||
return False
|
||||
for i in required:
|
||||
if i not in list(data.keys()):
|
||||
return False
|
||||
return True
|
Loading…
Reference in New Issue
Block a user