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

The sharing function is almost done

This commit is contained in:
Donald Zou 2024-08-06 10:17:14 -04:00
parent 4484668750
commit 958bc864c9
9 changed files with 245 additions and 28 deletions

View File

@ -77,7 +77,12 @@ class CustomJsonEncoder(DefaultJSONProvider):
super().__init__(app)
def default(self, o):
if isinstance(o, WireguardConfiguration) or isinstance(o, Peer) or isinstance(o, PeerJob) or isinstance(o, Log) or isinstance(o, DashboardAPIKey):
if (isinstance(o, WireguardConfiguration)
or isinstance(o, Peer)
or isinstance(o, PeerJob)
or isinstance(o, Log)
or isinstance(o, DashboardAPIKey)
or isinstance(o, PeerShareLink)):
return o.toJson()
return super().default(self, o)
@ -335,19 +340,19 @@ class PeerJobs:
return x < y
class PeerShareLink:
def __init__(self, ShareID:str, Peer: str, Configuration: str, SharedDate: datetime, ExpireDate: datetime):
def __init__(self, ShareID:str, Configuration: str, Peer: str, ExpireDate: datetime, ShareDate: datetime):
self.ShareID = ShareID
self.Peer = Peer
self.Configuration = Configuration
self.SharedDate = SharedDate
self.ExpireData = ExpireDate
self.ShareDate = ShareDate
self.ExpireDate = ExpireDate
def toJson(self):
return {
"SharedID": self.ShareID,
"ShareID": self.ShareID,
"Peer": self.Peer,
"Configuration": self.Configuration,
"ShareDate": self.SharedDate
"ExpireDate": self.ExpireDate
}
class PeerShareLinks:
@ -363,38 +368,50 @@ class PeerShareLinks:
ExpireDate DATETIME,
SharedDate DATETIME DEFAULT (datetime('now', 'localtime'))
)
""" % self.Name
"""
)
sqldb.commit()
self.__getSharedLinks()
# print(self.Links)
def __getSharedLinks(self):
self.Links.clear()
allLinks = cursor.execute("SELECT * FROM PeerShareLinks WHERE ExpireDate IS NULL OR ExpireDate > datetime('now', 'localtime')").fetchall()
for link in allLinks:
self.Links.append(*link)
self.Links.append(PeerShareLink(*link))
def getLink(self, Configuration: str, Peer: str):
def getLink(self, Configuration: str, Peer: str) -> list[PeerShareLink]:
return list(filter(lambda x : x.Configuration == Configuration and x.Peer == Peer, self.Links))
def getLink(self, ShareID: str):
def getLinkByID(self, ShareID: str) -> list[PeerShareLink]:
return list(filter(lambda x : x.ShareID == ShareID, self.Links))
def addLink(self, Configuration: str, Peer: str, ExpireDate: datetime = None) -> tuple[bool, message]:
def addLink(self, Configuration: str, Peer: str, ExpireDate: datetime = None) -> tuple[bool, str]:
try:
newShareID = str(uuid.uuid4())
if len(self.getLink(Configuration, Peer)) > 0:
cursor.execute("UPDATE PeerShareLinks SET ExpireDate = datetime('now', 'localtime') WHERE Configuration = ? AND Peer = ?", (Configuration, Peer, ))
cursor.execute("INSERT INTO PeerShareLinks VALUES (?, ?, ?, ?)", (newShareID, Configuration, Peer, ExpireDate, ))
if ExpireDate is not None:
ExpireDate = datetime.strptime(ExpireDate, '%Y-%m-%d %H:%M:%S')
cursor.execute("INSERT INTO PeerShareLinks (ShareID, Configuration, Peer, ExpireDate) VALUES (?, ?, ?, ?)", (newShareID, Configuration, Peer, ExpireDate, ))
sqldb.commit()
self.__getSharedLinks()
except Exception as e:
return False, str(e)
return True
return True, newShareID
def updateLinkExpireDate(self, ShareID, ExpireDate):
cursor.execute("UPDATE PeerShareLinks SET ExpireDate = datetime('now', 'localtime') WHERE ShareID = ?", (ShareID, ))
sqldb.commit()
self.__getSharedLinks()
def updateLinkExpireDate(self, ShareID, ExpireDate: datetime = None) -> tuple[bool, str]:
try:
if ExpireDate is None:
cursor.execute("UPDATE PeerShareLinks SET ExpireDate = datetime('now', 'localtime') WHERE ShareID = ?", (ShareID, ))
else:
cursor.execute("UPDATE PeerShareLinks SET ExpireDate = ? WHERE ShareID = ?", (ShareID, datetime.strptime(ExpireDate, '%Y-%m-%d %H:%M:%S'), ))
sqldb.commit()
self.__getSharedLinks()
return True
except Exception as e:
return False, str(e)
@ -876,10 +893,13 @@ class Peer:
self.remote_endpoint = tableData["remote_endpoint"]
self.preshared_key = tableData["preshared_key"]
self.jobs: list[PeerJob] = []
self.ShareLink: list[PeerShareLink] = []
self.getJobs()
self.getShareLink()
def toJson(self):
self.getJobs()
self.getShareLink()
return self.__dict__
def __repr__(self):
@ -978,7 +998,9 @@ PersistentKeepalive = {str(self.keepalive)}
def getJobs(self):
self.jobs = AllPeerJobs.searchJob(self.configuration.Name, self.id)
# print(AllPeerJobs.searchJob(self.configuration.Name, self.id))
def getShareLink(self):
self.ShareLink = AllPeerShareLinks.getLink(self.configuration.Name, self.id)
# Regex Match
def regex_match(regex, text):
@ -1551,6 +1573,38 @@ def API_restrictPeers(configName: str) -> ResponseObject:
return configuration.restrictPeers(peers)
return ResponseObject(False, "Configuration does not exist")
@app.route('/api/sharePeer/create', methods=['POST'])
def API_sharePeer_create():
data: dict[str, str] = request.get_json()
Configuration = data.get('Configuration')
Peer = data.get('Peer')
ExpireDate = data.get('ExpireDate')
if Configuration is None or Peer is None:
return ResponseObject(False, "Please specify configuration and peer")
activeLink = AllPeerShareLinks.getLink(Configuration, Peer)
if len(activeLink) > 0:
return ResponseObject(False, "This peer is already sharing, please stop sharing first.")
status, message = AllPeerShareLinks.addLink(Configuration, Peer, ExpireDate)
if not status:
return ResponseObject(status, message)
return ResponseObject(data=AllPeerShareLinks.getLinkByID(message))
@app.route('/api/sharePeer/update', methods=['POST'])
def API_sharePeer_update():
data: dict[str, str] = request.get_json()
ShareID: str = data.get("ShareID")
ExpireDate: str = data.get("ExpireDate")
if ShareID is None:
return ResponseObject(False, "Please specify ShareID")
if len(AllPeerShareLinks.getLinkByID(ShareID)) == 0:
return ResponseObject(False, "ShareID does not exist")
status, message = AllPeerShareLinks.updateLinkExpireDate(ShareID, ExpireDate)
if not status:
return ResponseObject(status, message)
return ResponseObject(data=AllPeerShareLinks.getLinkByID(ShareID))
@app.route('/api/allowAccessPeers/<configName>', methods=['POST'])
def API_allowAccessPeers(configName: str) -> ResponseObject:
@ -1949,6 +2003,7 @@ sqldb.row_factory = sqlite3.Row
cursor = sqldb.cursor()
DashboardConfig = DashboardConfig()
AllPeerShareLinks: PeerShareLinks = PeerShareLinks()
AllPeerJobs: PeerJobs = PeerJobs()
JobLogger: PeerJobLogger = PeerJobLogger()
DashboardLogger: DashboardLogger = DashboardLogger()

View File

@ -8,6 +8,7 @@
"name": "app",
"version": "0.0.0",
"dependencies": {
"@vuepic/vue-datepicker": "^9.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/shared": "^10.9.0",
"animate.css": "^4.1.1",
@ -721,6 +722,20 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.29.tgz",
"integrity": "sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA=="
},
"node_modules/@vuepic/vue-datepicker": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-9.0.1.tgz",
"integrity": "sha512-5sSdwib5cY8cE4Y7SCh+Zemfp+U/m6BDcgaPwd5Vmdv5LAASyV0wugn9sTb6NWX0sIQEdrGDl/RmD9EjcIke3A==",
"dependencies": {
"date-fns": "^3.6.0"
},
"engines": {
"node": ">=18.12.0"
},
"peerDependencies": {
"vue": ">=3.2.0"
}
},
"node_modules/@vueuse/core": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
@ -937,6 +952,15 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/date-fns": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/dayjs": {
"version": "1.11.12",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",

View File

@ -9,6 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@vuepic/vue-datepicker": "^9.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/shared": "^10.9.0",
"animate.css": "^4.1.1",

View File

@ -86,6 +86,7 @@ export default {
@setting="this.$emit('setting')"
@jobs="this.$emit('jobs')"
@refresh="this.$emit('refresh')"
@share="this.$emit('share')"
:Peer="Peer"
v-if="this.subMenuOpened"
ref="target"

View File

@ -40,6 +40,7 @@ import PeerJobs from "@/components/configurationComponents/peerJobs.vue";
import PeerJobsAllModal from "@/components/configurationComponents/peerJobsAllModal.vue";
import PeerJobsLogsModal from "@/components/configurationComponents/peerJobsLogsModal.vue";
import {ref} from "vue";
import PeerShareLinkModal from "@/components/configurationComponents/peerShareLinkModal.vue";
Chart.register(
ArcElement,
@ -70,6 +71,7 @@ Chart.register(
export default {
name: "peerList",
components: {
PeerShareLinkModal,
PeerJobsLogsModal,
PeerJobsAllModal, PeerJobs, PeerCreate, PeerQRCode, PeerSettings, PeerSearch, Peer, Line, Bar},
setup(){
@ -131,6 +133,10 @@ export default {
},
peerScheduleJobsLogs: {
modalOpen: false
},
peerShare:{
modalOpen: false,
selectedPeer: undefined
}
}
},
@ -141,26 +147,21 @@ export default {
'$route': {
immediate: true,
handler(){
console.log(this.dashboardConfigurationStore.Peers.RefreshInterval)
clearInterval(this.dashboardConfigurationStore.Peers.RefreshInterval);
console.log(this.dashboardConfigurationStore.Peers.RefreshInterval)
this.loading = true;
let id = this.$route.params.id;
this.configurationInfo = [];
this.configurationPeers = [];
if (id){
this.getPeers(id)
console.log("Changed..")
this.setPeerInterval();
}
}
},
'dashboardConfigurationStore.Configuration.Server.dashboard_refresh_interval'(){
console.log("Changed?")
clearInterval(this.dashboardConfigurationStore.Peers.RefreshInterval);
this.setPeerInterval();
},
}
},
beforeRouteLeave(){
clearInterval(this.dashboardConfigurationStore.Peers.RefreshInterval);
@ -248,7 +249,6 @@ export default {
this.dashboardConfigurationStore.Peers.RefreshInterval = setInterval(() => {
this.getPeers()
}, parseInt(this.dashboardConfigurationStore.Configuration.Server.dashboard_refresh_interval))
console.log(this.dashboardConfigurationStore.Peers.RefreshInterval)
},
},
computed: {
@ -548,7 +548,7 @@ export default {
:key="peer.id"
v-for="peer in this.searchPeers">
<Peer :Peer="peer"
@share="this.peerShare.selectedPeer = peer.id; this.peerShare.modalOpen = true;"
@refresh="this.getPeers()"
@jobs="peerScheduleJobs.modalOpen = true; peerScheduleJobs.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"
@setting="peerSetting.modalOpen = true; peerSetting.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"
@ -595,6 +595,12 @@ export default {
>
</PeerJobsLogsModal>
</Transition>
<Transition name="zoom">
<PeerShareLinkModal
v-if="this.peerShare.modalOpen"
@close="this.peerShare.modalOpen = false; this.peerShare.selectedPeer = undefined;"
:peer="this.configurationPeers.find(x => x.id === this.peerShare.selectedPeer)"></PeerShareLinkModal>
</Transition>
</div>
</template>

View File

@ -123,7 +123,7 @@ export default {
</a>
</li>
<li>
<a class="dropdown-item d-flex" role="button">
<a class="dropdown-item d-flex" role="button" @click="this.$emit('share')">
<i class="me-auto bi bi-share"></i> Share
</a>
</li>

View File

@ -0,0 +1,124 @@
<script>
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {fetchPost} from "@/utilities/fetch.js";
import dayjs from "dayjs";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import VueDatePicker from '@vuepic/vue-datepicker';
export default {
name: "peerShareLinkModal",
props: {
peer: Object
},
components: {
VueDatePicker
},
data(){
return {
dataCopy: undefined,
loading: false
}
},
setup(){
const store = DashboardConfigurationStore();
return {store}
},
mounted() {
this.dataCopy = JSON.parse(JSON.stringify(this.peer.ShareLink)).at(0);
},
methods: {
startSharing(){
this.loading = true;
fetchPost("/api/sharePeer/create", {
Configuration: this.peer.configuration.Name,
Peer: this.peer.id,
ExpireDate: dayjs().add(30, 'd').format("YYYY-MM-DD hh:mm:ss")
}, (res) => {
if (res.status){
this.peer.ShareLink = res.data;
this.dataCopy = res.data;
this.store.newMessage("Server", "Share link created successfully", "success")
}else{
this.store.newMessage("Server",
"Share link failed to create. Reason: " + res.message, "danger")
}
this.loading = false;
})
},
updateLinkExpireDate(){
fetchPost("/api/sharePeer/update", this.dataCopy, (res) => {
console.log(res)
})
}
},
computed: {
getUrl(){
return window.location.origin
+ window.location.pathname
+ this.$router.resolve(
{path: "/share", query: {"ShareID": this.dataCopy.ShareID}}).href;
}
},
watch: {
'dataCopy.ExpireDate'(){
this.updateLinkExpireDate()
}
}
}
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal" style="width: 500px">
<div class="card rounded-3 shadow flex-grow-1">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
<h4 class="mb-0">Share Peer</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4" v-if="this.peer.ShareLink">
<div v-if="!this.dataCopy">
<h6 class="mb-3 text-muted">
Currently the peer is not sharing
</h6>
<button
@click="this.startSharing()"
:disabled="this.loading"
class="w-100 btn bg-success-subtle text-success-emphasis border-1 border-success-subtle rounded-3 shadow-sm">
<span :class="{'animate__animated animate__flash animate__infinite animate__slower': this.loading}">
<i class="bi bi-send-fill me-2" ></i>
</span>
{{this.loading ? "Sharing...":"Start Sharing"}}
</button>
</div>
<div v-else>
<div class="d-flex gap-2 mb-4">
<i class="bi bi-link-45deg"></i>
<a :href="this.getUrl"
class="text-decoration-none" target="_blank">
{{ getUrl }}
</a>
</div>
<div class="d-flex flex-column gap-2">
<small>
<i class="bi bi-calendar me-2"></i>
Expire Date
</small>
<VueDatePicker v-model="this.dataCopy.ExpireDate" time-picker-inline
format="yyyy-MM-dd HH:mm:ss"
:dark="this.store.Configuration.Server.dashboard_theme === 'dark'"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -3,6 +3,7 @@ import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/js/bootstrap.js'
import 'bootstrap-icons/font/bootstrap-icons.css'
import 'animate.css/animate.compat.css'
import '@vuepic/vue-datepicker/dist/main.css'
import {createApp, markRaw} from 'vue'
import { createPinia } from 'pinia'

View File

@ -1,3 +1,8 @@
*,
.dp__input{
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
}
::-webkit-scrollbar {
display: none;
}