mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
Finished implementing add/delete config
This commit is contained in:
parent
46efe2b8dd
commit
b9633bbcd6
94
src/api.py
94
src/api.py
@ -1,43 +1,49 @@
|
|||||||
import ipaddress, subprocess, datetime, os, util
|
import ipaddress, subprocess, datetime, os, util
|
||||||
from util import *
|
from util import *
|
||||||
|
|
||||||
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
|
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
|
||||||
good = {"status": True, "reason": ""}
|
good = {"status": True, "reason": ""}
|
||||||
|
|
||||||
|
|
||||||
def togglePeerAccess(data, g):
|
def togglePeerAccess(data, g):
|
||||||
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
||||||
if checkUnlock:
|
if checkUnlock:
|
||||||
moveUnlockToLock = g.cur.execute(f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
moveUnlockToLock = g.cur.execute(
|
||||||
|
f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
||||||
if g.cur.rowcount == 1:
|
if g.cur.rowcount == 1:
|
||||||
print(g.cur.rowcount)
|
print(g.cur.rowcount)
|
||||||
print(util.deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
print(util.deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
||||||
else:
|
else:
|
||||||
moveLockToUnlock = g.cur.execute(f"SELECT * FROM {data['config']}_restrict_access WHERE id='{data['peerID']}'").fetchone()
|
moveLockToUnlock = g.cur.execute(
|
||||||
|
f"SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'").fetchone()
|
||||||
try:
|
try:
|
||||||
if len(moveLockToUnlock[-1]) == 0:
|
if len(moveLockToUnlock[-1]) == 0:
|
||||||
status = subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
status = subprocess.check_output(
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
else:
|
else:
|
||||||
now = str(datetime.datetime.now().strftime("%m%d%Y%H%M%S"))
|
now = str(datetime.datetime.now().strftime("%m%d%Y%H%M%S"))
|
||||||
f_name = now + "_tmp_psk.txt"
|
f_name = now + "_tmp_psk.txt"
|
||||||
f = open(f_name, "w+")
|
f = open(f_name, "w+")
|
||||||
f.write(moveLockToUnlock[-1])
|
f.write(moveLockToUnlock[-1])
|
||||||
f.close()
|
f.close()
|
||||||
subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]} preshared-key {f_name}",
|
subprocess.check_output(
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
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)
|
os.remove(f_name)
|
||||||
status = subprocess.check_output(f"wg-quick save {data['config']}", shell=True, stderr=subprocess.STDOUT)
|
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']}'")
|
g.cur.execute(
|
||||||
|
f"INSERT INTO {data['config']} SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||||
if g.cur.rowcount == 1:
|
if g.cur.rowcount == 1:
|
||||||
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||||
|
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
return {"status": False, "reason": str(exc.output.strip())}
|
return {"status": False, "reason": str(exc.output.strip())}
|
||||||
return good
|
return good
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class addConfiguration:
|
class addConfiguration:
|
||||||
def AddressCheck(data):
|
def AddressCheck(self, data):
|
||||||
address = data['address']
|
address = data['address']
|
||||||
address = address.replace(" ", "")
|
address = address.replace(" ", "")
|
||||||
address = address.split(',')
|
address = address.split(',')
|
||||||
@ -49,11 +55,11 @@ class addConfiguration:
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
return {"status": False, "reason": str(e)}
|
return {"status": False, "reason": str(e)}
|
||||||
if amount >= 1:
|
if amount >= 1:
|
||||||
return {"status": True, "reason":"", "data":f"Total of {amount} IPs"}
|
return {"status": True, "reason": "", "data": f"Total of {amount} IPs"}
|
||||||
else:
|
else:
|
||||||
return {"status": True, "reason":"", "data":f"0 available IPs"}
|
return {"status": True, "reason": "", "data": f"0 available IPs"}
|
||||||
|
|
||||||
def PortCheck(data, configs):
|
def PortCheck(self, data, configs):
|
||||||
port = data['port']
|
port = data['port']
|
||||||
if (not port.isdigit()) or int(port) < 1 or int(port) > 65535:
|
if (not port.isdigit()) or int(port) < 1 or int(port) > 65535:
|
||||||
return {"status": False, "reason": f"Invalid port."}
|
return {"status": False, "reason": f"Invalid port."}
|
||||||
@ -61,20 +67,28 @@ class addConfiguration:
|
|||||||
if i['port'] == port:
|
if i['port'] == port:
|
||||||
return {"status": False, "reason": f"{port} used by {i['conf']}."}
|
return {"status": False, "reason": f"{port} used by {i['conf']}."}
|
||||||
return good
|
return good
|
||||||
|
|
||||||
def NameCheck(data, configs):
|
def NameCheck(self, data, configs):
|
||||||
name = data['name']
|
name = data['name']
|
||||||
name = name.replace(" ", "")
|
name = name.replace(" ", "")
|
||||||
for i in configs:
|
for i in configs:
|
||||||
if name == i['conf']:
|
if name == i['conf']:
|
||||||
return {"status": False, "reason":f"{name} already existed."}
|
return {"status": False, "reason": f"{name} already existed."}
|
||||||
|
illegal_filename = ["(Space)", " ", ".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2",
|
||||||
|
"com3",
|
||||||
|
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
||||||
|
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
||||||
|
for i in illegal_filename:
|
||||||
|
name = name.replace(i, "")
|
||||||
|
if len(name) == 0:
|
||||||
|
return {"status": False, "reason": "Invalid name."}
|
||||||
return good
|
return good
|
||||||
|
|
||||||
def addConfiguration(data, configs, WG_CONF_PATH):
|
def addConfiguration(self, data, configs, WG_CONF_PATH):
|
||||||
output = ["[Interface]", "SaveConfig = true"]
|
output = ["[Interface]", "SaveConfig = true"]
|
||||||
required = ['addConfigurationPrivateKey', 'addConfigurationListenPort',
|
required = ['addConfigurationPrivateKey', 'addConfigurationListenPort',
|
||||||
'addConfigurationAddress', 'addConfigurationPreUp', 'addConfigurationPreDown',
|
'addConfigurationAddress', 'addConfigurationPreUp', 'addConfigurationPreDown',
|
||||||
'addConfigurationPostUp', 'addConfigurationPostDown']
|
'addConfigurationPostUp', 'addConfigurationPostDown']
|
||||||
for i in required:
|
for i in required:
|
||||||
e = data[i]
|
e = data[i]
|
||||||
if len(e) != 0:
|
if len(e) != 0:
|
||||||
@ -82,14 +96,42 @@ class addConfiguration:
|
|||||||
o = f"{key} = {e}"
|
o = f"{key} = {e}"
|
||||||
output.append(o)
|
output.append(o)
|
||||||
name = data['addConfigurationName']
|
name = data['addConfigurationName']
|
||||||
illegal_filename = [" ",".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3",
|
illegal_filename = ["(Space)", " ", ".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2",
|
||||||
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
"com3",
|
||||||
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
||||||
|
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
||||||
for i in illegal_filename:
|
for i in illegal_filename:
|
||||||
name = name.replace(i, "")
|
name = name.replace(i, "")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
newFile = open(f"{WG_CONF_PATH}/{name}.conf", "w+")
|
newFile = open(f"{WG_CONF_PATH}/{name}.conf", "w+")
|
||||||
newFile.write("\n".join(output))
|
newFile.write("\n".join(output))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"status": False, "reason":str(e)}
|
return {"status": False, "reason": str(e)}
|
||||||
return {"status": True, "reason":"", "data": name}
|
return {"status": True, "reason": "", "data": name}
|
||||||
|
|
||||||
|
def deleteConfiguration(self, data, config, g, WG_CONF_PATH):
|
||||||
|
confs = []
|
||||||
|
for i in config:
|
||||||
|
confs.append(i['conf'])
|
||||||
|
print(confs)
|
||||||
|
if data['name'] not in confs:
|
||||||
|
return {"status": False, "reason": "Configuration does not exist", "data": ""}
|
||||||
|
for i in config:
|
||||||
|
if i['conf'] == data['name']:
|
||||||
|
if i['status'] == "running":
|
||||||
|
try:
|
||||||
|
subprocess.check_output("wg-quick down " + data['name'], shell=True, stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
return {"status": False, "reason": "Can't stop peer", "data": str(exc.output.strip().decode("utf-8"))}
|
||||||
|
|
||||||
|
g.cur.execute(f'DROP TABLE {data["name"]}')
|
||||||
|
g.cur.execute(f'DROP TABLE {data["name"]}_restrict_access')
|
||||||
|
g.db.commit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(f'{WG_CONF_PATH}/{data["name"]}.conf')
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": False, "reason": "Can't delete peer", "data": str(e)}
|
||||||
|
|
||||||
|
return good
|
@ -1011,7 +1011,7 @@ def configuration(config_name):
|
|||||||
conf_data['checked'] = "checked"
|
conf_data['checked'] = "checked"
|
||||||
config_list = get_conf_list()
|
config_list = get_conf_list()
|
||||||
if config_name not in [conf['conf'] for conf in config_list]:
|
if config_name not in [conf['conf'] for conf in config_list]:
|
||||||
return render_template('index.html', conf=get_conf_list())
|
return redirect('/')
|
||||||
|
|
||||||
refresh_interval = int(config.get("Server", "dashboard_refresh_interval"))
|
refresh_interval = int(config.get("Server", "dashboard_refresh_interval"))
|
||||||
dns_address = config.get("Peers", "peer_global_DNS")
|
dns_address = config.get("Peers", "peer_global_DNS")
|
||||||
@ -1110,14 +1110,14 @@ def switch(config_name):
|
|||||||
shell=True, stderr=subprocess.STDOUT)
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||||
return jsonify({"status": False, "reason":"Can't stop peer", "message": str(exc.output.strip().decode("utf-8"))})
|
return jsonify({"status": False, "reason":"Can't stop configuration", "message": str(exc.output.strip().decode("utf-8"))})
|
||||||
elif status == "stopped":
|
elif status == "stopped":
|
||||||
try:
|
try:
|
||||||
subprocess.check_output("wg-quick up " + config_name,
|
subprocess.check_output("wg-quick up " + config_name,
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||||
return jsonify({"status": False, "reason":"Can't turn on peer", "message": str(exc.output.strip().decode("utf-8"))})
|
return jsonify({"status": False, "reason":"Can't turn on configuration", "message": str(exc.output.strip().decode("utf-8"))})
|
||||||
return jsonify({"status": True, "reason":""})
|
return jsonify({"status": True, "reason":""})
|
||||||
|
|
||||||
@app.route('/add_peer_bulk/<config_name>', methods=['POST'])
|
@app.route('/add_peer_bulk/<config_name>', methods=['POST'])
|
||||||
@ -1556,7 +1556,7 @@ def addConfigurationAddressCheck():
|
|||||||
returnData = {"status": True, "reason": ""}
|
returnData = {"status": True, "reason": ""}
|
||||||
required = ['address']
|
required = ['address']
|
||||||
if checkJSONAllParameter(required, data):
|
if checkJSONAllParameter(required, data):
|
||||||
returnData = api.addConfiguration.AddressCheck(data)
|
returnData = api.addConfiguration.AddressCheck(api.addConfiguration, data)
|
||||||
else:
|
else:
|
||||||
return jsonify(api.notEnoughParameter)
|
return jsonify(api.notEnoughParameter)
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
@ -1567,7 +1567,7 @@ def addConfigurationPortCheck():
|
|||||||
returnData = {"status": True, "reason": ""}
|
returnData = {"status": True, "reason": ""}
|
||||||
required = ['port']
|
required = ['port']
|
||||||
if checkJSONAllParameter(required, data):
|
if checkJSONAllParameter(required, data):
|
||||||
returnData = api.addConfiguration.PortCheck(data, get_conf_list())
|
returnData = api.addConfiguration.PortCheck(api.addConfiguration, data, get_conf_list())
|
||||||
else:
|
else:
|
||||||
return jsonify(api.notEnoughParameter)
|
return jsonify(api.notEnoughParameter)
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
@ -1578,7 +1578,7 @@ def addConfigurationNameCheck():
|
|||||||
returnData = {"status": True, "reason": ""}
|
returnData = {"status": True, "reason": ""}
|
||||||
required = ['name']
|
required = ['name']
|
||||||
if checkJSONAllParameter(required, data):
|
if checkJSONAllParameter(required, data):
|
||||||
returnData = api.addConfiguration.NameCheck(data, get_conf_list())
|
returnData = api.addConfiguration.NameCheck(api.addConfiguration, data, get_conf_list())
|
||||||
else:
|
else:
|
||||||
return jsonify(api.notEnoughParameter)
|
return jsonify(api.notEnoughParameter)
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
@ -1597,11 +1597,36 @@ def addConfiguration():
|
|||||||
for i in required:
|
for i in required:
|
||||||
if i not in data.keys():
|
if i not in data.keys():
|
||||||
return jsonify(api.notEnoughParameter)
|
return jsonify(api.notEnoughParameter)
|
||||||
|
config = get_conf_list()
|
||||||
|
nameCheck = api.addConfiguration.NameCheck(api.addConfiguration, {"name": data['addConfigurationName']}, config)
|
||||||
|
if not nameCheck['status']:
|
||||||
|
return nameCheck
|
||||||
|
|
||||||
returnData = api.addConfiguration.addConfiguration(data, get_conf_list(), WG_CONF_PATH)
|
portCheck = api.addConfiguration.PortCheck(api.addConfiguration, {"port": data['addConfigurationListenPort']}, config)
|
||||||
|
if not portCheck['status']:
|
||||||
|
return portCheck
|
||||||
|
|
||||||
|
addressCheck = api.addConfiguration.AddressCheck(api.addConfiguration, {"address": data['addConfigurationAddress']})
|
||||||
|
if not addressCheck['status']:
|
||||||
|
return addressCheck
|
||||||
|
|
||||||
|
returnData = api.addConfiguration.addConfiguration(api.addConfiguration, data, config, WG_CONF_PATH)
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/deleteConfiguration', methods=['POST'])
|
||||||
|
def deleteConfiguration():
|
||||||
|
data = request.get_json()
|
||||||
|
returnData = {"status": True, "reason": "", "data":""}
|
||||||
|
required = ['name']
|
||||||
|
if not checkJSONAllParameter(required, data):
|
||||||
|
return jsonify(api.notEnoughParameter)
|
||||||
|
|
||||||
|
returnData = api.addConfiguration.deleteConfiguration(api.addConfiguration, data, get_conf_list(), g, WG_CONF_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return returnData
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Dashboard Tools Related
|
Dashboard Tools Related
|
||||||
|
@ -272,7 +272,6 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.index-switch {
|
.index-switch {
|
||||||
text-align: right;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -671,7 +670,7 @@ pre.index-alert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#switch{
|
#switch{
|
||||||
transition: all 350ms ease-in;
|
transition: all 200ms ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle--switch{
|
.toggle--switch{
|
||||||
@ -686,7 +685,7 @@ pre.index-alert {
|
|||||||
position: relative;
|
position: relative;
|
||||||
border: 2px solid #6c757d8c;
|
border: 2px solid #6c757d8c;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
transition: all 350ms ease-in;
|
transition: all 200ms ease-in;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@ -706,10 +705,15 @@ pre.index-alert {
|
|||||||
animation-name: off;
|
animation-name: off;
|
||||||
animation-duration: 350ms;
|
animation-duration: 350ms;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
transition: all 350ms ease-in;
|
transition: all 200ms ease-in;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggleLabel:hover::before{
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.toggle--switch:checked + .toggleLabel{
|
.toggle--switch:checked + .toggleLabel{
|
||||||
background-color: #007bff17 !important;
|
background-color: #007bff17 !important;
|
||||||
border: 2px solid #007bff8c;
|
border: 2px solid #007bff8c;
|
||||||
@ -787,4 +791,12 @@ pre.index-alert {
|
|||||||
#reGeneratePrivateKey{
|
#reGeneratePrivateKey{
|
||||||
border-top-right-radius: 10px;
|
border-top-right-radius: 10px;
|
||||||
border-bottom-right-radius: 10px;
|
border-bottom-right-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.addConfigurationToggleStatus.waiting{
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.conf_card .card-body .row .card-col{*/
|
||||||
|
/* margin-bottom: 0.5rem;*/
|
||||||
|
/*}*/
|
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
@ -3,7 +3,6 @@
|
|||||||
* Under Apache-2.0 License
|
* Under Apache-2.0 License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
let peers = [];
|
let peers = [];
|
||||||
(function() {
|
(function() {
|
||||||
/**
|
/**
|
||||||
@ -37,6 +36,7 @@ let peers = [];
|
|||||||
let qrcodeModal = new bootstrap.Modal(document.getElementById('qrcode_modal'), bootstrapModalConfig);
|
let qrcodeModal = new bootstrap.Modal(document.getElementById('qrcode_modal'), bootstrapModalConfig);
|
||||||
let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig);
|
let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig);
|
||||||
let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig);
|
let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig);
|
||||||
|
let configurationDeleteModal = new bootstrap.Modal(document.getElementById('configuration_delete_modal'), bootstrapModalConfig);
|
||||||
$("[data-toggle='tooltip']").tooltip();
|
$("[data-toggle='tooltip']").tooltip();
|
||||||
$("[data-toggle='popover']").popover();
|
$("[data-toggle='popover']").popover();
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ let peers = [];
|
|||||||
setActiveConfigurationName();
|
setActiveConfigurationName();
|
||||||
window.history.pushState(null, null, `/configuration/${configuration_name}`);
|
window.history.pushState(null, null, `/configuration/${configuration_name}`);
|
||||||
$("title").text(`${configuration_name} | WGDashboard`);
|
$("title").text(`${configuration_name} | WGDashboard`);
|
||||||
|
$(".index-alert").addClass("d-none").text(``);
|
||||||
totalDataUsageChartObj.data.labels = [];
|
totalDataUsageChartObj.data.labels = [];
|
||||||
totalDataUsageChartObj.data.datasets[0].data = [];
|
totalDataUsageChartObj.data.datasets[0].data = [];
|
||||||
totalDataUsageChartObj.data.datasets[1].data = [];
|
totalDataUsageChartObj.data.datasets[1].data = [];
|
||||||
@ -667,7 +667,7 @@ let peers = [];
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeAllTooltips(){
|
function removeAllTooltips(){
|
||||||
$(".tooltip").remove()
|
$(".tooltip").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAccess(peerID){
|
function toggleAccess(peerID){
|
||||||
@ -828,21 +828,30 @@ let peers = [];
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function deleteConfiguration(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
window.configurations = {
|
window.configurations = {
|
||||||
addModal: () => { return addModal; },
|
addModal: () => { return addModal; },
|
||||||
deleteBulkModal: () => { return deleteBulkModal; },
|
deleteBulkModal: () => { return deleteBulkModal; },
|
||||||
deleteModal: () => { return deleteModal; },
|
deleteModal: () => { return deleteModal; },
|
||||||
|
configurationDeleteModal: () => { return configurationDeleteModal; },
|
||||||
ipModal: () => { return ipModal; },
|
ipModal: () => { return ipModal; },
|
||||||
qrcodeModal: () => { return qrcodeModal; },
|
qrcodeModal: () => { return qrcodeModal; },
|
||||||
settingModal: () => { return settingModal; },
|
settingModal: () => { return settingModal; },
|
||||||
configurationTimeout: () => { return configuration_timeout; },
|
configurationTimeout: () => { return configuration_timeout; },
|
||||||
updateDisplayMode: () => { display_mode = window.localStorage.getItem("displayMode") },
|
updateDisplayMode: () => { display_mode = window.localStorage.getItem("displayMode"); },
|
||||||
|
removeConfigurationInterval: () => { removeConfigurationInterval(); },
|
||||||
|
|
||||||
loadPeers: (searchString) => { loadPeers(searchString); },
|
loadPeers: (searchString) => { loadPeers(searchString); },
|
||||||
addPeersByBulk: () => { addPeersByBulk(); },
|
addPeersByBulk: () => { addPeersByBulk(); },
|
||||||
deletePeers: (config, peers_ids) => { deletePeers(config, peers_ids); },
|
deletePeers: (config, peers_ids) => { deletePeers(config, peers_ids); },
|
||||||
|
deleteConfiguration: () => { deleteConfiguration() },
|
||||||
parsePeers: (response) => { parsePeers(response); },
|
parsePeers: (response) => { parsePeers(response); },
|
||||||
toggleAccess: (peerID) => { toggleAccess(peerID) },
|
toggleAccess: (peerID) => { toggleAccess(peerID); },
|
||||||
|
|
||||||
|
|
||||||
setConfigurationName: (confName) => { configuration_name = confName; },
|
setConfigurationName: (confName) => { configuration_name = confName; },
|
||||||
@ -867,6 +876,40 @@ let $body = $("body");
|
|||||||
let available_ips = [];
|
let available_ips = [];
|
||||||
let $add_peer = document.getElementById("save_peer");
|
let $add_peer = document.getElementById("save_peer");
|
||||||
|
|
||||||
|
$("#configuration_delete").on("click", function(){
|
||||||
|
window.configurations.configurationDeleteModal().toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
function ajaxPostJSON(url, data, doneFunc){
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
headers: {"Content-Type": "application/json"}
|
||||||
|
}).done(function (res) {
|
||||||
|
doneFunc(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#sure_delete_configuration").on("click", function () {
|
||||||
|
window.configurations.removeConfigurationInterval();
|
||||||
|
let ele = $(this)
|
||||||
|
ele.attr("disabled", "disabled");
|
||||||
|
function done(res){
|
||||||
|
if (res.status){
|
||||||
|
$('#configuration_delete_modal button[data-dismiss="modal"]').remove();
|
||||||
|
ele.text("Delete Successful! Redirecting in 5 seconds.");
|
||||||
|
setTimeout(function(){
|
||||||
|
window.location.replace('/');
|
||||||
|
}, 5000)
|
||||||
|
}else{
|
||||||
|
$("#remove_configuration_alert").removeClass("d-none").text(res.reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxPostJSON("/api/deleteConfiguration", {"name": window.configurations.getConfigurationName()}, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ==========
|
* ==========
|
||||||
* Add peers
|
* Add peers
|
||||||
@ -883,7 +926,8 @@ document.querySelector(".add_btn").addEventListener("click", () => {
|
|||||||
/**
|
/**
|
||||||
* When configuration switch got click
|
* When configuration switch got click
|
||||||
*/
|
*/
|
||||||
$(".toggle--switch").on("click", function(){
|
$(".toggle--switch").on("change", function(){
|
||||||
|
console.log('lol')
|
||||||
$(this).addClass("waiting").attr("disabled", "disabled");
|
$(this).addClass("waiting").attr("disabled", "disabled");
|
||||||
let id = window.configurations.getConfigurationName();
|
let id = window.configurations.getConfigurationName();
|
||||||
let status = $(this).prop("checked");
|
let status = $(this).prop("checked");
|
||||||
@ -891,22 +935,23 @@ $(".toggle--switch").on("click", function(){
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/switch/${id}`
|
url: `/switch/${id}`
|
||||||
}).done(function(res){
|
}).done(function(res){
|
||||||
console.log();
|
if (res.status){
|
||||||
if (res){
|
|
||||||
if (status){
|
if (status){
|
||||||
window.configurations.showToast(`${id} is running.`)
|
window.configurations.showToast(`${id} is running.`)
|
||||||
}else{
|
}else{
|
||||||
window.configurations.showToast(`${id} is stopped.`)
|
window.configurations.showToast(`${id} is stopped.`)
|
||||||
}
|
}
|
||||||
ele.removeClass("waiting");
|
|
||||||
ele.removeAttr("disabled");
|
|
||||||
}else{
|
}else{
|
||||||
if (status){
|
if (status){
|
||||||
$(this).prop("checked", false)
|
ele.prop("checked", false)
|
||||||
}else{
|
}else{
|
||||||
$(this).prop("checked", true)
|
ele.prop("checked", true)
|
||||||
}
|
}
|
||||||
|
window.configurations.showToast(res.reason);
|
||||||
|
$(".index-alert").removeClass("d-none").text(`Configuration toggle failed. Please check the following error message:\n${res.message}`);
|
||||||
}
|
}
|
||||||
|
ele.removeClass("waiting");
|
||||||
|
ele.removeAttr("disabled");
|
||||||
window.configurations.loadPeers($('#search_peer_textbox').val())
|
window.configurations.loadPeers($('#search_peer_textbox').val())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
51
src/static/js/configuration.min.js
vendored
51
src/static/js/configuration.min.js
vendored
File diff suppressed because one or more lines are too long
@ -15,7 +15,7 @@ addConfigurationModal.on("hidden.bs.modal", function(){
|
|||||||
$("#add_configuration_form").trigger("reset");
|
$("#add_configuration_form").trigger("reset");
|
||||||
$("#add_configuration_form input").removeClass("is-valid").removeClass("is-invalid");
|
$("#add_configuration_form input").removeClass("is-valid").removeClass("is-invalid");
|
||||||
$(".addConfigurationAvailableIPs").text("N/A");
|
$(".addConfigurationAvailableIPs").text("N/A");
|
||||||
})
|
});
|
||||||
|
|
||||||
function showToast(msg){
|
function showToast(msg){
|
||||||
$(".toastContainer").append(
|
$(".toastContainer").append(
|
||||||
@ -28,7 +28,7 @@ function showToast(msg){
|
|||||||
</div>
|
</div>
|
||||||
<div class="toast-body">${msg}</div>
|
<div class="toast-body">${msg}</div>
|
||||||
<div class="toast-progressbar"></div>
|
<div class="toast-progressbar"></div>
|
||||||
</div>` )
|
</div>` );
|
||||||
$(`#${numberToast}-toast`).toast('show');
|
$(`#${numberToast}-toast`).toast('show');
|
||||||
$(`#${numberToast}-toast .toast-body`).html(msg);
|
$(`#${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("transition", `width ${$(`#${numberToast}-toast .toast-progressbar`).parent().data('delay')}ms cubic-bezier(0, 0, 0, 0)`);
|
||||||
@ -46,7 +46,6 @@ $(".toggle--switch").on("change", function(){
|
|||||||
url: `/switch/${id}`
|
url: `/switch/${id}`
|
||||||
}).done(function(res){
|
}).done(function(res){
|
||||||
let dot = $(`div[data-conf-id="${id}"] .dot`);
|
let dot = $(`div[data-conf-id="${id}"] .dot`);
|
||||||
console.log();
|
|
||||||
if (res.status){
|
if (res.status){
|
||||||
if (status){
|
if (status){
|
||||||
dot.removeClass("dot-stopped").addClass("dot-running");
|
dot.removeClass("dot-stopped").addClass("dot-running");
|
||||||
@ -57,11 +56,7 @@ $(".toggle--switch").on("change", function(){
|
|||||||
showToast(`${id} is stopped.`);
|
showToast(`${id} is stopped.`);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
// $(".index-alert").removeClass("d-none");
|
|
||||||
// $(".index-alert-full code").text(res.message);
|
|
||||||
ele.parents().children(".card-message").html(`<pre class="index-alert">Configuration toggle failed. Please check the following error message:<br><code>${res.message}</code></pre>`)
|
ele.parents().children(".card-message").html(`<pre class="index-alert">Configuration toggle failed. Please check the following error message:<br><code>${res.message}</code></pre>`)
|
||||||
|
|
||||||
|
|
||||||
if (status){
|
if (status){
|
||||||
ele.prop("checked", false)
|
ele.prop("checked", false)
|
||||||
}else{
|
}else{
|
||||||
@ -113,6 +108,7 @@ function ajaxPostJSON(url, data, doneFunc){
|
|||||||
doneFunc(res);
|
doneFunc(res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function validInput(input){
|
function validInput(input){
|
||||||
input.removeClass("is-invalid").addClass("is-valid").removeAttr("disabled").data("checked", true);
|
input.removeClass("is-invalid").addClass("is-valid").removeAttr("disabled").data("checked", true);
|
||||||
}
|
}
|
||||||
@ -215,42 +211,40 @@ $("#addConfigurationBtn").on("click", function(){
|
|||||||
}
|
}
|
||||||
if (filled){
|
if (filled){
|
||||||
$("#addConfigurationModal .modal-footer .btn").hide();
|
$("#addConfigurationModal .modal-footer .btn").hide();
|
||||||
$(".addConfigurationStatus").removeClass("d-none").html(`<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div> Adding peers`)
|
$(".addConfigurationStatus").removeClass("d-none");
|
||||||
let data = {};
|
let data = {};
|
||||||
let q = [];
|
let q = [];
|
||||||
for (let i = 0; i < input.length; i++){
|
for (let i = 0; i < input.length; i++){
|
||||||
let $i = $(input[i]);
|
let $i = $(input[i]);
|
||||||
data[$i.attr("name")] = $i.val();
|
data[$i.attr("name")] = $i.val();
|
||||||
q.push($i.attr("name"))
|
q.push($i.attr("name"));
|
||||||
}
|
}
|
||||||
function done(res){
|
let done = (res) => {
|
||||||
let name = res.data;
|
let name = res.data;
|
||||||
|
$(".addConfigurationAddStatus").removeClass("text-primary").addClass("text-success").html(`<i class="bi bi-check-circle-fill"></i> ${name} added successfully.`);
|
||||||
if (res.status){
|
if (res.status){
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
$(".addConfigurationToggleStatus").removeClass("waiting").html(`<div class="spinner-border spinner-border-sm" role="status"></div> Toggle Configuration`)
|
||||||
$(".addConfigurationStatus").html(`<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div> Toggling ${res.data}`)
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/switch/${name}`
|
url: `/switch/${name}`
|
||||||
}).done(function(res){
|
}).done(function(res){
|
||||||
if (res.status){
|
if (res.status){
|
||||||
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-success").html(`<i class="bi bi-check-circle-fill"></i> ${name} toggled! Refresh in 5 seconds.`);
|
$(".addConfigurationToggleStatus").removeClass("text-primary").addClass("text-success").html(`<i class="bi bi-check-circle-fill"></i> Toggle Successfully. Refresh in 5 seconds.`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$(".addConfigurationStatus").text("Refeshing...")
|
$(".addConfigurationToggleStatus").text("Refeshing...")
|
||||||
location.reload();
|
location.reload();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}else{
|
}else{
|
||||||
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} toggle failed.`)
|
$(".addConfigurationToggleStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} toggle failed.`)
|
||||||
$("#addCconfigurationAlert").removeClass("d-none").children(".alert-body").text(res.reason);
|
$("#addCconfigurationAlertMessage").removeClass("d-none").html(`${name} toggle failed. Please check the following error message:<br>${res.message}`);
|
||||||
$("#addCconfigurationAlertMessage").removeClass("d-none").text(res.message);
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} adding failed.`)
|
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} adding failed.`)
|
||||||
$("#addCconfigurationAlert").removeClass("d-none").children(".alert-body").text(res.reason);
|
$("#addCconfigurationAlert").removeClass("d-none").children(".alert-body").text(res.reason);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
ajaxPostJSON("/api/addConfiguration", data, done);
|
ajaxPostJSON("/api/addConfiguration", data, done);
|
||||||
}
|
}
|
||||||
});
|
});
|
10
src/static/js/index.min.js
vendored
Normal file
10
src/static/js/index.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -19,7 +19,9 @@
|
|||||||
<div id="config_body">
|
<div id="config_body">
|
||||||
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4 mb-4">
|
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4 mb-4">
|
||||||
<div class="info mt-4">
|
<div class="info mt-4">
|
||||||
<div id="config_info_alert"></div>
|
<div>
|
||||||
|
<pre class="index-alert d-none" style="margin-bottom: 1rem;"></pre>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<small class="text-muted"><strong>CONFIGURATION</strong></small>
|
<small class="text-muted"><strong>CONFIGURATION</strong></small>
|
||||||
@ -29,8 +31,8 @@
|
|||||||
<small class="text-muted"><strong>SWITCH</strong></small><br>
|
<small class="text-muted"><strong>SWITCH</strong></small><br>
|
||||||
<!-- <div id="conf_status_btn" class="info_loading"></div> -->
|
<!-- <div id="conf_status_btn" class="info_loading"></div> -->
|
||||||
<div id="switch" class="info_loading">
|
<div id="switch" class="info_loading">
|
||||||
<input type="checkbox" class="toggle--switch" id="switch">
|
<input type="checkbox" class="toggle--switch" id="toggle--switch">
|
||||||
<label for="switch" class="toggleLabel"></label>
|
<label for="toggle--switch" class="toggleLabel"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-100"></div>
|
<div class="w-100"></div>
|
||||||
@ -142,9 +144,11 @@
|
|||||||
<button type="button" class="btn btn-primary add_btn"><i class="bi bi-plus-circle-fill" style=""></i></button>
|
<button type="button" class="btn btn-primary add_btn"><i class="bi bi-plus-circle-fill" style=""></i></button>
|
||||||
<button type="button" class="btn btn-secondary setting_btn"><i class="bi bi-three-dots"></i></button>
|
<button type="button" class="btn btn-secondary setting_btn"><i class="bi bi-three-dots"></i></button>
|
||||||
<div class="setting_btn_menu">
|
<div class="setting_btn_menu">
|
||||||
<a class="text-primary" id="configuration_setting"><i class="bi bi-gear-fill"></i> Configration Settings</a>
|
|
||||||
<a class="text-danger" id="delete_peers_by_bulk_btn"><i class="bi bi-trash-fill"></i> Delete Peers</a>
|
<a class="text-danger" id="delete_peers_by_bulk_btn"><i class="bi bi-trash-fill"></i> Delete Peers</a>
|
||||||
<a class="text-info" id="download_all_peers" data-url="/download_all/{{conf_data['name']}}"><i class="bi bi-cloud-download-fill"></i> Download All Peers</a>
|
<a class="text-info" id="download_all_peers" data-url="/download_all/{{conf_data['name']}}"><i class="bi bi-cloud-download-fill"></i> Download All Peers</a>
|
||||||
|
<hr>
|
||||||
|
<a class="text-primary" id="configuration_setting"><i class="bi bi-gear-fill"></i> Configration Settings</a>
|
||||||
|
<a class="text-danger" id="configuration_delete"><i class="bi bi-trash3-fill"></i> Delete Configuration</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -262,6 +266,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal fade" id="configuration_delete_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
|
||||||
|
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="staticBackdropLabel">Are you sure to delete this configuration?</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="remove_configuration_alert" class="alert alert-danger alert-dismissible fade show d-none" role="alert">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<p style="margin: 0">This action is not reversible. The configuration will get toggle off, and delete from database and from the configuration folder.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">No</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="sure_delete_configuration">Yes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="modal fade" id="delete_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
|
<div class="modal fade" id="delete_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
|
||||||
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
@ -426,18 +453,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="position-fixed top-0 right-0 p-3 toastContainer" style="z-index: 5; right: 0; top: 50px;">
|
<div class="position-fixed top-0 right-0 p-3 toastContainer" style="z-index: 5; right: 0; top: 50px;"></div>
|
||||||
<!-- <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">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="toast-body">
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
{% include "tools.html" %}
|
{% include "tools.html" %}
|
||||||
</body>
|
</body>
|
||||||
{% include "footer.html" %}
|
{% include "footer.html" %}
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
{% if conf == [] %}
|
{% 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>
|
<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 %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% for i in conf%}
|
{% for i in conf%}
|
||||||
<div class="card mt-3 conf_card" data-conf-id="{{i['conf']}}">
|
<div class="card mt-3 conf_card" data-conf-id="{{i['conf']}}">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-message"></div>
|
<div class="card-message"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</main>
|
</main>
|
||||||
@ -77,9 +77,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="addCconfigurationAlert" class="alert alert-danger alert-dismissible fade show d-none" role="alert">
|
<div id="addCconfigurationAlert" class="alert alert-danger alert-dismissible fade show d-none" role="alert">
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
<div class="alert-body"></div>
|
<div class="alert-body"></div>
|
||||||
</div>
|
</div>
|
||||||
<pre id="addCconfigurationAlertMessage" class="index-alert d-none"></pre>
|
<pre id="addCconfigurationAlertMessage" class="index-alert d-none"></pre>
|
||||||
@ -152,7 +149,13 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" id="addConfigurationBtn">Add</button>
|
<button type="button" class="btn btn-primary" id="addConfigurationBtn">Add</button>
|
||||||
<p class="text-primary addConfigurationStatus d-none"></p>
|
<div class="text-primary addConfigurationStatus addConfigurationAddStatus d-none">
|
||||||
|
<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>
|
||||||
|
Add Configuration
|
||||||
|
</div>
|
||||||
|
<div class="text-primary addConfigurationStatus addConfigurationToggleStatus d-none waiting">
|
||||||
|
<i class="bi bi-circle"></i> Toggle Configuration
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -162,4 +165,5 @@
|
|||||||
{% include "footer.html" %}
|
{% include "footer.html" %}
|
||||||
<script src="{{ url_for('static',filename='js/wireguard.min.js') }}"></script>
|
<script src="{{ url_for('static',filename='js/wireguard.min.js') }}"></script>
|
||||||
<script src="{{ url_for('static',filename='js/index.js') }}"></script>
|
<script src="{{ url_for('static',filename='js/index.js') }}"></script>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -106,7 +106,7 @@ def checkJSONAllParameter(required, data):
|
|||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
return False
|
return False
|
||||||
for i in required:
|
for i in required:
|
||||||
if i not in list(data.keys()):
|
if i not in list(data.keys()) or len(data[i]) == 0:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user