Finished client deletion

This commit is contained in:
Donald Zou 2025-08-11 17:29:15 +08:00
parent 9424ad1f13
commit 48d9800b71
9 changed files with 338 additions and 64 deletions

View File

@ -18,13 +18,7 @@ def ResponseObject(status=True, message=None, data=None, status_code = 200) -> F
response.content_type = "application/json" response.content_type = "application/json"
return response return response
def login_required(f):
@wraps(f)
def func(*args, **kwargs):
if session.get("Email") is None or session.get("TotpVerified") is None or not session.get("TotpVerified") or session.get("Role") != "client":
return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
return f(*args, **kwargs)
return func
from modules.DashboardClients import DashboardClients from modules.DashboardClients import DashboardClients
def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], dashboardConfig: DashboardConfig, dashboardClients: DashboardClients): def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], dashboardConfig: DashboardConfig, dashboardClients: DashboardClients):
@ -32,6 +26,18 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
client = Blueprint('client', __name__, template_folder=os.path.abspath("./static/client/dist")) client = Blueprint('client', __name__, template_folder=os.path.abspath("./static/client/dist"))
prefix = f'{dashboardConfig.GetConfig("Server", "app_prefix")[1]}/client' prefix = f'{dashboardConfig.GetConfig("Server", "app_prefix")[1]}/client'
def login_required(f):
@wraps(f)
def func(*args, **kwargs):
if session.get("Email") is None or session.get("TotpVerified") is None or not session.get("TotpVerified") or session.get("Role") != "client":
return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
if not dashboardClients.GetClient(session.get("ClientID")):
session.clear()
return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
return f(*args, **kwargs)
return func
@client.before_request @client.before_request
def clientBeforeRequest(): def clientBeforeRequest():
@ -107,9 +113,11 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
if session.get('Email') is None: if session.get('Email') is None:
return ResponseObject(False, "Sign in status is invalid", status_code=401) return ResponseObject(False, "Sign in status is invalid", status_code=401)
session['TotpVerified'] = True session['TotpVerified'] = True
profile = dashboardClients.GetClientProfile(session.get("ClientID"))
return ResponseObject(True, data={ return ResponseObject(True, data={
"Email": session.get('Email'), "Email": session.get('Email'),
"Profile": dashboardClients.GetClientProfile(session.get("ClientID")) "Profile": profile
}) })
return ResponseObject(status, msg) return ResponseObject(status, msg)
@ -145,7 +153,7 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
@client.post(f'{prefix}/api/settings/updatePassword') @client.post(f'{prefix}/api/settings/updatePassword')
@login_required @login_required
def ClientAPI_Settings_UpdatePassword(): def ClientAPI_Settings_UpdatePassword():
data = request.json data = request.get_json()
status, message = dashboardClients.UpdateClientPassword(session['Email'], **data) status, message = dashboardClients.UpdateClientPassword(session['Email'], **data)
return ResponseObject(status, message) return ResponseObject(status, message)

View File

@ -1263,6 +1263,8 @@ def API_Clients_AssignClient():
client = data.get('ClientID') client = data.get('ClientID')
if not all([configurationName, id, client]): if not all([configurationName, id, client]):
return ResponseObject(False, "Please provide all required fields") return ResponseObject(False, "Please provide all required fields")
if not DashboardClients.GetClient(client):
return ResponseObject(False, "Client does not exist")
status, data = DashboardClients.AssignClient(configurationName, id, client) status, data = DashboardClients.AssignClient(configurationName, id, client)
if not status: if not status:
@ -1307,7 +1309,8 @@ def API_Clients_AssignedPeers():
clientId = data.get("ClientID") clientId = data.get("ClientID")
if not clientId: if not clientId:
return ResponseObject(False, "Please provide ClientID") return ResponseObject(False, "Please provide ClientID")
if not DashboardClients.GetClient(clientId):
return ResponseObject(False, "Client does not exist")
d = DashboardClients.GetClientAssignedPeersGrouped(clientId) d = DashboardClients.GetClientAssignedPeersGrouped(clientId)
if d is None: if d is None:
return ResponseObject(False, "Client does not exist") return ResponseObject(False, "Client does not exist")
@ -1319,6 +1322,8 @@ def API_Clients_GeneratePasswordResetLink():
clientId = data.get("ClientID") clientId = data.get("ClientID")
if not clientId: if not clientId:
return ResponseObject(False, "Please provide ClientID") return ResponseObject(False, "Please provide ClientID")
if not DashboardClients.GetClient(clientId):
return ResponseObject(False, "Client does not exist")
token = DashboardClients.GenerateClientPasswordResetLink(clientId) token = DashboardClients.GenerateClientPasswordResetLink(clientId)
if token: if token:
@ -1331,8 +1336,22 @@ def API_Clients_UpdateProfile():
clientId = data.get("ClientID") clientId = data.get("ClientID")
if not clientId: if not clientId:
return ResponseObject(False, "Please provide ClientID") return ResponseObject(False, "Please provide ClientID")
if not DashboardClients.GetClient(clientId):
return ResponseObject(False, "Client does not exist")
value = data.get('Name') value = data.get('Name')
return ResponseObject(status=DashboardClients.UpdateClientProfile(clientId, value)) return ResponseObject(status=DashboardClients.UpdateClientProfile(clientId, value))
@app.post(f'{APP_PREFIX}/api/clients/deleteClient')
def API_Clients_DeleteClient():
data = request.get_json()
clientId = data.get("ClientID")
if not clientId:
return ResponseObject(False, "Please provide ClientID")
if not DashboardClients.GetClient(clientId):
return ResponseObject(False, "Client does not exist")
return ResponseObject(status=DashboardClients.DeleteClient(clientId))
''' '''
Index Page Index Page
''' '''

View File

@ -189,6 +189,7 @@ class DashboardClients:
}) })
) )
self.logger.log(Message=f"User {data.get('email', '')} from {data.get('iss', '')} signed up") self.logger.log(Message=f"User {data.get('email', '')} from {data.get('iss', '')} signed up")
self.__getClients()
return True, newClientUUID return True, newClientUUID
return False, "User already signed up" return False, "User already signed up"
@ -294,6 +295,7 @@ class DashboardClients:
}) })
) )
self.logger.log(Message=f"User {Email} signed up") self.logger.log(Message=f"User {Email} signed up")
self.__getClients()
except Exception as e: except Exception as e:
self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}") self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}")
return False, "Signe up failed." return False, "Signe up failed."
@ -347,6 +349,33 @@ class DashboardClients:
return False return False
return True return True
def DeleteClient(self, ClientID):
try:
with self.engine.begin() as conn:
client = self.GetClient(ClientID)
if client.get("ClientGroup") == "Local":
conn.execute(
self.dashboardClientsTable.delete().where(
self.dashboardClientsTable.c.ClientID == ClientID
)
)
else:
conn.execute(
self.dashboardOIDCClientsTable.delete().where(
self.dashboardOIDCClientsTable.c.ClientID == ClientID
)
)
conn.execute(
self.dashboardClientsInfoTable.delete().where(
self.dashboardClientsInfoTable.c.ClientID == ClientID
)
)
self.DashboardClientsPeerAssignment.UnassignPeers(ClientID)
except Exception as e:
self.logger.log(Status="false", Message=f"Failed to delete {ClientID}")
return False
return True
''' '''
For WGDashboard Admin to Manage Clients For WGDashboard Admin to Manage Clients
''' '''

View File

@ -108,6 +108,20 @@ class DashboardClientsPeerAssignment:
self.__getAssignments() self.__getAssignments()
return True return True
def UnassignPeers(self, ClientID):
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsPeerAssignmentTable.update().values({
"UnassignedDate": datetime.datetime.now()
}).where(
db.and_(
self.dashboardClientsPeerAssignmentTable.c.ClientID == ClientID,
self.dashboardClientsPeerAssignmentTable.c.UnassignedDate.is_(db.null())
)
)
)
self.__getAssignments()
return True
def GetAssignedClients(self, ConfigurationName, PeerID) -> list[Assignment]: def GetAssignedClients(self, ConfigurationName, PeerID) -> list[Assignment]:
self.__getAssignments() self.__getAssignments()

View File

@ -8,7 +8,8 @@
"name": "app", "name": "app",
"version": "4.3", "version": "4.3",
"dependencies": { "dependencies": {
"@vue/language-server": "^3.0.3", "@volar/language-server": "2.4.23",
"@vue/language-server": "3.0.5",
"@vuepic/vue-datepicker": "^11.0.2", "@vuepic/vue-datepicker": "^11.0.2",
"@vueuse/core": "^13.5.0", "@vueuse/core": "^13.5.0",
"@vueuse/shared": "^13.5.0", "@vueuse/shared": "^13.5.0",
@ -1594,23 +1595,23 @@
} }
}, },
"node_modules/@volar/language-core": { "node_modules/@volar/language-core": {
"version": "2.4.20", "version": "2.4.23",
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz", "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.23.tgz",
"integrity": "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA==", "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/source-map": "2.4.20" "@volar/source-map": "2.4.23"
} }
}, },
"node_modules/@volar/language-server": { "node_modules/@volar/language-server": {
"version": "2.4.20", "version": "2.4.23",
"resolved": "https://registry.npmmirror.com/@volar/language-server/-/language-server-2.4.20.tgz", "resolved": "https://registry.npmmirror.com/@volar/language-server/-/language-server-2.4.23.tgz",
"integrity": "sha512-fNNFzEad0sO4pVZnpHggglbIeaKjLs4vH1JPPN+zd/4hSEI2u8+Qck10JhswCSO6xFTFbKxVquvWu2U2tT0EHQ==", "integrity": "sha512-k0iO+tybMGMMyrNdWOxgFkP0XJTdbH0w+WZlM54RzJU3WZSjHEupwL30klpM7ep4FO6qyQa03h+VcGHD4Q8gEg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-core": "2.4.20", "@volar/language-core": "2.4.23",
"@volar/language-service": "2.4.20", "@volar/language-service": "2.4.23",
"@volar/typescript": "2.4.20", "@volar/typescript": "2.4.23",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"request-light": "^0.7.0", "request-light": "^0.7.0",
"vscode-languageserver": "^9.0.1", "vscode-languageserver": "^9.0.1",
@ -1620,30 +1621,30 @@
} }
}, },
"node_modules/@volar/language-service": { "node_modules/@volar/language-service": {
"version": "2.4.20", "version": "2.4.23",
"resolved": "https://registry.npmmirror.com/@volar/language-service/-/language-service-2.4.20.tgz", "resolved": "https://registry.npmmirror.com/@volar/language-service/-/language-service-2.4.23.tgz",
"integrity": "sha512-LoCD4rEI1Bj5ld6b+2GH1SbDGnoisvJ5skHlrkFEtJWw0T2+bhqGUXwekFudV/bRtp8fPhvD5ZUtjWSW0VRztg==", "integrity": "sha512-h5mU9DZ/6u3LCB9xomJtorNG6awBNnk9VuCioGsp6UtFiM8amvS5FcsaC3dabdL9zO0z+Gq9vIEMb/5u9K6jGQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-core": "2.4.20", "@volar/language-core": "2.4.23",
"vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11", "vscode-languageserver-textdocument": "^1.0.11",
"vscode-uri": "^3.0.8" "vscode-uri": "^3.0.8"
} }
}, },
"node_modules/@volar/source-map": { "node_modules/@volar/source-map": {
"version": "2.4.20", "version": "2.4.23",
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz", "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.23.tgz",
"integrity": "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg==", "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@volar/typescript": { "node_modules/@volar/typescript": {
"version": "2.4.20", "version": "2.4.23",
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz", "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.23.tgz",
"integrity": "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ==", "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-core": "2.4.20", "@volar/language-core": "2.4.23",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"vscode-uri": "^3.0.8" "vscode-uri": "^3.0.8"
} }
@ -1758,12 +1759,12 @@
} }
}, },
"node_modules/@vue/language-core": { "node_modules/@vue/language-core": {
"version": "3.0.3", "version": "3.0.5",
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.5.tgz",
"integrity": "sha512-I9wY0ULMN9tMSua+2C7g+ez1cIziVMUzIHlDYGSl2rtru3Eh4sXj95vZ+4GBuXwwPnEmYfzSApVbXiVbI8V5Gg==", "integrity": "sha512-gCEjn9Ik7I/seHVNIEipOm8W+f3/kg60e8s1IgIkMYma2wu9ZGUTMv3mSL2bX+Md2L8fslceJ4SU8j1fgSRoiw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-core": "2.4.20", "@volar/language-core": "2.4.22",
"@vue/compiler-dom": "^3.5.0", "@vue/compiler-dom": "^3.5.0",
"@vue/compiler-vue2": "^2.7.16", "@vue/compiler-vue2": "^2.7.16",
"@vue/shared": "^3.5.0", "@vue/shared": "^3.5.0",
@ -1781,16 +1782,31 @@
} }
} }
}, },
"node_modules/@vue/language-server": { "node_modules/@vue/language-core/node_modules/@volar/language-core": {
"version": "3.0.3", "version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@vue/language-server/-/language-server-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.22.tgz",
"integrity": "sha512-u/gyF/R89+UVlXd9Fc+8Se5Y+SxePSM1rtR361MFVu7qc92LmcxRqBIibiz8LY+KTkpMhHIqs/jObtX0d40QBg==", "integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-server": "2.4.20", "@volar/source-map": "2.4.22"
"@vue/language-core": "3.0.3", }
"@vue/language-service": "3.0.3", },
"@vue/typescript-plugin": "3.0.3", "node_modules/@vue/language-core/node_modules/@volar/source-map": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.22.tgz",
"integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==",
"license": "MIT"
},
"node_modules/@vue/language-server": {
"version": "3.0.5",
"resolved": "https://registry.npmmirror.com/@vue/language-server/-/language-server-3.0.5.tgz",
"integrity": "sha512-f3SeLh8w4qjE82hZWVTDjTXnJ6PcKuqoDSXs69JPGfSH4yuy7VXC2IIoMhtvnupMxXTYjtJQJKjhe0p/h4whhw==",
"license": "MIT",
"dependencies": {
"@volar/language-server": "2.4.22",
"@vue/language-core": "3.0.5",
"@vue/language-service": "3.0.5",
"@vue/typescript-plugin": "3.0.5",
"vscode-uri": "^3.0.8" "vscode-uri": "^3.0.8"
}, },
"bin": { "bin": {
@ -1800,14 +1816,69 @@
"typescript": "*" "typescript": "*"
} }
}, },
"node_modules/@vue/language-service": { "node_modules/@vue/language-server/node_modules/@volar/language-core": {
"version": "3.0.3", "version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@vue/language-service/-/language-service-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.22.tgz",
"integrity": "sha512-DsJOPZUmSCEa61nDh0UqMPS7pS9Ti7uEHVRXBEc6oRp2SsZH8IGooaxHNT1Nbj0OtQfcMcopytPwD6H4EBQjNw==", "integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/language-service": "2.4.20", "@volar/source-map": "2.4.22"
"@vue/language-core": "3.0.3", }
},
"node_modules/@vue/language-server/node_modules/@volar/language-server": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/language-server/-/language-server-2.4.22.tgz",
"integrity": "sha512-THIGWcQsEJKZU7SjVKPcy4MIamX4qpusKErj33ru7fi2WcD+FmFjYY/F2LIk/C15xEcb34JT1uZBlbO2dfzYSQ==",
"license": "MIT",
"dependencies": {
"@volar/language-core": "2.4.22",
"@volar/language-service": "2.4.22",
"@volar/typescript": "2.4.22",
"path-browserify": "^1.0.1",
"request-light": "^0.7.0",
"vscode-languageserver": "^9.0.1",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11",
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vue/language-server/node_modules/@volar/language-service": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/language-service/-/language-service-2.4.22.tgz",
"integrity": "sha512-8TmvOf/6uqaJMBVQIP9kgVpRzMrqLI3nCmWuSIPAldlmwjZTOiN17GA4AL4sTFJUg61xCSyMQWbProNFQ88yew==",
"license": "MIT",
"dependencies": {
"@volar/language-core": "2.4.22",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11",
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vue/language-server/node_modules/@volar/source-map": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.22.tgz",
"integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==",
"license": "MIT"
},
"node_modules/@vue/language-server/node_modules/@volar/typescript": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.22.tgz",
"integrity": "sha512-6ZczlJW1/GWTrNnkmZxJp4qyBt/SGVlcTuCWpI5zLrdPdCZsj66Aff9ZsfFaT3TyjG8zVYgBMYPuCm/eRkpcpQ==",
"license": "MIT",
"dependencies": {
"@volar/language-core": "2.4.22",
"path-browserify": "^1.0.1",
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vue/language-service": {
"version": "3.0.5",
"resolved": "https://registry.npmmirror.com/@vue/language-service/-/language-service-3.0.5.tgz",
"integrity": "sha512-3EFghz2F8oqQtqrSQjZiDZ+6jjCOrgdqPyJThPsy46EQfwslwFTW1ks87FzJtZR9xyfIpF3+0rxrFUyrWNFU3w==",
"license": "MIT",
"dependencies": {
"@volar/language-service": "2.4.22",
"@vue/language-core": "3.0.5",
"@vue/shared": "^3.5.0", "@vue/shared": "^3.5.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"volar-service-css": "0.0.65", "volar-service-css": "0.0.65",
@ -1821,6 +1892,33 @@
"vscode-uri": "^3.0.8" "vscode-uri": "^3.0.8"
} }
}, },
"node_modules/@vue/language-service/node_modules/@volar/language-core": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.22.tgz",
"integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==",
"license": "MIT",
"dependencies": {
"@volar/source-map": "2.4.22"
}
},
"node_modules/@vue/language-service/node_modules/@volar/language-service": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/language-service/-/language-service-2.4.22.tgz",
"integrity": "sha512-8TmvOf/6uqaJMBVQIP9kgVpRzMrqLI3nCmWuSIPAldlmwjZTOiN17GA4AL4sTFJUg61xCSyMQWbProNFQ88yew==",
"license": "MIT",
"dependencies": {
"@volar/language-core": "2.4.22",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11",
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vue/language-service/node_modules/@volar/source-map": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.22.tgz",
"integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==",
"license": "MIT"
},
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.5.17", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz", "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz",
@ -1872,17 +1970,43 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vue/typescript-plugin": { "node_modules/@vue/typescript-plugin": {
"version": "3.0.3", "version": "3.0.5",
"resolved": "https://registry.npmmirror.com/@vue/typescript-plugin/-/typescript-plugin-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@vue/typescript-plugin/-/typescript-plugin-3.0.5.tgz",
"integrity": "sha512-UgMxoIxrR0HoTV50DH7MTeT/YU917VAJxJg+lQFwTkxJTNPsaZ+QCmnsR46/s6MBRIHCJinn+up2aC22XXf4PA==", "integrity": "sha512-iR34R1dtgU75r2zxl62mGXyJVznh4Ne+1cUVQeBN6Ci3R3AAzP3v3vVVNu+QwdS37CtQAiTXfOJdiySQQ64NwQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@volar/typescript": "2.4.20", "@volar/typescript": "2.4.22",
"@vue/language-core": "3.0.3", "@vue/language-core": "3.0.5",
"@vue/shared": "^3.5.0", "@vue/shared": "^3.5.0",
"path-browserify": "^1.0.1" "path-browserify": "^1.0.1"
} }
}, },
"node_modules/@vue/typescript-plugin/node_modules/@volar/language-core": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.22.tgz",
"integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==",
"license": "MIT",
"dependencies": {
"@volar/source-map": "2.4.22"
}
},
"node_modules/@vue/typescript-plugin/node_modules/@volar/source-map": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.22.tgz",
"integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==",
"license": "MIT"
},
"node_modules/@vue/typescript-plugin/node_modules/@volar/typescript": {
"version": "2.4.22",
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.22.tgz",
"integrity": "sha512-6ZczlJW1/GWTrNnkmZxJp4qyBt/SGVlcTuCWpI5zLrdPdCZsj66Aff9ZsfFaT3TyjG8zVYgBMYPuCm/eRkpcpQ==",
"license": "MIT",
"dependencies": {
"@volar/language-core": "2.4.22",
"path-browserify": "^1.0.1",
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vuepic/vue-datepicker": { "node_modules/@vuepic/vue-datepicker": {
"version": "11.0.2", "version": "11.0.2",
"resolved": "https://registry.npmmirror.com/@vuepic/vue-datepicker/-/vue-datepicker-11.0.2.tgz", "resolved": "https://registry.npmmirror.com/@vuepic/vue-datepicker/-/vue-datepicker-11.0.2.tgz",
@ -2029,9 +2153,9 @@
} }
}, },
"node_modules/alien-signals": { "node_modules/alien-signals": {
"version": "2.0.5", "version": "2.0.6",
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz", "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.6.tgz",
"integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==", "integrity": "sha512-P3TxJSe31bUHBiblg59oU1PpaWPtmxF9GhJ/cB7OkgJ0qN/ifFSKUI25/v8ZhsT+lIG6ac8DpTOplXxORX6F3Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/animate.css": { "node_modules/animate.css": {

View File

@ -12,7 +12,8 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@vue/language-server": "^3.0.3", "@volar/language-server": "2.4.23",
"@vue/language-server": "3.0.5",
"@vuepic/vue-datepicker": "^11.0.2", "@vuepic/vue-datepicker": "^11.0.2",
"@vueuse/core": "^13.5.0", "@vueuse/core": "^13.5.0",
"@vueuse/shared": "^13.5.0", "@vueuse/shared": "^13.5.0",

View File

@ -0,0 +1,62 @@
<script setup lang="ts">
import LocaleText from "@/components/text/localeText.vue";
import { fetchPost } from "@/utilities/fetch"
import {ref} from "vue";
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore.js"
const props = defineProps(['client'])
const deleting = ref(false)
const confirmDelete = ref(false)
const emits = defineEmits(['refresh'])
const dashboardConfigurationStore = DashboardConfigurationStore()
const deleteClient = async () => {
deleting.value = true
await fetchPost("/api/clients/deleteClient", {
ClientID: props.client.ClientID
}, (res) => {
deleting.value = false
if (res.status){
emits("deleteSuccess")
dashboardConfigurationStore.newMessage("Server", "Delete client successfully", "success")
}else {
dashboardConfigurationStore.newMessage("Server", "Failed to delete client", "danger")
}
})
}
</script>
<template>
<div class="p-3 d-flex gap-3 flex-column border-bottom">
<div class="d-flex align-items-center gap-2">
<h6 class="mb-0">
<LocaleText t="Delete Client" v-if="!confirmDelete"></LocaleText>
<LocaleText t="Are you sure to delete this client?" v-else></LocaleText>
</h6>
<button class="btn btn-sm bg-danger-subtle text-danger-emphasis rounded-3 ms-auto"
v-if="!confirmDelete"
@click="confirmDelete = true"
>
<i class="bi bi-trash-fill me-2"></i>
<LocaleText t="Delete"></LocaleText>
</button>
<template v-if="confirmDelete">
<button
@click="deleteClient"
class="btn btn-sm bg-danger-subtle text-danger-emphasis rounded-3 ms-auto">
<i class="bi bi-trash-fill me-2"></i>
<LocaleText t="Yes"></LocaleText>
</button>
<button class="btn btn-sm bg-secondary-subtle text-secondary-emphasis rounded-3"
v-if="confirmDelete" @click="confirmDelete = false">
<i class="bi bi-x-lg me-2"></i>
<LocaleText t="No"></LocaleText>
</button>
</template>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -1,5 +1,5 @@
<script setup lang="ts" async> <script setup lang="ts" async>
import {useRoute} from "vue-router"; import {useRoute, useRouter} from "vue-router";
import { fetchGet, fetchPost } from "@/utilities/fetch.js" import { fetchGet, fetchPost } from "@/utilities/fetch.js"
@ -10,10 +10,12 @@ import {computed, reactive, ref, watch} from "vue";
import LocaleText from "@/components/text/localeText.vue"; import LocaleText from "@/components/text/localeText.vue";
import ClientAssignedPeers from "@/components/clientComponents/clientAssignedPeers.vue"; import ClientAssignedPeers from "@/components/clientComponents/clientAssignedPeers.vue";
import ClientResetPassword from "@/components/clientComponents/clientResetPassword.vue"; import ClientResetPassword from "@/components/clientComponents/clientResetPassword.vue";
import ClientDelete from "@/components/clientComponents/clientDelete.vue";
const assignmentStore = DashboardClientAssignmentStore() const assignmentStore = DashboardClientAssignmentStore()
const dashboardConfigurationStore = DashboardConfigurationStore() const dashboardConfigurationStore = DashboardConfigurationStore()
const route = useRoute() const route = useRoute()
const router = useRouter()
const client = computed(() => { const client = computed(() => {
return assignmentStore.getClientById(route.params.id) return assignmentStore.getClientById(route.params.id)
}) })
@ -25,9 +27,10 @@ const getAssignedPeers = async () => {
clientAssignedPeers.value = res.data; clientAssignedPeers.value = res.data;
}) })
} }
const emits = defineEmits(['deleteSuccess'])
const clientProfile = reactive({ const clientProfile = reactive({
Name: client.value.Name Name: undefined
}) })
if (client.value){ if (client.value){
@ -36,8 +39,14 @@ if (client.value){
await getAssignedPeers() await getAssignedPeers()
}) })
await getAssignedPeers() await getAssignedPeers()
clientProfile.Name = client.value.Name
}else{
router.push('/clients')
dashboardConfigurationStore.newMessage("WGDashboard", "Client does not exist", "danger")
} }
const updatingProfile = ref(false) const updatingProfile = ref(false)
const updateProfile = async () => { const updateProfile = async () => {
updatingProfile.value = true updatingProfile.value = true
@ -55,6 +64,10 @@ const updateProfile = async () => {
updatingProfile.value = false updatingProfile.value = false
}) })
} }
const deleteSuccess = () => {
router.push('/clients')
emits("deleteSuccess")
}
</script> </script>
@ -104,6 +117,9 @@ const updateProfile = async () => {
:client="client"></ClientAssignedPeers> :client="client"></ClientAssignedPeers>
<ClientResetPassword <ClientResetPassword
:client="client" v-if="client.ClientGroup === 'Local'"></ClientResetPassword> :client="client" v-if="client.ClientGroup === 'Local'"></ClientResetPassword>
<ClientDelete
@deleteSuccess="deleteSuccess()"
:client="client"></ClientDelete>
</div> </div>
</div> </div>
<div v-else class="d-flex w-100 h-100 text-muted"> <div v-else class="d-flex w-100 h-100 text-muted">

View File

@ -52,6 +52,7 @@ const oidc = computed(() => {
class="col-sm-4 border-end d-flex flex-column clientListContainer"> class="col-sm-4 border-end d-flex flex-column clientListContainer">
<div class="d-flex flex-column overflow-y-scroll" style="flex: 1 0 0"> <div class="d-flex flex-column overflow-y-scroll" style="flex: 1 0 0">
<ClientGroup :searchString="searchString" <ClientGroup :searchString="searchString"
v-if="Object.keys(assignmentStore.clients).includes('Local')"
:clients="assignmentStore.clients.Local" groupName="Local"></ClientGroup> :clients="assignmentStore.clients.Local" groupName="Local"></ClientGroup>
<ClientGroup v-for="(clients, groupName) in oidc" <ClientGroup v-for="(clients, groupName) in oidc"
:searchString="searchString" :searchString="searchString"
@ -61,7 +62,7 @@ const oidc = computed(() => {
<div <div
:class="{'hide': !route.params.id}" :class="{'hide': !route.params.id}"
class="col-sm-8 clientViewerContainer"> class="col-sm-8 clientViewerContainer">
<RouterView></RouterView> <RouterView @deleteSuccess="async () => { await assignmentStore.getClients()}"></RouterView>
</div> </div>
</div> </div>
</div> </div>