Added toggle for signing up local clients

This commit is contained in:
Donald Zou
2025-12-28 17:02:14 +08:00
parent 0d70d13d0f
commit a3058d2a28
7 changed files with 68 additions and 36 deletions

View File

@@ -54,6 +54,8 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
@client.post(f'{prefix}/api/signup') @client.post(f'{prefix}/api/signup')
def ClientAPI_SignUp(): def ClientAPI_SignUp():
if not dashboardConfig.GetConfig("Clients", "sign_up")[1]:
abort(404)
data = request.get_json() data = request.get_json()
status, msg = dashboardClients.SignUp(**data) status, msg = dashboardClients.SignUp(**data)
return ResponseObject(status, msg) return ResponseObject(status, msg)
@@ -209,7 +211,10 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
@client.get(f'{prefix}/api/serverInformation') @client.get(f'{prefix}/api/serverInformation')
def ClientAPI_ServerInformation(): def ClientAPI_ServerInformation():
return ResponseObject(data={ return ResponseObject(data={
"ServerTimezone": str(get_localzone()) "ServerTimezone": str(get_localzone()),
"SignUp": {
"enable": dashboardConfig.GetConfig("Clients", "sign_up")[1]
}
}) })
@client.get(f'{prefix}/api/validateAuthentication') @client.get(f'{prefix}/api/validateAuthentication')

View File

@@ -83,6 +83,7 @@ class DashboardConfig:
}, },
"Clients": { "Clients": {
"enable": "true", "enable": "true",
"sign_up": "true"
}, },
"WireGuardConfiguration": { "WireGuardConfiguration": {
"autostart": "", "autostart": "",

View File

@@ -2,7 +2,7 @@
import { ref, reactive } from "vue" import { ref, reactive } from "vue"
import LocaleText from "@/components/text/localeText.vue"; import LocaleText from "@/components/text/localeText.vue";
import OidcSettings from "@/components/clientComponents/clientSettingComponents/oidcSettings.vue"; import OidcSettings from "@/components/clientComponents/clientSettingComponents/oidcSettings.vue";
import { fetchGet } from "@/utilities/fetch.js" import { fetchGet, fetchPost } from "@/utilities/fetch.js"
const emits = defineEmits(['close']) const emits = defineEmits(['close'])
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore" import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore"
const dashboardConfigurationStore = DashboardConfigurationStore() const dashboardConfigurationStore = DashboardConfigurationStore()
@@ -12,12 +12,16 @@ const values = reactive({
}) })
const toggling = ref(false) const toggling = ref(false)
const toggleClientSideApp = async () => { const updateSettings = async (key: string) => {
toggling.value = true toggling.value = true
await fetchGet("/api/clients/toggleStatus", {}, (res) => { await fetchPost("/api/updateDashboardConfigurationItem", {
values.enableClients = res.data section: "Clients",
key: key,
value: dashboardConfigurationStore.Configuration.Clients[key]
}, async (res) => {
await dashboardConfigurationStore.getConfiguration()
toggling.value = false
}) })
toggling.value = false
} }
</script> </script>
@@ -37,16 +41,43 @@ const toggleClientSideApp = async () => {
</h6> </h6>
<div class="form-check form-switch ms-auto"> <div class="form-check form-switch ms-auto">
<label class="form-check-label" for="oidc_switch"> <label class="form-check-label" for="oidc_switch">
<LocaleText :t="values.enableClients ? 'Enabled':'Disabled'"></LocaleText> <LocaleText :t="dashboardConfigurationStore.Configuration.Clients.enable ? 'Enabled':'Disabled'"></LocaleText>
</label> </label>
<input <input
:disabled="oidcStatusLoading" :disabled="toggling"
v-model="values.enableClients" v-model="dashboardConfigurationStore.Configuration.Clients.enable"
@change="toggleClientSideApp()" @change="updateSettings('enable')"
class="form-check-input" type="checkbox" role="switch" id="oidc_switch"> class="form-check-input" type="checkbox" role="switch" id="oidc_switch">
</div> </div>
</div> </div>
<OidcSettings mode="Client"></OidcSettings> <hr>
<div>
<div class="d-flex align-items-center">
<h6 class="mb-0">
<LocaleText t="Sign Up as Local Client"></LocaleText>
</h6>
<div class="form-check form-switch ms-auto">
<label class="form-check-label" for="sign_up_switch">
<LocaleText :t="dashboardConfigurationStore.Configuration.Clients.sign_up ? 'Enabled':'Disabled'"></LocaleText>
</label>
<input
:disabled="toggling"
v-model="dashboardConfigurationStore.Configuration.Clients.sign_up"
@change="updateSettings('sign_up')"
class="form-check-input" type="checkbox" role="switch" id="sign_up_switch">
</div>
</div>
<small class="text-muted mb-0">
<LocaleText t="Allow clients to sign up with Email and Password"></LocaleText>
</small>
</div>
<div>
<OidcSettings mode="Client"></OidcSettings>
<small class="text-muted mb-0">
<LocaleText t="Allow clients to access with OpenID"></LocaleText>
</small>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,22 +1,12 @@
<script setup async> <script setup>
import './assets/main.css' import './assets/main.css'
import NotificationList from "@/components/Notification/notificationList.vue"; import NotificationList from "@/components/Notification/notificationList.vue";
import {clientStore} from "@/stores/clientStore.js";
import {axiosGet} from "@/utilities/request.js";
const store = clientStore()
const serverInformation = axiosGet("/api/serverInformation", {})
if (serverInformation){
store.serverInformation = serverInformation;
}
</script> </script>
<template> <template>
<div data-bs-theme="dark" class="text-body bg-body vw-100 vh-100 bg-body"> <div data-bs-theme="dark" class="text-body bg-body vw-100 vh-100 bg-body">
<div class="d-flex vw-100 p-sm-4 overflow-y-scroll innerContainer d-flex flex-column"> <div class="d-flex vw-100 p-sm-4 overflow-y-scroll innerContainer d-flex flex-column">
<div class="mx-auto my-sm-auto position-relative" <div class="mx-auto my-sm-auto position-relative" id="listContainer">
id="listContainer"
>
<Suspense> <Suspense>
<RouterView v-slot="{ Component }"> <RouterView v-slot="{ Component }">
<Transition name="app" type="transition" mode="out-in"> <Transition name="app" type="transition" mode="out-in">

View File

@@ -96,7 +96,7 @@ if (route.query.Email){
</span> </span>
</button> </button>
</form> </form>
<div> <div v-if="store.serverInformation.SignUp.enable">
<hr class="my-4"> <hr class="my-4">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="text-muted"> <span class="text-muted">

View File

@@ -6,43 +6,43 @@ import router from "@/router/router.js";
import {createPinia} from "pinia"; import {createPinia} from "pinia";
import 'bootstrap/dist/js/bootstrap.bundle.js' import 'bootstrap/dist/js/bootstrap.bundle.js'
import {axiosPost} from "@/utilities/request.js"; import {axiosGet, axiosPost} from "@/utilities/request.js";
import {clientStore} from "@/stores/clientStore.js";
const params = new URLSearchParams(window.location.search) const params = new URLSearchParams(window.location.search)
const state = params.get('state') const state = params.get('state')
const code = params.get('code') const code = params.get('code')
const initApp = () => { const initApp = async () => {
const app = createApp(App) const app = createApp(App)
const serverInformation = await axiosGet("/api/serverInformation", {})
app.use(createPinia()) app.use(createPinia())
if (serverInformation){
const store = clientStore()
store.serverInformation = serverInformation.data;
}
app.use(router) app.use(router)
app.mount("#app") app.mount("#app")
} }
function removeSearchString() {
let url = new URL(window.location.href);
url.search = ''; // Remove all query parameters
history.replaceState({}, document.title, url.toString());
}
if (state && code){ if (state && code){
axiosPost("/api/signin/oidc", { await axiosPost("/api/signin/oidc", {
provider: state, provider: state,
code: code, code: code,
redirect_uri: window.location.protocol + '//' + window.location.host + window.location.pathname redirect_uri: window.location.protocol + '//' + window.location.host + window.location.pathname
}).then(data => { }).then(async (data) => {
let url = new URL(window.location.href); let url = new URL(window.location.href);
url.search = ''; url.search = '';
history.replaceState({}, document.title, url.toString()); history.replaceState({}, document.title, url.toString());
initApp() await initApp()
if (!data.status){ if (!data.status){
const store = clientStore() const store = clientStore()
store.newNotification(data.message, 'danger') store.newNotification(data.message, 'danger')
} }
}) })
}else{ }else{
initApp() await initApp()
} }

View File

@@ -50,6 +50,11 @@ const router = createRouter({
}) })
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const store = clientStore() const store = clientStore()
if (to.path === "/signup" && !store.serverInformation.SignUp.enable){
next('/signin')
store.newNotification("Sign up is disabled. Please contact administrator for more information", "warning")
}
if (to.path === '/signout'){ if (to.path === '/signout'){
await axios.get(requestURl('/api/signout')).then(() => { await axios.get(requestURl('/api/signout')).then(() => {
next('/signin') next('/signin')