mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-06-28 01:06:58 +00:00
Update
This commit is contained in:
parent
6cb30bcd7f
commit
c6af129960
@ -81,7 +81,10 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
|
|||||||
if session.get('username') is None:
|
if session.get('username') 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
|
||||||
return ResponseObject(True)
|
return ResponseObject(True, data={
|
||||||
|
"Email": session.get('username'),
|
||||||
|
"Profile": DashboardClients.GetClientProfile(session.get("ClientID"))
|
||||||
|
})
|
||||||
return ResponseObject(status, msg)
|
return ResponseObject(status, msg)
|
||||||
|
|
||||||
@client.get(prefix)
|
@client.get(prefix)
|
||||||
|
@ -59,7 +59,14 @@ class DashboardClients:
|
|||||||
).where(
|
).where(
|
||||||
self.dashboardClientsTable.c.DeletedDate is None)
|
self.dashboardClientsTable.c.DeletedDate is None)
|
||||||
).mappings().fetchall()
|
).mappings().fetchall()
|
||||||
|
|
||||||
|
def GetClientProfile(self, ClientID):
|
||||||
|
with self.engine.connect() as conn:
|
||||||
|
return dict(conn.execute(
|
||||||
|
self.dashboardClientsInfoTable.select().where(
|
||||||
|
self.dashboardClientsInfoTable.c.ClientID == ClientID
|
||||||
|
)
|
||||||
|
).mappings().fetchone())
|
||||||
|
|
||||||
def SignIn(self, Email, Password) -> tuple[bool, str]:
|
def SignIn(self, Email, Password) -> tuple[bool, str]:
|
||||||
if not all([Email, Password]):
|
if not all([Email, Password]):
|
||||||
|
@ -74,10 +74,8 @@ class DashboardClientsPeerAssignment:
|
|||||||
|
|
||||||
def GetAssignedPeers(self, ClientID):
|
def GetAssignedPeers(self, ClientID):
|
||||||
peers = []
|
peers = []
|
||||||
assigned = list(
|
assigned = filter(lambda e:
|
||||||
filter(lambda e:
|
e['ClientID'] == ClientID, self.assignments)
|
||||||
e['ClientID'] == ClientID, self.assignments)
|
|
||||||
)
|
|
||||||
|
|
||||||
for a in assigned:
|
for a in assigned:
|
||||||
peer = filter(lambda e : e.id == a['PeerID'],
|
peer = filter(lambda e : e.id == a['PeerID'],
|
||||||
@ -97,6 +95,4 @@ class DashboardClientsPeerAssignment:
|
|||||||
'configuration_name': a['ConfigurationName'],
|
'configuration_name': a['ConfigurationName'],
|
||||||
'peer_configuration_data': p.downloadPeer()
|
'peer_configuration_data': p.downloadPeer()
|
||||||
})
|
})
|
||||||
|
|
||||||
print(peers)
|
|
||||||
return peers
|
return peers
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import './assets/main.css'
|
import './assets/main.css'
|
||||||
import NotificationList from "@/components/notification/notificationList.vue";
|
import NotificationList from "@/components/Notification/notificationList.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
<script setup>
|
||||||
|
import {ref} from "vue";
|
||||||
|
import ConfigurationQRCode from "@/components/Configuration/configurationQRCode.vue";
|
||||||
|
|
||||||
|
const props = defineProps([
|
||||||
|
'config'
|
||||||
|
])
|
||||||
|
|
||||||
|
const showQRCode = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="card shadow rounded-3">
|
||||||
|
<div class="card-header d-flex align-items-center">
|
||||||
|
<div>
|
||||||
|
<small v-if="props.config.status === 'stopped'">
|
||||||
|
<i class="bi bi-lightbulb text-secondary me-2"></i>
|
||||||
|
</small>
|
||||||
|
<small v-else>
|
||||||
|
<i class="bi bi-lightbulb-fill text-success me-2"></i>
|
||||||
|
</small>
|
||||||
|
<small style="word-break: break-all">
|
||||||
|
{{ props.config.name }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div class="ms-auto d-flex gap-2 button-group">
|
||||||
|
<a role="button" class="px-2 py-1 text-white rounded-3" aria-label="Download Configuration">
|
||||||
|
<i class="bi bi-download"></i>
|
||||||
|
</a>
|
||||||
|
<a role="button"
|
||||||
|
@click="showQRCode = true"
|
||||||
|
class="px-2 py-1 text-white rounded-3" aria-label="Display QR Code">
|
||||||
|
<i class="bi bi-qr-code"></i>
|
||||||
|
</a>
|
||||||
|
<Transition name="app">
|
||||||
|
<ConfigurationQRCode
|
||||||
|
v-if="showQRCode"
|
||||||
|
@back="showQRCode = false"
|
||||||
|
:qrcode-data="config.peer_configuration_data.file"></ConfigurationQRCode>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div>
|
||||||
|
<small class="d-block text-muted" style="font-size: 0.8rem">Public Key</small>
|
||||||
|
<small>
|
||||||
|
<samp style="word-break: break-word">{{ props.config.id }}</samp>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-center">Data Usage</h6>
|
||||||
|
<div class="row text-center">
|
||||||
|
<div class="col-4">
|
||||||
|
<small class="d-block text-muted">
|
||||||
|
Total
|
||||||
|
</small>
|
||||||
|
<small>3.20 GB / 4GB</small>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<small class="d-block text-muted">
|
||||||
|
Received
|
||||||
|
</small>
|
||||||
|
<small>3.20 GB</small>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<small class="d-block text-muted">
|
||||||
|
Sent
|
||||||
|
</small>
|
||||||
|
<small>3.20 GB</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.button-group a:hover{
|
||||||
|
background-color: #ffffff20;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import * as uuid from "uuid";
|
||||||
|
import {onMounted} from "vue";
|
||||||
|
import QRCode from "qrcode";
|
||||||
|
import Qrcode from "@/components/SignIn/qrcode.vue";
|
||||||
|
|
||||||
|
const props = defineProps([
|
||||||
|
'qrcodeData'
|
||||||
|
])
|
||||||
|
|
||||||
|
const emits = defineEmits([
|
||||||
|
'back'
|
||||||
|
])
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-2 position-fixed top-0 start-0 vw-100 vh-100 d-flex qrcodeContainer">
|
||||||
|
<div class="m-auto d-flex gap-3 flex-column">
|
||||||
|
<a role="button" @click="emits('back')">
|
||||||
|
<i class="me-2 bi bi-chevron-left"></i> Back
|
||||||
|
</a>
|
||||||
|
<Qrcode :content="props.qrcodeData" ></Qrcode>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.qrcodeContainer{
|
||||||
|
background-color: #00000050;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {clientStore} from "@/stores/clientStore.js";
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
import Notification from "@/components/notification/notification.vue";
|
import Notification from "@/components/Notification/notification.vue";
|
||||||
import {computed, onMounted} from "vue";
|
import {computed, onMounted} from "vue";
|
||||||
const store = clientStore()
|
const store = clientStore()
|
||||||
const notifications = computed(() => {
|
const notifications = computed(() => {
|
@ -1,19 +1,21 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted} from "vue";
|
import {onMounted} from "vue";
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
import * as uuid from "uuid";
|
||||||
|
|
||||||
const props = defineProps([
|
const props = defineProps([
|
||||||
"content"
|
"content"
|
||||||
])
|
])
|
||||||
|
const id = uuid.v4().toString()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
QRCode.toCanvas(document.getElementById('qrcode'), props.content, function (error) {})
|
QRCode.toCanvas(document.getElementById(`qrcode_${id}`), props.content, function (error) {})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<canvas id="qrcode" class="rounded-3 shadow"></canvas>
|
<canvas :id="'qrcode_' + id" class="rounded-3 shadow"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup async>
|
<script setup async>
|
||||||
import {computed, onMounted, reactive, ref} from "vue";
|
import {computed, onMounted, reactive, ref, watch} from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {axiosPost, requestURl} from "@/utilities/request.js";
|
import {axiosPost, requestURl} from "@/utilities/request.js";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
@ -45,13 +45,8 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['clearToken'])
|
const emits = defineEmits(['clearToken'])
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
const verify = async (e) => {
|
const verify = async (e) => {
|
||||||
e.preventDefault()
|
if (e) e.preventDefault()
|
||||||
if (formFilled){
|
if (formFilled){
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const data = await axiosPost('/api/signin/totp', {
|
const data = await axiosPost('/api/signin/totp', {
|
||||||
@ -61,6 +56,7 @@ const verify = async (e) => {
|
|||||||
loading.value = false
|
loading.value = false
|
||||||
if (data){
|
if (data){
|
||||||
if (data.status){
|
if (data.status){
|
||||||
|
store.clientProfile = data.data
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}else{
|
}else{
|
||||||
store.newNotification(data.message, "danger")
|
store.newNotification(data.message, "danger")
|
||||||
@ -71,6 +67,10 @@ const verify = async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(formFilled, () => {
|
||||||
|
verify()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
import {defineStore} from "pinia";
|
import {defineStore} from "pinia";
|
||||||
import {ref} from "vue";
|
import {onMounted, reactive, ref} from "vue";
|
||||||
import {v4} from "uuid"
|
import {v4} from "uuid"
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import {axiosGet} from "@/utilities/request.js";
|
||||||
|
|
||||||
|
|
||||||
export const clientStore = defineStore('clientStore', () => {
|
export const clientStore = defineStore('clientStore', () => {
|
||||||
const notifications = ref([])
|
const notifications = ref([])
|
||||||
|
const configurations = ref([])
|
||||||
|
const clientProfile = reactive({
|
||||||
|
Email: "",
|
||||||
|
Profile: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
function newNotification(content, status) {
|
function newNotification(content, status) {
|
||||||
notifications.value.push({
|
notifications.value.push({
|
||||||
id: v4().toString(),
|
id: v4().toString(),
|
||||||
@ -15,8 +23,16 @@ export const clientStore = defineStore('clientStore', () => {
|
|||||||
show: true
|
show: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getConfigurations(){
|
||||||
|
const data = await axiosGet("/api/configurations")
|
||||||
|
if (data){
|
||||||
|
configurations.value = data.data
|
||||||
|
}else{
|
||||||
|
newNotification("Failed to fetch configurations", "danger")
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
notifications, newNotification
|
notifications, newNotification, getConfigurations, configurations, clientProfile
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,14 +1,26 @@
|
|||||||
<script setup>
|
<script setup async>
|
||||||
import {onMounted} from "vue";
|
import {computed, onMounted, ref} from "vue";
|
||||||
import {axiosGet} from "@/utilities/request.js";
|
import {axiosGet} from "@/utilities/request.js";
|
||||||
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
|
import Configuration from "@/components/Configuration/configuration.vue";
|
||||||
|
const store = clientStore()
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
const loadConfigurations = async () => {
|
||||||
|
|
||||||
|
await store.getConfigurations()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const configurations = computed(() => {
|
||||||
|
return store.configurations
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const data = await axiosGet("/api/configurations")
|
// loading.value = true;
|
||||||
if (data){
|
await loadConfigurations();
|
||||||
console.log(data)
|
loading.value = false;
|
||||||
}else{
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -33,13 +45,23 @@ onMounted(async () => {
|
|||||||
</RouterLink>
|
</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="d-flex flex-column gap-3">
|
<Transition name="app" mode="out-in">
|
||||||
<div class="px-3 border-bottom py-4">
|
<div class="d-flex flex-column gap-3" v-if="!loading">
|
||||||
<h6>Hi donaldzou@live.hk!</h6>
|
<div class="px-3 border-bottom py-4">
|
||||||
<h5 class="mb-0">You have <strong>3</strong> configurations available</h5>
|
<h6>Hi donaldzou@live.hk!</h6>
|
||||||
|
<h5 class="mb-0">You have <strong>
|
||||||
|
{{ configurations.length }}
|
||||||
|
</strong> configuration{{ configurations.length > 1 ? 's':''}} available</h5>
|
||||||
|
</div>
|
||||||
|
<div class="px-3">
|
||||||
|
<Configuration v-for="config in configurations" :config="config"></Configuration>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
<div v-else class="d-flex py-4">
|
||||||
</div>
|
<div class="spinner-border m-auto"></div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user