mirror of
https://github.com/donaldzou/WGDashboard
synced 2025-02-26 05:58:47 +00:00
Finalized the email function
This commit is contained in:
parent
5d84b61f18
commit
4f92a7edf3
@ -1883,7 +1883,8 @@ class DashboardConfig:
|
||||
"encryption": "",
|
||||
"username": "",
|
||||
"email_password": "",
|
||||
"send_from": ""
|
||||
"send_from": "",
|
||||
"email_template": ""
|
||||
},
|
||||
"WireGuardConfiguration": {
|
||||
"autostart": ""
|
||||
@ -3053,15 +3054,14 @@ def API_Email_Send():
|
||||
data = request.get_json()
|
||||
if "Receiver" not in data.keys():
|
||||
return ResponseObject(False, "Please at least specify receiver")
|
||||
|
||||
body = data.get('Body', '')
|
||||
download = None
|
||||
if "ConfigurationName" in data.keys() and "Peer" in data.keys():
|
||||
if data.get('ConfigurationName') in WireguardConfigurations.keys():
|
||||
configuration = WireguardConfigurations.get(data.get('ConfigurationName'))
|
||||
attachmentName = ""
|
||||
if configuration is not None:
|
||||
fp, p = configuration.searchPeer(data.get('Peer'))
|
||||
print(fp)
|
||||
if fp:
|
||||
template = Template(body)
|
||||
download = p.downloadPeer()
|
||||
@ -3073,9 +3073,34 @@ def API_Email_Send():
|
||||
attachmentName = f'{u}.conf'
|
||||
|
||||
s, m = EmailSender.send(data.get('Receiver'), data.get('Subject', ''), body,
|
||||
data.get('IncludeAttachment', False), download['fileName'])
|
||||
data.get('IncludeAttachment', False), (download.get('fileName', '') if download else ''))
|
||||
return ResponseObject(s, m)
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/email/previewBody')
|
||||
def API_Email_PreviewBody():
|
||||
data = request.get_json()
|
||||
body = data.get('Body', '')
|
||||
if len(body) == 0:
|
||||
return ResponseObject(False, "Nothing to preview")
|
||||
if ("ConfigurationName" not in data.keys()
|
||||
or "Peer" not in data.keys() or data.get('ConfigurationName') not in WireguardConfigurations.keys()):
|
||||
return ResponseObject(False, "Please specify configuration and peer")
|
||||
|
||||
configuration = WireguardConfigurations.get(data.get('ConfigurationName'))
|
||||
fp, p = configuration.searchPeer(data.get('Peer'))
|
||||
if not fp:
|
||||
return ResponseObject(False, "Peer does not exist")
|
||||
|
||||
try:
|
||||
template = Template(body)
|
||||
download = p.downloadPeer()
|
||||
body = template.render(peer=p.toJson(), configurationFile=download)
|
||||
return ResponseObject(data=body)
|
||||
except Exception as e:
|
||||
return ResponseObject(False, message=str(e))
|
||||
|
||||
|
||||
|
||||
@app.get(f'{APP_PREFIX}/api/systemStatus')
|
||||
def API_SystemStatus():
|
||||
cpu_percpu = psutil.cpu_percent(interval=0.5, percpu=True)
|
||||
|
@ -1,23 +1,28 @@
|
||||
<script setup async>
|
||||
import LocaleText from "@/components/text/localeText.vue";
|
||||
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||
import {reactive, ref} from "vue";
|
||||
import {reactive, ref, watch} from "vue";
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
import PeerShareWithEmailBodyPreview
|
||||
from "@/components/configurationComponents/peerShareLinkComponents/peerShareWithEmailBodyPreview.vue";
|
||||
import {GetLocale} from "@/utilities/locale.js";
|
||||
const props = defineProps(['dataCopy', 'selectedPeer'])
|
||||
const emailIsReady = ref(false)
|
||||
await fetchGet("/api/email/ready", {}, (res) => {
|
||||
emailIsReady.value = res.status
|
||||
})
|
||||
|
||||
const store = DashboardConfigurationStore()
|
||||
const email = reactive({
|
||||
Receiver: "",
|
||||
Body: "",
|
||||
Body: store.Configuration.Email.email_template,
|
||||
Subject: "",
|
||||
IncludeAttachment: false,
|
||||
ConfigurationName: props.selectedPeer.configuration.Name,
|
||||
Peer: props.selectedPeer.id
|
||||
})
|
||||
const store = DashboardConfigurationStore()
|
||||
|
||||
const livePreview = ref(false)
|
||||
|
||||
const sending = ref(false)
|
||||
|
||||
const sendEmail = async () => {
|
||||
@ -32,6 +37,15 @@ const sendEmail = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
const placeholderTranslate = (key) => {
|
||||
return GetLocale(key)
|
||||
}
|
||||
const emits = defineEmits(['fullscreen'])
|
||||
watch(livePreview, () => {
|
||||
console.log(livePreview.value)
|
||||
emits('fullscreen', livePreview.value)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -49,7 +63,7 @@ const sendEmail = async () => {
|
||||
style="padding-left: calc( 0.75rem + 24px )"
|
||||
v-model="email.Receiver"
|
||||
:disabled="sending"
|
||||
placeholder="Send to who?"
|
||||
:placeholder="placeholderTranslate('Send to who?')"
|
||||
required
|
||||
id="email_receiver" aria-describedby="emailHelp">
|
||||
</div>
|
||||
@ -57,22 +71,48 @@ const sendEmail = async () => {
|
||||
<i class="bi bi-hash" style="position: absolute; top: 0.4rem; left: 0.75rem;"></i>
|
||||
<input type="text" class="form-control rounded-0 border-top-0 border-bottom-0"
|
||||
style="padding-left: calc( 0.75rem + 24px )"
|
||||
placeholder="Subject"
|
||||
:placeholder="placeholderTranslate('Subject')"
|
||||
:disabled="sending"
|
||||
v-model="email.Subject"
|
||||
id="email_subject" aria-describedby="emailHelp">
|
||||
</div>
|
||||
<textarea class="form-control rounded-bottom-3 rounded-top-0"
|
||||
v-model="email.Body"
|
||||
:disabled="sending"
|
||||
placeholder="Body"
|
||||
style="min-height: 300px"></textarea>
|
||||
<div class="row g-0">
|
||||
<div :class="[livePreview ? 'col-6' : 'col-12']">
|
||||
<textarea class="form-control rounded-top-0 rounded-bottom-0 font-monospace border-bottom-0"
|
||||
v-model="email.Body"
|
||||
:disabled="sending"
|
||||
:placeholder="placeholderTranslate('Body')"
|
||||
style="height: 400px; max-height: 400px;"></textarea>
|
||||
</div>
|
||||
<div class="col-6" v-if="livePreview">
|
||||
<PeerShareWithEmailBodyPreview
|
||||
:body="email.Body"
|
||||
:selectedPeer="selectedPeer"
|
||||
>
|
||||
</PeerShareWithEmailBodyPreview>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card border-top-0 rounded-top-0 rounded-bottom-3 bg-body-tertiary"
|
||||
style="border: var(--bs-border-width) solid var(--bs-border-color)">
|
||||
<div class="card-body d-flex flex-column gap-2">
|
||||
<div class="form-check form-switch ms-auto">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
v-model="livePreview"
|
||||
role="switch" id="livePreview">
|
||||
<label class="form-check-label" for="livePreview">
|
||||
<LocaleText t="Live Preview"></LocaleText>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
v-model="email.IncludeAttachment"
|
||||
role="switch" id="includeAttachment" checked>
|
||||
role="switch" id="includeAttachment">
|
||||
<label class="form-check-label" for="includeAttachment">
|
||||
<LocaleText t="Include configuration file as an attachment"></LocaleText>
|
||||
</label>
|
||||
@ -102,5 +142,12 @@ const sendEmail = async () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
textarea:focus, input:focus{
|
||||
box-shadow: none;
|
||||
border-color: var(--bs-border-color) !important;
|
||||
}
|
||||
|
||||
textarea{
|
||||
padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x);
|
||||
}
|
||||
</style>
|
@ -0,0 +1,70 @@
|
||||
<script setup>
|
||||
|
||||
import {fetchPost} from "@/utilities/fetch.js";
|
||||
import {ref, watch} from "vue";
|
||||
|
||||
const props = defineProps(['body', 'selectedPeer'])
|
||||
const preview = ref("")
|
||||
const error = ref(false)
|
||||
const errorMsg = ref("")
|
||||
|
||||
|
||||
const getPreview = async () => {
|
||||
if (props.body){
|
||||
error.value = false;
|
||||
preview.value = ("")
|
||||
await fetchPost('/api/email/previewBody', {
|
||||
Body: props.body,
|
||||
ConfigurationName: props.selectedPeer.configuration.Name,
|
||||
Peer: props.selectedPeer.id
|
||||
}, (res) => {
|
||||
|
||||
if (res.status){
|
||||
preview.value = res.data;
|
||||
}else{
|
||||
errorMsg.value = res.message
|
||||
}
|
||||
error.value = !res.status
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
await getPreview();
|
||||
let timeout = undefined
|
||||
watch(() => {
|
||||
return props.body
|
||||
}, async () => {
|
||||
if (timeout === undefined){
|
||||
timeout = setTimeout(async () => {
|
||||
await getPreview();
|
||||
}, 500)
|
||||
}else{
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(async () => {
|
||||
await getPreview();
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card rounded-0 border-start-0 border-bottom-0 bg-body-secondary" style="height: 400px; overflow: scroll">
|
||||
<div class="card-body">
|
||||
<div class="alert alert-danger rounded-3" v-if="error && body">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<span class="font-monospace">
|
||||
{{errorMsg}}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="body"
|
||||
:class="{'opacity-50': error}"
|
||||
:innerText="preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.card{
|
||||
border-color: var(--bs-border-color) !important;
|
||||
}
|
||||
</style>
|
@ -21,7 +21,8 @@ export default {
|
||||
data(){
|
||||
return {
|
||||
dataCopy: undefined,
|
||||
loading: false
|
||||
loading: false,
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
setup(){
|
||||
@ -107,7 +108,7 @@ export default {
|
||||
<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: 700px">
|
||||
<div class="m-auto modal-dialog-centered dashboardModal" :style="[ this.fullscreen ? 'width: 100%' : 'width: 700px']">
|
||||
<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">
|
||||
@ -167,7 +168,9 @@ export default {
|
||||
</button>
|
||||
<hr>
|
||||
<Suspense>
|
||||
<PeerShareWithEmail :selectedPeer="selectedPeer" :dataCopy="dataCopy"></PeerShareWithEmail>
|
||||
<PeerShareWithEmail
|
||||
@fullscreen="(f) => { this.fullscreen = f; }"
|
||||
:selectedPeer="selectedPeer" :dataCopy="dataCopy"></PeerShareWithEmail>
|
||||
<template #fallback>
|
||||
<h6 class="text-muted">
|
||||
<span class="spinner-border me-2 spinner-border-sm" role="status"></span>
|
||||
|
@ -7,7 +7,7 @@ const store = DashboardConfigurationStore()
|
||||
|
||||
onMounted(() => {
|
||||
checkEmailReady()
|
||||
document.querySelectorAll("#emailAccount input, #emailAccount select").forEach(x => {
|
||||
document.querySelectorAll("#emailAccount input, #emailAccount select, #email_template").forEach(x => {
|
||||
x.addEventListener("change", async () => {
|
||||
let id = x.attributes.getNamedItem('id').value;
|
||||
await fetchPost("/api/updateDashboardConfigurationItem", {
|
||||
@ -67,7 +67,7 @@ const sendTestEmail = async () => {
|
||||
</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body d-flex flex-column gap-3">
|
||||
<form @submit="(e) => e.preventDefault(e)" id="emailAccount">
|
||||
<div class="row gx-2 gy-2">
|
||||
<div class="col-12 col-lg-4">
|
||||
@ -152,26 +152,46 @@ const sendTestEmail = async () => {
|
||||
</div>
|
||||
</form>
|
||||
<hr v-if="emailIsReady">
|
||||
<form
|
||||
v-if="emailIsReady"
|
||||
@submit="(e) => {e.preventDefault(); sendTestEmail()}"
|
||||
class="input-group mb-3">
|
||||
|
||||
<input type="email" class="form-control rounded-start-3"
|
||||
v-model="testEmailReceiver"
|
||||
:disabled="testing"
|
||||
placeholder="Test Email Receiver">
|
||||
<button class="btn bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-end-3"
|
||||
type="submit" value="Submit"
|
||||
:disabled="testEmailReceiver.length === 0 || testing"
|
||||
id="button-addon2">
|
||||
<i class="bi bi-send me-2" v-if="!testing"></i>
|
||||
<span class="spinner-border spinner-border-sm me-2" v-else>
|
||||
<div v-if="emailIsReady">
|
||||
<label class="text-muted mb-1" for="test_email">
|
||||
<small class="fw-bold">
|
||||
<LocaleText t="Send Test Email"></LocaleText>
|
||||
</small>
|
||||
</label>
|
||||
<form
|
||||
|
||||
@submit="(e) => {e.preventDefault(); sendTestEmail()}"
|
||||
class="input-group">
|
||||
|
||||
<input type="email" class="form-control rounded-start-3"
|
||||
id="test_email"
|
||||
placeholder="john@example.com"
|
||||
v-model="testEmailReceiver"
|
||||
:disabled="testing">
|
||||
<button class="btn bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-end-3"
|
||||
type="submit" value="Submit"
|
||||
:disabled="testEmailReceiver.length === 0 || testing"
|
||||
id="button-addon2">
|
||||
<i class="bi bi-send me-2" v-if="!testing"></i>
|
||||
<span class="spinner-border spinner-border-sm me-2" v-else>
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</span>
|
||||
<LocaleText :t="!testing ? 'Send Test Email':'Sending...'"></LocaleText>
|
||||
</button>
|
||||
</form>
|
||||
<LocaleText :t="!testing ? 'Send':'Sending...'"></LocaleText>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<label class="text-muted mb-1" for="email_template">
|
||||
<small class="fw-bold">
|
||||
<LocaleText t="Email Body Template"></LocaleText>
|
||||
</small>
|
||||
</label>
|
||||
<textarea class="form-control rounded-3 font-monospace"
|
||||
v-model="store.Configuration.Email.email_template"
|
||||
id="email_template"
|
||||
style="min-height: 400px"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user