initial commit
parent
30c1adf506
commit
f5ddd0a0a6
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"pager": {
|
||||||
|
"url": "http://127.0.0.1:3000/api/message/preset"
|
||||||
|
},
|
||||||
|
"deliveryModes": [
|
||||||
|
{
|
||||||
|
"name": "Normal Duplex",
|
||||||
|
"preset": "184cdb82b05"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,145 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Webform Configuration</title>
|
||||||
|
<!-- <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> -->
|
||||||
|
<link href="css/materialdesignicons.min.css" rel="stylesheet">
|
||||||
|
<link href="css/vuetify.min.css" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<v-app>
|
||||||
|
<v-app-bar app>
|
||||||
|
<v-toolbar-title>Webform Configuration</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="success" @click="storeConfig()">Store & Restart</v-btn>
|
||||||
|
<v-checkbox label="Expert Mode" v-model="EXPERTMODE"></v-checkbox>
|
||||||
|
</v-app-bar>
|
||||||
|
<v-content>
|
||||||
|
<v-form>
|
||||||
|
<v-tabs v-model="configTab" next-icon="mdi-arrow-right-bold-box-outline" prev-icon="mdi-arrow-left-bold-box-outline" show-arrows>
|
||||||
|
<v-tab key="botSettings">Form Settings</v-tab>
|
||||||
|
<v-tab v-show="EXPERTMODE" key="notificationConfig">Notification Configuration</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
<v-tabs-items v-model="configTab">
|
||||||
|
<v-tab-item key="botSettings">
|
||||||
|
<v-container>
|
||||||
|
<p>Targets:</p>
|
||||||
|
<v-row>
|
||||||
|
<v-btn color="success" @click="addDeliveryMode()">Add</v-btn>
|
||||||
|
</v-row>
|
||||||
|
<v-row v-for="(deliveryMode, index) in configData.deliveryModes" :key="deliveryMode._id" style="border-bottom: 2px solid black;">
|
||||||
|
<pre>Index: {{ index }}</pre>
|
||||||
|
<v-col cols="12" sm="12" md="12">
|
||||||
|
<v-btn color="error" @click="configData.deliveryModes.splice(index, 1)" icon><v-icon>mdi-delete</v-icon></v-btn>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="6" sm="6" md="4">
|
||||||
|
<v-text-field v-model="deliveryMode.name" label="Name"></v-text-field>
|
||||||
|
<v-autocomplete
|
||||||
|
v-model="deliveryMode.preset"
|
||||||
|
:items="presetSearchItems"
|
||||||
|
:loading="!presetSearchItems.length > 0"
|
||||||
|
color="white"
|
||||||
|
hide-no-data
|
||||||
|
dense
|
||||||
|
label="Profile"
|
||||||
|
placeholder="Start typing to Search"
|
||||||
|
prepend-icon="mdi-database-search"
|
||||||
|
></v-autocomplete>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</v-tab-item>
|
||||||
|
<v-tab-item key="notificationConfig">
|
||||||
|
<v-container>
|
||||||
|
<b>Routing Paramters:</b>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" sm="12" md="6">
|
||||||
|
<v-text-field label="Daemon Endpoint URL" v-model="configData.pager.url"></v-text-field>
|
||||||
|
</v-col>
|
||||||
|
</v-container>
|
||||||
|
</v-tab-item>
|
||||||
|
</v-tabs-items>
|
||||||
|
</v-form>
|
||||||
|
</v-content>
|
||||||
|
</v-app>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="js/vue/vue.js"></script>
|
||||||
|
<script src="js/vue/vuetify.js"></script>
|
||||||
|
<script src="js/vue/vue-resource_1.5.1.js"></script>
|
||||||
|
<script>
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
vuetify: new Vuetify(),
|
||||||
|
http: { root: '/' },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
EXPERTMODE: false,
|
||||||
|
configTab: null,
|
||||||
|
configData: {
|
||||||
|
"bottoken": "",
|
||||||
|
"pager": {
|
||||||
|
"url": "",
|
||||||
|
},
|
||||||
|
"menuSupport": false,
|
||||||
|
"deliveryModes": []
|
||||||
|
},
|
||||||
|
presetSearchItems: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadPresets()
|
||||||
|
this.loadConfig()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadPresets() {
|
||||||
|
this.$http.get('/api/deliveryPresets')
|
||||||
|
.then(response => {
|
||||||
|
this.presetSearchItems = response.body.map(x => { return {
|
||||||
|
text: x.name,
|
||||||
|
value: x.key,
|
||||||
|
}})
|
||||||
|
}, response => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadConfig() {
|
||||||
|
this.$http.get('/config').then(response => {
|
||||||
|
const newConfig = response.body
|
||||||
|
newConfig.deliveryModes = newConfig.deliveryModes.map((x) => {
|
||||||
|
x._id = btoa(JSON.stringify(x))
|
||||||
|
return x
|
||||||
|
})
|
||||||
|
this.configData = newConfig
|
||||||
|
}, response => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
storeConfig() {
|
||||||
|
const storeConfig = JSON.parse(JSON.stringify(this.configData))
|
||||||
|
storeConfig.deliveryModes = storeConfig.deliveryModes.map((x) => {
|
||||||
|
delete x._id
|
||||||
|
return x
|
||||||
|
})
|
||||||
|
this.$http.post('/config', storeConfig).then(response => {
|
||||||
|
})
|
||||||
|
.then(this.$http.post('/restart'))
|
||||||
|
.then(() => {
|
||||||
|
document.body.style = 'display:none'
|
||||||
|
setTimeout(() => window.location.reload(), 1e3)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addDeliveryMode() {
|
||||||
|
this.configData.deliveryModes.push({
|
||||||
|
name: "",
|
||||||
|
preset: null
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,262 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>smartpager.network Webform</title>
|
||||||
|
<!-- <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> -->
|
||||||
|
<link href="css/materialdesignicons.min.css" rel="stylesheet">
|
||||||
|
<link href="css/vuetify.min.css" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<v-app>
|
||||||
|
<v-app-bar app>
|
||||||
|
<v-toolbar-title>Webform</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<span>SmartPager Framework made with 🧡 by cheetah.cat - uses BOSKrypt AES256 Encryption </span>
|
||||||
|
<v-img src="ready.png" max-width="96px" max-height="48px"></v-img>
|
||||||
|
</v-app-bar>
|
||||||
|
<v-content>
|
||||||
|
<v-container> <!-- Device List-->
|
||||||
|
<v-data-table must-sort :footer-props="footerProps"
|
||||||
|
:options="options" :loading="loadingD" loading-text="Loading... Please wait"
|
||||||
|
:headers="devicesHeaders" item-key="_id" :items="deviceListData"
|
||||||
|
:single-expand="singleExpand" item-key="name" show-expand
|
||||||
|
class="elevation-1">
|
||||||
|
<template v-slot:top>
|
||||||
|
<v-toolbar flat>
|
||||||
|
<v-toolbar-title>Device List</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
</template>
|
||||||
|
<template v-slot:no-data>
|
||||||
|
No Devices to show
|
||||||
|
</template>
|
||||||
|
<template v-slot:expanded-item="{ headers, item }">
|
||||||
|
<td :colspan="headers.length">
|
||||||
|
<section v-if="item.deviceType == 'birdyslim'">
|
||||||
|
<pre>Device ID: {{ item.deviceID }}</pre>
|
||||||
|
<pre v-if="!!item.poweredOn">Powered On: {{ item.poweredOn }}</pre>
|
||||||
|
<pre v-if="!!item.isCharging">Charging: {{ item.isCharging }}</pre>
|
||||||
|
<pre v-if="!!item.battery">Battery: {{ item.battery }}</pre>
|
||||||
|
<pre v-if="!!item.lastSeen">Last Seen: {{ item.lastSeen }}</pre>
|
||||||
|
<pre v-if="!!item.rssi">POCSAG RSSI: -{{ item.rssi }}dBm</pre>
|
||||||
|
<pre v-if="!!item.gps">GPS Position:
|
||||||
|
Lat: {{ item.gps.latitude }}
|
||||||
|
Lng: {{ item.gps.longitude }}
|
||||||
|
Last Acquisition: {{ item.gps.lastGPSAcquisition }}m ago
|
||||||
|
</pre>
|
||||||
|
<pre v-if="!!item.lastLoRaPacket">
|
||||||
|
Last LoRaWAN Packet:
|
||||||
|
{{ item.lastLoRaPacket }}
|
||||||
|
</pre>
|
||||||
|
</section>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</v-container>
|
||||||
|
<hr>
|
||||||
|
<v-container> <!-- Recent Messages -->
|
||||||
|
<v-data-table must-sort :footer-props="footerProps"
|
||||||
|
:options="options" :loading="loadingM" loading-text="Loading... Please wait"
|
||||||
|
:headers="recentMessagesHeaders" item-key="id" :items="recentMessageListData" :items-per-page="5"
|
||||||
|
:single-expand="singleExpandRM" item-key="name" show-expand
|
||||||
|
class="elevation-1">
|
||||||
|
<template v-slot:top>
|
||||||
|
<v-toolbar flat>
|
||||||
|
<v-toolbar-title>Message History</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<v-dialog v-model="dialogNewMessage" fullscreen hide-overlay transition="dialog-bottom-transition">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-btn color="primary" v-bind="attrs" v-on="on">
|
||||||
|
<v-icon>mdi-email</v-icon>
|
||||||
|
New Message
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-card>
|
||||||
|
<v-toolbar dark color="primary">
|
||||||
|
<v-btn icon dark @click="dialogNewMessage = false">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>New Message</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" sm="12" md="6">
|
||||||
|
<v-autocomplete
|
||||||
|
v-model="newMSGData.preset"
|
||||||
|
:items="presetSearchItems"
|
||||||
|
:loading="!presetSearchItems.length > 0"
|
||||||
|
color="white"
|
||||||
|
hide-no-data
|
||||||
|
dense
|
||||||
|
label="Profile"
|
||||||
|
placeholder="Start typing to Search"
|
||||||
|
prepend-icon="mdi-database-search"
|
||||||
|
></v-autocomplete>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" sm="12" md="6">
|
||||||
|
<span>
|
||||||
|
Please leave a reference/name!
|
||||||
|
</span>
|
||||||
|
<v-textarea v-model="newMSGData.payload" label="Message"></v-select>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" sm="12" md="6">
|
||||||
|
<v-btn color="success" dark text @click="testMsg_send()">Send</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</v-toolbar>
|
||||||
|
</template>
|
||||||
|
<template v-slot:no-data>
|
||||||
|
No Messages to show, you can send one using the 'New Message' Button
|
||||||
|
</template>
|
||||||
|
<template v-slot:expanded-item="{ headers, item }">
|
||||||
|
<td :colspan="headers.length">
|
||||||
|
<pre>{{ item }}</pre>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
</v-app>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="js/vue/vue.js"></script>
|
||||||
|
<script src="js/vue/vuetify.js"></script>
|
||||||
|
<script src="js/vue/vue-resource_1.5.1.js"></script>
|
||||||
|
<script>
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
vuetify: new Vuetify(),
|
||||||
|
http: { root: '/' },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
EXPERTMODE:false,
|
||||||
|
|
||||||
|
dialogNewMessage: false,
|
||||||
|
presetSearchItems: [],
|
||||||
|
|
||||||
|
loadingD: true,
|
||||||
|
loadingM: false,
|
||||||
|
search: '',
|
||||||
|
expanded: [],
|
||||||
|
singleExpand: true,
|
||||||
|
singleExpandRM: true,
|
||||||
|
options: {
|
||||||
|
itemsPerPage: -1,
|
||||||
|
},
|
||||||
|
footerProps: {
|
||||||
|
itemsPerPageOptions: [ -1, 5, 10, 20, 50, 75, 100 ]
|
||||||
|
},
|
||||||
|
devicesHeaders: [
|
||||||
|
{ text: 'ID', align: 'start', groupable: false, sortable: false, value: 'deviceID', },
|
||||||
|
{ text: 'Type', value: 'deviceType', groupable: true },
|
||||||
|
{ text: 'Last Seen', value: 'lastSeen', groupable: false },
|
||||||
|
],
|
||||||
|
newMSGData: {
|
||||||
|
pager: {
|
||||||
|
payload: "Test Message",
|
||||||
|
},
|
||||||
|
preset: null,
|
||||||
|
},
|
||||||
|
lastMSGLog: null,
|
||||||
|
messagesCheckList: [],
|
||||||
|
deviceListData: [],
|
||||||
|
|
||||||
|
recentMessageListData: [],
|
||||||
|
recentMessagesHeaders: [
|
||||||
|
{ text: 'ID', align: 'start', groupable: false, sortable: false, value: 'id', },
|
||||||
|
{ text: 'Type', value: 'type', groupable: true, sortable: false },
|
||||||
|
{ text: 'State', value: 'state', groupable: false, sortable: false },
|
||||||
|
{ text: 'Date', value: 'date', groupable: false, sortable: false },
|
||||||
|
{ text: 'Message', value: '_payload', groupable: false, sortable: false },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.refreshDevices()
|
||||||
|
setInterval(this.refreshDevices, 1e3)
|
||||||
|
|
||||||
|
this.refreshMessages()
|
||||||
|
setInterval(this.refreshMessages, 1e3)
|
||||||
|
|
||||||
|
this.$http.get('/api/modes')
|
||||||
|
.then(response => {
|
||||||
|
console.log(response.body)
|
||||||
|
this.presetSearchItems = response.body.map(x => { return {
|
||||||
|
text: x.name,
|
||||||
|
value: x.preset,
|
||||||
|
//Description
|
||||||
|
}})
|
||||||
|
}, response => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refreshDevices() {
|
||||||
|
this.$http.get('/api/devices').then(response => {
|
||||||
|
this.deviceListData = Object.keys(response.body).map(key => {
|
||||||
|
const item = response.body[ key ]
|
||||||
|
const keyData = key.split(':')
|
||||||
|
item.deviceType = keyData[ 0 ], item.deviceID = keyData[ 1 ]
|
||||||
|
|
||||||
|
item.lastSeen = new Date(item.lastSeen).toLocaleString()
|
||||||
|
//item.validStateText = this.validStateLUT[item.validState]
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
//this.accountData.sort((a,b) => a.validState - b.validState)
|
||||||
|
this.loadingD = false
|
||||||
|
}, response => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshMessages() {
|
||||||
|
if (this.messagesCheckList.length == 0) return
|
||||||
|
this.$http.get('/api/message/status', { params: {
|
||||||
|
ids: this.messagesCheckList
|
||||||
|
} }).then(response => {
|
||||||
|
this.recentMessageListData = response.body.map(msg => {
|
||||||
|
const stateArray = [msg._routerData.recvAck, msg._routerData.readAck, msg._routerData.response]
|
||||||
|
// msg.state = [ msg.type, stateArray.filter(x=>x!==false).length, ...stateArray ]
|
||||||
|
msg.state = '-'
|
||||||
|
if (msg.type === 'duplex') {
|
||||||
|
switch (stateArray.filter(x=>x!==false).length) {
|
||||||
|
case 0: msg.state = '📨 Sent'; break;
|
||||||
|
case 1: msg.state = '📬 Received'; break;
|
||||||
|
case 2: msg.state = '👀 Read'; break;
|
||||||
|
case 3: msg.state = '💬 Responded'; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.date = new Date(msg.date).toLocaleString()
|
||||||
|
return msg
|
||||||
|
})
|
||||||
|
this.loadingM = false
|
||||||
|
}, response => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
testMsg_send() {
|
||||||
|
console.log(this.newMSGData.preset)
|
||||||
|
this.$http.post('/api/message/preset/',
|
||||||
|
Object.assign({ preset: this.newMSGData.preset }, { payload: this.newMSGData.payload })
|
||||||
|
).then(x=>{
|
||||||
|
console.log('response', x)
|
||||||
|
this.messagesCheckList.push(x.body)
|
||||||
|
this.dialogNewMessage = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 128 KiB |
@ -0,0 +1,177 @@
|
|||||||
|
const config = require('./config.json')
|
||||||
|
|
||||||
|
const io = require("socket.io-client")
|
||||||
|
const axios = require('axios')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
function filter(txt) {
|
||||||
|
if (txt.length > 240) txt = txt.substring(0, 240)
|
||||||
|
return txt.replace(/[^\x00-\x7F]/g, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function editStatus(msgId, msg) {
|
||||||
|
if (!assoc[msgId]) return
|
||||||
|
const sPass = Math.floor( (new Date().valueOf() - assoc[msgId].date.valueOf() ) / 1e3)
|
||||||
|
msg = `+${ sPass }s> ${ msg }`
|
||||||
|
|
||||||
|
console.log(assoc[msgId])
|
||||||
|
const [tgChatId, tgMsgId] = [assoc[msgId].tgchat, assoc[msgId].tgmsg]
|
||||||
|
assoc[msgId].newText = assoc[msgId].newText + '\n' + msg
|
||||||
|
console.log(assoc[msgId])
|
||||||
|
bot.telegram.editMessageText(tgChatId, tgMsgId, null, assoc[msgId].newText).then(console.log)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
socket.on('msgmgr:event', (eventType, eventData) => {
|
||||||
|
console.log(eventType, eventData)
|
||||||
|
switch (eventType) {
|
||||||
|
case 'status': {
|
||||||
|
const [msgId, uuid, status] = eventData
|
||||||
|
editStatus(msgId, `${ uuid } is ${ status }`)
|
||||||
|
} break;
|
||||||
|
case 'read':
|
||||||
|
editStatus(eventData, 'read')
|
||||||
|
break;
|
||||||
|
case 'response': {
|
||||||
|
const [msgId, response] = eventData
|
||||||
|
editStatus(msgId, 'response ' + response)
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bot.on('message', (ctx) => {
|
||||||
|
if (!ctx.update.message.text) return ctx.reply("not a textmessage")
|
||||||
|
// if (!ctx.update.message.type)
|
||||||
|
console.log(ctx.update.message.from)
|
||||||
|
const preview = `Preview: ${ filter(ctx.update.message.from.first_name) }:${ filter(ctx.update.message.text) }`
|
||||||
|
console.log(preview)
|
||||||
|
ctx.reply(preview, Markup.inlineKeyboard(
|
||||||
|
config.deliveryModes.map((deliveryModeConfig, index) =>
|
||||||
|
Markup.button.callback(deliveryModeConfig.name, 'deliveryMode-' + index)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let deliveryModeIndex in config.deliveryModes) {
|
||||||
|
bot.action('deliveryMode-' + deliveryModeIndex, async (ctx) => {
|
||||||
|
const origText = ctx.update.callback_query.message.text.substring(8+1)
|
||||||
|
await ctx.answerCbQuery()
|
||||||
|
await ctx.editMessageReplyMarkup(undefined)
|
||||||
|
|
||||||
|
const deliveryModeData = config.deliveryModes[ deliveryModeIndex ]
|
||||||
|
|
||||||
|
let msgId = (
|
||||||
|
await axios.post(
|
||||||
|
new URL(config.pager.url).origin + '/api/message/' + (!!deliveryModeData.preset ? 'preset' : 'advanced'),
|
||||||
|
Object.assign( !!deliveryModeData.preset
|
||||||
|
? { preset: deliveryModeData.preset } // backward compatibility
|
||||||
|
: { ...deliveryModeData.params }
|
||||||
|
, {
|
||||||
|
payload: origText
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).data
|
||||||
|
assoc[msgId] = {
|
||||||
|
date: new Date(),
|
||||||
|
tgmsg: ctx.update.callback_query.message.message_id,
|
||||||
|
text: origText,
|
||||||
|
newText: `Preview: ${ origText }\n\n--[${ msgId }]--\n`,
|
||||||
|
tgchat: ctx.update.callback_query.message.chat.id
|
||||||
|
}
|
||||||
|
await ctx.editMessageText(assoc[msgId].newText)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const express = require('express')
|
||||||
|
const { query } = require('express')
|
||||||
|
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
app.use(express.json())
|
||||||
|
app.use(express.static('html_public'))
|
||||||
|
app.use(express.static(__dirname + '/node_modules/@mdi/font'))
|
||||||
|
|
||||||
|
const allowedIDs = []
|
||||||
|
|
||||||
|
app.get('/api/modes', async (req, res) => {
|
||||||
|
return res.json(config.deliveryModes)
|
||||||
|
})
|
||||||
|
app.get('/api/devices', async (req, res) => {
|
||||||
|
const devices = (await axios.get(new URL(config.pager.url).origin + '/api/devices')).data
|
||||||
|
Object.keys(devices).map(key => {
|
||||||
|
devices[ key ].lastLoRaPacket = !!devices[ key ].lastLoRaPacket
|
||||||
|
? {
|
||||||
|
received_at: devices[ key ].lastLoRaPacket.received_at,
|
||||||
|
} : null
|
||||||
|
})
|
||||||
|
return res.json(devices)
|
||||||
|
})
|
||||||
|
app.get('/api/message/status', async (req, res) => {
|
||||||
|
if (!req.query.ids) return res.status(500).json("ERROR: no ids")
|
||||||
|
const queryIDs = req.query.ids
|
||||||
|
if (queryIDs.length > 3) queryIds = queryIDs.slice(0,3)
|
||||||
|
let results = []
|
||||||
|
for (let msgID of queryIDs) {
|
||||||
|
if (allowedIDs.indexOf(msgID) > -1)
|
||||||
|
try {
|
||||||
|
let msgStatus = (
|
||||||
|
await axios.get(new URL(config.pager.url).origin + '/api/message/status/' + msgID)
|
||||||
|
).data
|
||||||
|
|
||||||
|
if (!!msgStatus._routerData && !!msgStatus._routerData.metadata) {
|
||||||
|
msgStatus._routerData.metadata = msgStatus._routerData.metadata.map(x => {
|
||||||
|
if (x.ack == 'operational') {
|
||||||
|
try {
|
||||||
|
x.operationalData = x.metadata.uplink_message.decoded_payload.operationalData
|
||||||
|
} catch (ee) {}
|
||||||
|
}
|
||||||
|
delete x.metadata
|
||||||
|
return x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
results.push(msgStatus)
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.json(results)
|
||||||
|
})
|
||||||
|
app.post('/api/message/preset', async (req, res) => {
|
||||||
|
if (!req.body.preset) return res.status(500).json("ERROR: no msg preset")
|
||||||
|
if (!req.body.payload) return res.status(500).json("ERROR: no msg payload")
|
||||||
|
|
||||||
|
if (config.deliveryModes.filter(a=>a.preset == req.body.preset).length !== 1) return res.status(500).json("ERROR: mode does not exist")
|
||||||
|
|
||||||
|
let msgId = (
|
||||||
|
await axios.post(config.pager.url, { preset: req.body.preset, payload: req.body.payload })
|
||||||
|
).data
|
||||||
|
allowedIDs.push(msgId)
|
||||||
|
return res.json(msgId)
|
||||||
|
})
|
||||||
|
app.listen(3091, '0.0.0.0' || config.host || '127.0.0.1')
|
||||||
|
|
||||||
|
const appConfig = express()
|
||||||
|
appConfig.use(express.json())
|
||||||
|
appConfig.use(express.static('html_config'))
|
||||||
|
appConfig.use(express.static(__dirname + '/node_modules/@mdi/font'))
|
||||||
|
|
||||||
|
/** CONFIG Routes */
|
||||||
|
|
||||||
|
appConfig.get('/config', async (req, res) => {
|
||||||
|
return res.json(JSON.parse(fs.readFileSync('config.json')))
|
||||||
|
})
|
||||||
|
appConfig.get('/api/deliveryPresets', async (req, res) => {
|
||||||
|
const presets = await axios.get(new URL(config.pager.url).origin + '/api/deliveryPresets')
|
||||||
|
return res.json(presets.data)
|
||||||
|
})
|
||||||
|
appConfig.post('/config', async (req, res) => {
|
||||||
|
if (!(!!req.body.deliveryModes)) return res.status(403).json(false)
|
||||||
|
if (!(!!req.body.pager)) return res.status(403).json(false)
|
||||||
|
console.log(req.body)
|
||||||
|
fs.writeFileSync('config.json', JSON.stringify(req.body, null, "\t"))
|
||||||
|
return res.json(true)
|
||||||
|
})
|
||||||
|
appConfig.post('/restart', (req, res) => {
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
appConfig.listen(3090, '0.0.0.0' || config.host || '127.0.0.1')
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@mdi/font": "^7.0.96",
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"socket.io-client": "^4.0.2"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue