1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 07:10:09 +01:00

Rename configuration done

This commit is contained in:
Donald Zou 2024-11-06 18:36:55 +08:00
parent 3bc54a4e16
commit 4956b0d89d
4 changed files with 308 additions and 165 deletions

View File

@ -1,5 +1,4 @@
import itertools import itertools, random
import random
import shutil import shutil
import sqlite3 import sqlite3
import configparser import configparser
@ -7,7 +6,6 @@ import hashlib
import ipaddress import ipaddress
import json import json
import traceback import traceback
# Python Built-in Library
import os import os
import secrets import secrets
import subprocess import subprocess
@ -17,45 +15,30 @@ import urllib.error
import uuid import uuid
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any from typing import Any
import bcrypt import bcrypt
# PIP installed library
import ifcfg import ifcfg
import psutil import psutil
import pyotp import pyotp
from flask import Flask, request, render_template, session, g from flask import Flask, request, render_template, session, g
from json import JSONEncoder from json import JSONEncoder
from flask_cors import CORS from flask_cors import CORS
from icmplib import ping, traceroute from icmplib import ping, traceroute
# Import other python files
import threading import threading
from flask.json.provider import DefaultJSONProvider from flask.json.provider import DefaultJSONProvider
DASHBOARD_VERSION = 'v4.1' DASHBOARD_VERSION = 'v4.1'
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.') CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
DB_PATH = os.path.join(CONFIGURATION_PATH, 'db') DB_PATH = os.path.join(CONFIGURATION_PATH, 'db')
if not os.path.isdir(DB_PATH): if not os.path.isdir(DB_PATH):
os.mkdir(DB_PATH) os.mkdir(DB_PATH)
DASHBOARD_CONF = os.path.join(CONFIGURATION_PATH, 'wg-dashboard.ini') DASHBOARD_CONF = os.path.join(CONFIGURATION_PATH, 'wg-dashboard.ini')
# WireGuard's configuration path
WG_CONF_PATH = None WG_CONF_PATH = None
# Dashboard Config Name
# Upgrade Required
UPDATE = None UPDATE = None
# Flask App Configuration
app = Flask("WGDashboard") app = Flask("WGDashboard")
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
app.secret_key = secrets.token_urlsafe(32) app.secret_key = secrets.token_urlsafe(32)
class ModelEncoder(JSONEncoder): class ModelEncoder(JSONEncoder):
def default(self, o: Any) -> Any: def default(self, o: Any) -> Any:
if hasattr(o, 'toJson'): if hasattr(o, 'toJson'):
@ -63,12 +46,10 @@ class ModelEncoder(JSONEncoder):
else: else:
return super(ModelEncoder, self).default(o) return super(ModelEncoder, self).default(o)
''' '''
Classes Classes
''' '''
def ResponseObject(status=True, message=None, data=None) -> Flask.response_class: def ResponseObject(status=True, message=None, data=None) -> Flask.response_class:
response = Flask.make_response(app, { response = Flask.make_response(app, {
"status": status, "status": status,
@ -326,6 +307,19 @@ class PeerJobs:
except Exception as e: except Exception as e:
return False, str(e) return False, str(e)
def updateJobConfigurationName(self, ConfigurationName: str, NewConfigurationName: str) -> tuple[bool, str]:
try:
with self.jobdb:
jobdbCursor = self.jobdb.cursor()
jobdbCursor.execute('''
UPDATE PeerJobs SET Configuration = ? WHERE Configuration = ?
''', (NewConfigurationName, ConfigurationName, ))
self.jobdb.commit()
self.__getJobs()
except Exception as e:
return False, str(e)
def runJob(self): def runJob(self):
needToDelete = [] needToDelete = []
for job in self.Jobs: for job in self.Jobs:
@ -357,6 +351,10 @@ class PeerJobs:
JobLogger.log(job.JobID, s["status"], JobLogger.log(job.JobID, s["status"],
f"Peer {fp.id} from {c.Name} failed {job.Action}ed." f"Peer {fp.id} from {c.Name} failed {job.Action}ed."
) )
else:
needToDelete.append(job)
else:
needToDelete.append(job)
for j in needToDelete: for j in needToDelete:
self.deleteJob(j) self.deleteJob(j)
@ -540,10 +538,13 @@ class WireguardConfiguration:
existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall() existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall()
def __createDatabase(self): def __createDatabase(self, dbName = None):
if dbName is None:
dbName = self.Name
existingTables = sqlSelect("SELECT name FROM sqlite_master WHERE type='table'").fetchall() existingTables = sqlSelect("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
existingTables = [t['name'] for t in existingTables] existingTables = [t['name'] for t in existingTables]
if self.Name not in existingTables: if dbName not in existingTables:
sqlUpdate( sqlUpdate(
""" """
CREATE TABLE '%s'( CREATE TABLE '%s'(
@ -555,10 +556,10 @@ class WireguardConfiguration:
keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL, keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) )
""" % self.Name """ % dbName
) )
if f'{self.Name}_restrict_access' not in existingTables: if f'{dbName}_restrict_access' not in existingTables:
sqlUpdate( sqlUpdate(
""" """
CREATE TABLE '%s_restrict_access' ( CREATE TABLE '%s_restrict_access' (
@ -570,9 +571,9 @@ class WireguardConfiguration:
keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL, keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) )
""" % self.Name """ % dbName
) )
if f'{self.Name}_transfer' not in existingTables: if f'{dbName}_transfer' not in existingTables:
sqlUpdate( sqlUpdate(
""" """
CREATE TABLE '%s_transfer' ( CREATE TABLE '%s_transfer' (
@ -580,9 +581,9 @@ class WireguardConfiguration:
total_sent FLOAT NULL, total_data FLOAT NULL, total_sent FLOAT NULL, total_data FLOAT NULL,
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, time DATETIME cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, time DATETIME
) )
""" % self.Name """ % dbName
) )
if f'{self.Name}_deleted' not in existingTables: if f'{dbName}_deleted' not in existingTables:
sqlUpdate( sqlUpdate(
""" """
CREATE TABLE '%s_deleted' ( CREATE TABLE '%s_deleted' (
@ -594,7 +595,7 @@ class WireguardConfiguration:
keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL, keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) )
""" % self.Name """ % dbName
) )
def __dumpDatabase(self): def __dumpDatabase(self):
@ -976,7 +977,7 @@ class WireguardConfiguration:
os.mkdir(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup')) os.mkdir(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup'))
time = datetime.now().strftime("%Y%m%d%H%M%S") time = datetime.now().strftime("%Y%m%d%H%M%S")
shutil.copy( shutil.copy(
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], f'{self.Name}.conf'), self.__configPath,
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.conf') os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.conf')
) )
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.sql'), 'w+') as f: with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.sql'), 'w+') as f:
@ -1085,6 +1086,27 @@ class WireguardConfiguration:
self.__dropDatabase() self.__dropDatabase()
return True return True
def renameConfiguration(self, newConfigurationName) -> tuple[bool, str]:
if newConfigurationName in WireguardConfigurations.keys():
return False, "Configuration name already exist"
try:
if self.getStatus():
self.toggleConfiguration()
self.__createDatabase(newConfigurationName)
sqlUpdate(f'INSERT INTO "{newConfigurationName}" SELECT * FROM "{self.Name}"')
sqlUpdate(f'INSERT INTO "{newConfigurationName}_restrict_access" SELECT * FROM "{self.Name}_restrict_access"')
sqlUpdate(f'INSERT INTO "{newConfigurationName}_deleted" SELECT * FROM "{self.Name}_deleted"')
sqlUpdate(f'INSERT INTO "{newConfigurationName}_transfer" SELECT * FROM "{self.Name}_transfer"')
AllPeerJobs.updateJobConfigurationName(self.Name, newConfigurationName)
shutil.copy(
self.__configPath,
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], f'{newConfigurationName}.conf')
)
self.deleteConfiguration()
except Exception as e:
return False, str(e)
return True, None
class Peer: class Peer:
def __init__(self, tableData, configuration: WireguardConfiguration): def __init__(self, tableData, configuration: WireguardConfiguration):
self.configuration = configuration self.configuration = configuration
@ -1430,7 +1452,6 @@ class DashboardConfig:
the_dict[section][key] = self.GetConfig(section, key)[1] the_dict[section][key] = self.GetConfig(section, key)[1]
return the_dict return the_dict
''' '''
Private Functions Private Functions
''' '''
@ -1583,13 +1604,10 @@ cors = CORS(app, resources={rf"{APP_PREFIX}/api/*": {
"allow_headers": ["Content-Type", "wg-dashboard-apikey"] "allow_headers": ["Content-Type", "wg-dashboard-apikey"]
}}) }})
''' '''
API Routes API Routes
''' '''
@app.before_request @app.before_request
def auth_req(): def auth_req():
if request.method.lower() == 'options': if request.method.lower() == 'options':
@ -1647,7 +1665,6 @@ def auth_req():
def API_ValidateAPIKey(): def API_ValidateAPIKey():
return ResponseObject(True) return ResponseObject(True)
@app.get(f'{APP_PREFIX}/api/validateAuthentication') @app.get(f'{APP_PREFIX}/api/validateAuthentication')
def API_ValidateAuthentication(): def API_ValidateAuthentication():
token = request.cookies.get("authToken") + "" token = request.cookies.get("authToken") + ""
@ -1655,7 +1672,6 @@ def API_ValidateAuthentication():
return ResponseObject(False, "Invalid authentication.") return ResponseObject(False, "Invalid authentication.")
return ResponseObject(True) return ResponseObject(True)
@app.post(f'{APP_PREFIX}/api/authenticate') @app.post(f'{APP_PREFIX}/api/authenticate')
def API_AuthenticateLogin(): def API_AuthenticateLogin():
data = request.get_json() data = request.get_json()
@ -1691,20 +1707,17 @@ def API_AuthenticateLogin():
else: else:
return ResponseObject(False, "Sorry, your username or password is incorrect.") return ResponseObject(False, "Sorry, your username or password is incorrect.")
@app.get(f'{APP_PREFIX}/api/signout') @app.get(f'{APP_PREFIX}/api/signout')
def API_SignOut(): def API_SignOut():
resp = ResponseObject(True, "") resp = ResponseObject(True, "")
resp.delete_cookie("authToken") resp.delete_cookie("authToken")
return resp return resp
@app.route(f'{APP_PREFIX}/api/getWireguardConfigurations', methods=["GET"]) @app.route(f'{APP_PREFIX}/api/getWireguardConfigurations', methods=["GET"])
def API_getWireguardConfigurations(): def API_getWireguardConfigurations():
_getConfigurationList() _getConfigurationList()
return ResponseObject(data=[wc for wc in WireguardConfigurations.values()]) return ResponseObject(data=[wc for wc in WireguardConfigurations.values()])
@app.route(f'{APP_PREFIX}/api/addWireguardConfiguration', methods=["POST"]) @app.route(f'{APP_PREFIX}/api/addWireguardConfiguration', methods=["POST"])
def API_addWireguardConfiguration(): def API_addWireguardConfiguration():
data = request.get_json() data = request.get_json()
@ -1751,7 +1764,6 @@ def API_addWireguardConfiguration():
WireguardConfigurations[data['ConfigurationName']] = WireguardConfiguration(data=data) WireguardConfigurations[data['ConfigurationName']] = WireguardConfiguration(data=data)
return ResponseObject() return ResponseObject()
@app.get(f'{APP_PREFIX}/api/toggleWireguardConfiguration/') @app.get(f'{APP_PREFIX}/api/toggleWireguardConfiguration/')
def API_toggleWireguardConfiguration(): def API_toggleWireguardConfiguration():
configurationName = request.args.get('configurationName') configurationName = request.args.get('configurationName')
@ -1788,6 +1800,21 @@ def API_deleteWireguardConfiguration():
WireguardConfigurations.pop(data.get("Name")) WireguardConfigurations.pop(data.get("Name"))
return ResponseObject(status) return ResponseObject(status)
@app.post(f'{APP_PREFIX}/api/renameWireguardConfiguration')
def API_renameWireguardConfiguration():
data = request.get_json()
keys = ["Name", "NewConfigurationName"]
for k in keys:
if (k not in data.keys() or data.get(k) is None or len(data.get(k)) == 0 or
(k == "Name" and data.get(k) not in WireguardConfigurations.keys())):
return ResponseObject(False, "Please provide the configuration name you want to rename")
status, message = WireguardConfigurations[data.get("Name")].renameConfiguration(data.get("NewConfigurationName"))
if status:
WireguardConfigurations.pop(data.get("Name"))
WireguardConfigurations[data.get("NewConfigurationName")] = WireguardConfiguration(data.get("NewConfigurationName"))
return ResponseObject(status, message)
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurationBackup') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurationBackup')
def API_getWireguardConfigurationBackup(): def API_getWireguardConfigurationBackup():
configurationName = request.args.get('configurationName') configurationName = request.args.get('configurationName')
@ -1876,7 +1903,6 @@ def API_restoreWireguardConfigurationBackup():
def API_getDashboardConfiguration(): def API_getDashboardConfiguration():
return ResponseObject(data=DashboardConfig.toJson()) return ResponseObject(data=DashboardConfig.toJson())
@app.post(f'{APP_PREFIX}/api/updateDashboardConfigurationItem') @app.post(f'{APP_PREFIX}/api/updateDashboardConfigurationItem')
def API_updateDashboardConfigurationItem(): def API_updateDashboardConfigurationItem():
data = request.get_json() data = request.get_json()
@ -1924,7 +1950,6 @@ def API_deleteDashboardAPIKey():
return ResponseObject(True, data=DashboardConfig.DashboardAPIKeys) return ResponseObject(True, data=DashboardConfig.DashboardAPIKeys)
return ResponseObject(False, "Dashboard API Keys function is disbaled") return ResponseObject(False, "Dashboard API Keys function is disbaled")
@app.post(f'{APP_PREFIX}/api/updatePeerSettings/<configName>') @app.post(f'{APP_PREFIX}/api/updatePeerSettings/<configName>')
def API_updatePeerSettings(configName): def API_updatePeerSettings(configName):
data = request.get_json() data = request.get_json()
@ -1970,7 +1995,6 @@ def API_deletePeers(configName: str) -> ResponseObject:
return ResponseObject(False, "Configuration does not exist") return ResponseObject(False, "Configuration does not exist")
@app.post(f'{APP_PREFIX}/api/restrictPeers/<configName>') @app.post(f'{APP_PREFIX}/api/restrictPeers/<configName>')
def API_restrictPeers(configName: str) -> ResponseObject: def API_restrictPeers(configName: str) -> ResponseObject:
data = request.get_json() data = request.get_json()
@ -2139,7 +2163,6 @@ def API_addPeers(configName):
return ResponseObject(False, "Configuration does not exist") return ResponseObject(False, "Configuration does not exist")
@app.get(f"{APP_PREFIX}/api/downloadPeer/<configName>") @app.get(f"{APP_PREFIX}/api/downloadPeer/<configName>")
def API_downloadPeer(configName): def API_downloadPeer(configName):
data = request.args data = request.args
@ -2151,8 +2174,6 @@ def API_downloadPeer(configName):
return ResponseObject(False, "Peer does not exist") return ResponseObject(False, "Peer does not exist")
return ResponseObject(data=peer.downloadPeer()) return ResponseObject(data=peer.downloadPeer())
@app.get(f"{APP_PREFIX}/api/downloadAllPeers/<configName>") @app.get(f"{APP_PREFIX}/api/downloadAllPeers/<configName>")
def API_downloadAllPeers(configName): def API_downloadAllPeers(configName):
if configName not in WireguardConfigurations.keys(): if configName not in WireguardConfigurations.keys():
@ -2168,13 +2189,11 @@ def API_downloadAllPeers(configName):
peerData.append(file) peerData.append(file)
return ResponseObject(data=peerData) return ResponseObject(data=peerData)
@app.get(f"{APP_PREFIX}/api/getAvailableIPs/<configName>") @app.get(f"{APP_PREFIX}/api/getAvailableIPs/<configName>")
def API_getAvailableIPs(configName): def API_getAvailableIPs(configName):
status, ips = _getWireguardConfigurationAvailableIP(configName) status, ips = _getWireguardConfigurationAvailableIP(configName)
return ResponseObject(status=status, data=ips) return ResponseObject(status=status, data=ips)
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurationInfo') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurationInfo')
def API_getConfigurationInfo(): def API_getConfigurationInfo():
configurationName = request.args.get("configurationName") configurationName = request.args.get("configurationName")
@ -2186,7 +2205,6 @@ def API_getConfigurationInfo():
"configurationRestrictedPeers": WireguardConfigurations[configurationName].getRestrictedPeersList() "configurationRestrictedPeers": WireguardConfigurations[configurationName].getRestrictedPeersList()
}) })
@app.get(f'{APP_PREFIX}/api/getDashboardTheme') @app.get(f'{APP_PREFIX}/api/getDashboardTheme')
def API_getDashboardTheme(): def API_getDashboardTheme():
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1]) return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
@ -2245,13 +2263,10 @@ def API_getPeerScheduleJobLogs(configName):
requestAll = True requestAll = True
return ResponseObject(data=JobLogger.getLogs(requestAll, configName)) return ResponseObject(data=JobLogger.getLogs(requestAll, configName))
''' '''
Tools Tools
''' '''
@app.get(f'{APP_PREFIX}/api/ping/getAllPeersIpAddress') @app.get(f'{APP_PREFIX}/api/ping/getAllPeersIpAddress')
def API_ping_getAllPeersIpAddress(): def API_ping_getAllPeersIpAddress():
ips = {} ips = {}

View File

@ -4,6 +4,8 @@ import {onMounted, reactive, ref, useTemplateRef, watch} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js"; import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import UpdateConfigurationName
from "@/components/configurationComponents/editConfigurationComponents/updateConfigurationName.vue";
const props = defineProps({ const props = defineProps({
configurationInfo: Object configurationInfo: Object
}) })
@ -47,6 +49,8 @@ const saveForm = () => {
} }
}) })
} }
const updateConfigurationName = ref(false)
watch(data, () => { watch(data, () => {
dataChanged.value = JSON.stringify(data) !== JSON.stringify(props.configurationInfo); dataChanged.value = JSON.stringify(data) !== JSON.stringify(props.configurationInfo);
}, { }, {
@ -67,24 +71,40 @@ watch(data, () => {
</div> </div>
<div class="card-body px-4 pb-4"> <div class="card-body px-4 pb-4">
<div class="d-flex gap-2 flex-column"> <div class="d-flex gap-2 flex-column">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center gap-3" v-if="!updateConfigurationName">
<small class="text-muted"> <small class="text-muted">
<LocaleText t="Name"></LocaleText> <LocaleText t="Name"></LocaleText>
</small> </small>
<small class="ms-auto"><samp>{{data.Name}}</samp></small> <small>{{data.Name}}</small>
<button
@click="updateConfigurationName = true"
class="btn btn-sm bg-danger-subtle border-danger-subtle text-danger-emphasis rounded-3 ms-auto">
Update Name
</button>
</div> </div>
<div class="d-flex align-items-center"> <UpdateConfigurationName
<small class="text-muted"> @close="updateConfigurationName = false"
:configuration-name="data.Name"
v-if="updateConfigurationName"></UpdateConfigurationName>
<template v-else>
<hr>
<div class="d-flex align-items-center gap-3">
<small class="text-muted" style="word-break: keep-all">
<LocaleText t="Public Key"></LocaleText> <LocaleText t="Public Key"></LocaleText>
</small> </small>
<small class="ms-auto"><samp>{{data.PublicKey}}</samp></small> <small class="ms-auto" style="word-break: break-all">
{{data.PublicKey}}
</small>
</div> </div>
<hr> <hr>
<div> <div>
<label for="configuration_private_key" class="form-label d-flex"> <div class="d-flex">
<label for="configuration_private_key" class="form-label">
<small class="text-muted d-block"> <small class="text-muted d-block">
<LocaleText t="Private Key"></LocaleText> <LocaleText t="Private Key"></LocaleText>
</small> </small>
</label>
<div class="form-check form-switch ms-auto"> <div class="form-check form-switch ms-auto">
<input class="form-check-input" <input class="form-check-input"
type="checkbox" role="switch" id="editPrivateKeySwitch" type="checkbox" role="switch" id="editPrivateKeySwitch"
@ -94,7 +114,7 @@ watch(data, () => {
<small>Edit</small> <small>Edit</small>
</label> </label>
</div> </div>
</label> </div>
<input type="text" class="form-control form-control-sm rounded-3" <input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving || !editPrivateKey" :disabled="saving || !editPrivateKey"
:class="{'is-invalid': !reqField.PrivateKey}" :class="{'is-invalid': !reqField.PrivateKey}"
@ -181,6 +201,7 @@ watch(data, () => {
> >
<i class="bi bi-save-fill"></i></button> <i class="bi bi-save-fill"></i></button>
</div> </div>
</template>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,110 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
import {fetchPost} from "@/utilities/fetch.js";
import {useRouter} from "vue-router";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
const props = defineProps({
configurationName: String
})
const emit = defineEmits(['close'])
const newConfigurationName = reactive({
data: "",
valid: false
});
const store = WireguardConfigurationsStore()
onMounted(() => {
watch(() => newConfigurationName.data, (newVal) => {
newConfigurationName.valid = /^[a-zA-Z0-9_=+.-]{1,15}$/.test(newVal) && newVal.length > 0 && !store.Configurations.find(x => x.Name === newVal);
})
})
const dashboardConfigurationStore = DashboardConfigurationStore()
const loading = ref(false)
const router = useRouter()
const rename = async () => {
if (newConfigurationName.data){
loading.value = true
clearInterval(dashboardConfigurationStore.Peers.RefreshInterval)
await fetchPost("/api/renameWireguardConfiguration", {
Name: props.configurationName,
NewConfigurationName: newConfigurationName.data
}, async (res) => {
if (res.status){
await store.getConfigurations()
dashboardConfigurationStore.newMessage("Server", "Configuration renamed", "success")
router.push(`/configuration/${newConfigurationName.data}/peers`)
}else{
dashboardConfigurationStore.newMessage("Server", res.message, "danger")
loading.value = false
}
})
}
}
</script>
<template>
<div class="card rounded-3 flex-grow-1 bg-danger-subtle border-danger-subtle border shadow">
<div class="card-body">
<p>
<LocaleText t="To update this configuration's name, WGDashboard will execute the following operations:"></LocaleText>
</p>
<ol>
<li>
<LocaleText t="Duplicate current configuration's database table and .conf file with the new name"></LocaleText>
</li>
<li>
<LocaleText t="Delete current configuration's database table and .conf file"></LocaleText>
</li>
</ol>
<div class="d-flex align-items-center gap-3 inputGroup">
<input class="form-control form-control-sm rounded-3" :value="configurationName" disabled>
<h3 class="mb-0">
<i class="bi bi-arrow-right"></i>
</h3>
<input class="form-control form-control-sm rounded-3"
id="newConfigurationName"
:class="[newConfigurationName.data ? (newConfigurationName.valid ? 'is-valid' : 'is-invalid') : '']"
v-model="newConfigurationName.data">
</div>
<div class="invalid-feedback" :class="{'d-block': !newConfigurationName.valid && newConfigurationName.data}">
<LocaleText t="Configuration name is invalid. Possible reasons:"></LocaleText>
<ul class="mb-0">
<li>
<LocaleText t="Configuration name already exist."></LocaleText>
</li>
<li>
<LocaleText t="Configuration name can only contain 15 lower/uppercase alphabet, numbers, underscore, equal sign, plus sign, period and hyphen."></LocaleText>
</li>
</ul>
</div>
<div class="d-flex mt-3">
<button
@click="emit('close')"
class="btn btn-sm bg-secondary-subtle border-secondary-subtle text-secondary-emphasis rounded-3">
<LocaleText t="Cancel"></LocaleText>
</button>
<button
@click="rename()"
:disabled="!newConfigurationName.data || loading"
class="btn btn-sm btn-danger rounded-3 ms-auto">
<LocaleText t="Save"></LocaleText>
</button>
</div>
</div>
</div>
</template>
<style scoped>
@media screen and (max-width: 567px) {
.inputGroup{
flex-direction: column;
h3{
transform: rotate(90deg);
}
}
}
</style>

View File

@ -165,7 +165,6 @@ export default {
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -199,9 +198,7 @@ export default {
v-model="this.newConfiguration.PublicKey" disabled v-model="this.newConfiguration.PublicKey" disabled
> >
</div> </div>
</div> </div>
</div> </div>
<div class="card rounded-3 shadow"> <div class="card rounded-3 shadow">
<div class="card-header"> <div class="card-header">