version 0.0.1

This commit is contained in:
Simon Zeyer 2024-09-23 22:45:58 +02:00
commit 66760c4325
5 changed files with 656 additions and 0 deletions

129
base.js Normal file
View File

@ -0,0 +1,129 @@
const PluginBaseTemplate = require('./../../templates/pluginBaseTemplate');
const manifest = require('./manifest.json');
const Basedata = require('../../../models/basedata');
const Operation = require('../../../models/core/core_operation');
const Organizations = require('../../../models/organizations');
const Alertdevices = require('../../../models/alertdevices');
const Configuration = require('../../../models/configuration');
const FCMTokens = require('../../../models/fctmtokens');
/**
* Class for DIVERA_STATUS communication
* @class plugins/inbound/divera_status
* @namespace plugins/inbound/divera_status
* @memberof plugins/inbound/divera_status
*/
class divera_status extends PluginBaseTemplate {
/**
* Constructor
*
* Sets up everything, starts service DIVERA_STATUS
*/
constructor() {
super(manifest, __dirname);
this.basedata = new Basedata(global.plgManager.logger);
this.organizations = new Organizations(global.plgManager.logger);
this.alertdevices = new Alertdevices(global.plgManager.logger);
this.configuration = new Configuration(global.plgManager.logger);
this.fcmTokens = new FCMTokens(global.plgManager.logger);
}
/**
* Plugin-specific implementation
*/
newFeedback(feedbackInfo) {
global.plgManager.logger.info('Received new Feedback from REST API', {label: this.logIdentifier});
global.plgManager.event_new_feedback_received(feedbackInfo.operationUUID, feedbackInfo.basedataUUID, feedbackInfo.stateId);
}
/**
* reconfigures DIVERA_STATUS plugin with new config settings
* @param {function} callback success, true or false
* @memberof plugins/inbound/divera_status
*/
initializePlugin(callback) {
this.config = {
AUTOLOGIN_KEY: this.getConfigValue('AUTOLOGIN_KEY'),
STATUS_EB: this.getConfigValue('STATUS_EB'),
STATUS_NEB: this.getConfigValue('STATUS_NEB'),
MONITOR_ID: this.getConfigValue('MONITOR_ID'),
loglevel: 'debug'
}
if (
(typeof this.config.AUTOLOGIN_KEY !== 'undefined') &&
(typeof this.config.status_mapping_use_text !== 'undefined')
//|| (typeof this.config.httpsPort !== 'undefined') && (typeof this.config.runOnHTTPS !== 'undefined')
) {
global.plgManager.logger.info('Properly inititlized settings', {label: this.logIdentifier});
if (this.config.AUTOLOGIN_KEY != '') {
callback(true);
} else {
global.plgManager.logger.error('Could not initialize settings', {label: this.logIdentifier});
callback(false);
}
} else {
global.plgManager.logger.error('Could not initialize settings', {label: this.logIdentifier});
callback(false);
}
}
/**
* Wires messages from service to event model of plugin
* All Messages in service need to be wired here to be recognised in plugin
* @memberof plugins/inbound/divera_status
*/
wireServiceCommunication() {
this.subProcess.on('message', function (msg) {
var payload = [];
try {
payload = JSON.parse(msg);
} catch (err) {
payload = [];
}
if (typeof payload.logmessage != 'undefined') {
msg = payload.logmessage;
}
global.plgManager.logger.info(JSON.stringify(msg), {label: this.logIdentifier});
var payload = null;
try {
payload = JSON.parse(msg);
} catch (err) {
payload = err.message;
}
if (typeof payload.feedbackState != 'undefined') {
var basedataUUID = payload.feedbackState.basedataUUID;
var operationUUID = payload.feedbackState.operationUUID;
var feedbackState = payload.feedbackState.feedbackState;
global.plgManager.event_new_feedback_received(operationUUID, basedataUUID, feedbackState);
global.plgManager.logger.info('Sending new Feedback to PluginManager', {label: this.logIdentifier});
}
if (typeof payload.logmessage != 'undefined') {
global.plgManager.logger.info(payload.logmessage, { label: this.logIdentifier });
} else if (typeof payload.event != 'undefined') {
// service send structured data
if (payload.event.event === 'event_new_feedback') {
var message = payload.event.feedback;
global.plgManager.logger.info('NEW FEEDBACK', {label: this.logIdentifier});
//this.event_new_feedback_received()
} else if (payload.event.event === 'error') {
global.plgManager.logger.error('PLUGIN | RESTAPI | SERVICE | ERROR',{label: this.logIdentifier});
global.plgManager.logger.error('ERROR ' + JSON.stringify(payload.event.error), {label: this.logIdentifier});
global.plgManager.event_new_admin_notification('REST API Fehler: ' + JSON.stringify(payload.event.error));
this.executeServiceRestartRoutine();
}
} else {
global.plgManager.logger.info('UNSOLICITED MESSAGE: ' + JSON.stringify(msg), {label: this.logIdentifier});
}
}.bind(this));
}
}
module.exports = divera_status;

50
manifest.json Normal file
View File

@ -0,0 +1,50 @@
{
"name": "Divera Status",
"version": "0.0.1",
"description": "Übernehmen des Status aus der Divera App in Alarmiator",
"main": "base.js",
"service": "service.js",
"namespace" : "divera_status",
"logidentifier" : "DIVERA_STATUS",
"author": "Simon Zeyer",
"plgtype": "inbound",
"isService" : true,
"configstore" : {
"fields" : [
{
"fieldname" : "AUTOLOGIN_KEY",
"label" : "Monitor Autologin key",
"description" : "Auto-Login-Key eines Monitor, der den Status der Nutzer sehen darf.",
"presetvalue" : "",
"type" : "string",
"mandantory" : true
},
{
"fieldname" : "STATUS_EB",
"label" : "Status für Einsatzbereit",
"description" : "Aktiviert alle seine Gruppen in ALARMIATOR wenn User in Divera diesen Status erhällt (Geofence z.B.)",
"presetvalue" : "",
"type" : "string",
"mandantory" : false
},
{
"fieldname" : "STATUS_NEB",
"label" : "Status für nicht Einsatzbereit",
"description" : "Deaktiviert alle seine Gruppen in ALARMIATOR wenn User in Divera diesen Status erhällt (Geofence z.B.)",
"presetvalue" : "",
"type" : "string",
"mandantory" : false
},
{
"fieldname" : "MONITOR_ID",
"label" : "ID des Monitor",
"description" : "Normalerweise 1",
"presetvalue" : "1",
"type" : "string",
"mandantory" : true
}
]
},
"alarmingByUser" : false
}

209
package-lock.json generated Normal file
View File

@ -0,0 +1,209 @@
{
"name": "alarmiator_divera_status",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "alarmiator_divera_status",
"version": "0.0.1",
"dependencies": {
"axios": "^1.7.7",
"axios-cookiejar-support": "^5.0.2"
}
},
"node_modules/agent-base": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
"dependencies": {
"debug": "^4.3.4"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios-cookiejar-support": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-5.0.2.tgz",
"integrity": "sha512-4KwFqiH62Ry/J+ue1NwqLvBSaK3Bp/Owc9jTe7BS9c22uN8/4MB5pY7HV9QwQjV3ZRonCoSj5V8Pjx911qQqAw==",
"dependencies": {
"http-cookie-agent": "^6.0.5"
},
"engines": {
"node": ">=18.0.0"
},
"funding": {
"url": "https://github.com/sponsors/3846masa"
},
"peerDependencies": {
"axios": ">=0.20.0",
"tough-cookie": ">=4.0.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/http-cookie-agent": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.6.tgz",
"integrity": "sha512-XkwhYUWo0yhiHBWqLmAe2kIBymVY70ewi9sKmy6YBHpNU3BCH4nipKrtY5/effAxj0qneQ9ziZG5TXgaKLfYgg==",
"dependencies": {
"agent-base": "^7.1.1"
},
"engines": {
"node": ">=18.0.0"
},
"funding": {
"url": "https://github.com/sponsors/3846masa"
},
"peerDependencies": {
"tough-cookie": "^4.0.0 || ^5.0.0",
"undici": "^5.11.0 || ^6.0.0"
},
"peerDependenciesMeta": {
"undici": {
"optional": true
}
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/tldts": {
"version": "6.1.47",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.47.tgz",
"integrity": "sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==",
"peer": true,
"dependencies": {
"tldts-core": "^6.1.47"
},
"bin": {
"tldts": "bin/cli.js"
}
},
"node_modules/tldts-core": {
"version": "6.1.47",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz",
"integrity": "sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA==",
"peer": true
},
"node_modules/tough-cookie": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
"integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
"peer": true,
"dependencies": {
"tldts": "^6.1.32"
},
"engines": {
"node": ">=16"
}
}
}
}

18
package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "alarmiator_divera_status",
"version": "0.0.1",
"private": true,
"description": "Divera status to Alarmiator",
"keywords": [],
"author": "",
"license": "",
"main": "service.js",
"scripts": {
"start": "node service.js",
"test": "swagger project test"
},
"dependencies": {
"axios": "^1.7.7",
"axios-cookiejar-support": "^5.0.2"
}
}

250
service.js Normal file
View File

@ -0,0 +1,250 @@
var Database = require('../../../models/database');
var manifest = require('./manifest.json');
const { createWinstonLogger } = require('../../../utils/logging');
const Basedata = require('../../../models/basedata');
const Feedbackstates = require('../../../models/feedbackstates');
const Feedbackstore = require('../../../models/core/feedbackstore');
const Operations = require('../../../models/operationshelper');
const Groups = require('../../../models/groups');
// axios session
const axios = require('axios').default;
const { CookieJar } = require('tough-cookie');
const { wrapper } = require('axios-cookiejar-support');
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
global.manifest = manifest;
global.apiAdress = null;
var serviceState = 0;
var config = null;
var pulled_data = {};
const AUTH_ENDPOINT = "https://app.divera247.com/monitor/"
const PULL_ENDPOINT = "https://app.divera247.com/api/pull"
async function getFeedbackStateIDbyName(name){
return new Promise((resolve, reject) => {
var feedbackstates = new Feedbackstates(global.logger);
feedbackstates.getAllActiveStates((rows)=>{
if(rows !== null){
rows.forEach((e)=>{
if(name == e.stateLabel){
resolve(e.id)
}
})
}
resolve(null)
})
});
}
function setFeedback(operationUUID, basedataUUID, feedbackState) {
var feedbackstore = new Feedbackstore(global.logger);
global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | persisting feedback now ..');
feedbackstore.setFeedback(basedataUUID, operationUUID, feedbackState, (success) => {
if (success) {
global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | successfully persisted feedback');
var feedbackInfo = {
basedataUUID: basedataUUID,
operationUUID: operationUUID,
feedbackState: feedbackState
}
var sendMessage = {
feedbackState : feedbackInfo
}
process.send(JSON.stringify(sendMessage));
} else {
global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | ERROR - Could not persist feedback');
}
})
}
async function getMemberByName(firstname,lastname){
return new Promise((resolve, reject) => {
new Basedata(global.logger).getListOfBasedata((rows)=>{
if(rows !== null){
rows.forEach((e)=> {
if(e.firstname == firstname && e.lastname == lastname){
resolve(e.uuid)
}
})
}
resolve(null)
})
});
}
async function setGroupsMutedStateForMember(member_guid, muted = false){
var b= new Basedata(global.logger)
b.getBaseDataForUUID(member_guid,(_rows)=> {
if(_rows !== null){
_rows.forEach((_e)=>{
var g = new Groups(global.logger)
g.setAllGroupsMutedStateForBasedata(_e.id,muted?1:0,(success)=>{})
})
}
})
}
async function getActiveOperation(){
return new Promise((resolve, reject) => {
new Operations(global.logger).getListOfActiveOperations((rows)=>{
if(rows !== null && rows.length > 0){
resolve(rows[0].uuid)
}
resolve(null)
})
});
}
/**
* Log Function for inter process communication
*/
function LogAtMain(msg) {
process.send('{"logmessage" : "' + msg + '"}');
}
/**
*
* Wire messages coming from Plugin base.js
*
*/
process.on('message', (msg) => {
if (typeof msg.config != 'undefined') {
config = msg.config;
global.apiAdress = config.apiAdress || null;
serviceState = 1;
LogAtMain('Recieved Configuration from CORE');
} else if (typeof msg.start != 'undefined') {
if (msg.start === 1) {
startAPI();
}
}
});
// GENERIC Error Handling
process.on('unhandledRejection', (reason, p) => {
console.log('PLUGIN | DIVERA_STATUS | Unhandled Rejection at: Promise', p, 'reason:', reason.stack);
LogAtMain('Unhandled Rejection at: Promise', p, 'reason:', reason.stack);
});
process.on('uncaughtException', function (err) {
console.log('PLUGIN | DIVERA_STATUS | Caught exception: ' + err);
process.send('{"error" : "' + err.message + '"}');
});
/**
* Start API Logger
*/
// create a rolling file logger based on date/time that fires process events
global.appRoot = __dirname + '/../../../';
global.logger = createWinstonLogger('DIVERA_STATUS ', global.appRoot + '/logs/api/DIVERA_STATUS-%DATE%.log');
global.logger.info('Started DIVERA_STATUS Sync', {label: 'APPJS '});
/**
* connect to database
*/
var coreDb = new Database(global.logger);
coreDb.openCoreDatabase((successDatabase) => {
if (successDatabase) {
global.coreDb = coreDb.db;
global.logger.info('database started', {label: 'APPJS '});
} else {
global.logger.error('Could not connect to database', {label: 'APPJS '});
}
});
async function auth(){
let resp = await client.get(`${AUTH_ENDPOINT}${config.MONITOR_ID}.html?autologin=${config.AUTOLOGIN_KEY}`)
if(resp.status === 200){
return true
}
return false
}
async function pull(){
let resp = await client.get(`${PULL_ENDPOINT}?ts=0`)
if(resp.status === 200){
return resp.data
}
return null
}
async function onStateChange(consumer_id, status_id){
var d_consumer = pulled_data['consumer'][consumer_id]
var d_status = pulled_data['status'][status_id]
global.logger.info(`${d_consumer['stdformat_name']}: ${d_status['name']}`)
let a_consumer = await getMemberByName(d_consumer.firstname, d_consumer.lastname)
if(a_consumer === null){
global.logger.debug(`basedata nicht gefunden`)
return
}
let a_status = await getFeedbackStateIDbyName(d_status['name'])
if(a_status !== null){
// Status ist eine Rückmeldung
let a_operation = await getActiveOperation()
if(a_consumer === null){
global.logger.debug(`kein aktiver alarm`)
return
}
setFeedback(a_operation, a_consumer, a_status)
}else{
// Status auf einsatzbereit/nicht einsatzbereit prüfen
if(config.STATUS_EB == d_status['name']){
//Alle Gruppen alamieren
setGroupsMutedStateForMember(a_consumer,false)
}
if(config.STATUS_NEB == d_status['name']){
//Alle Gruppen alamieren deaktivieren
setGroupsMutedStateForMember(a_consumer,true)
}
}
}
async function startAPI() {
let _auth = await auth()
if(_auth){
global.logger.info('auth OK')
var _pulled_data = await pull()
while(_pulled_data !== null){
if(_pulled_data !== null){
if(_pulled_data.success){
var d = _pulled_data.data
if('cluster' in d){
pulled_data['consumer'] = d['cluster']['consumer']
pulled_data['status'] = d['cluster']['status']
}
if('monitor' in d){
var m = d['monitor'][config.MONITOR_ID]
Object.entries(m).forEach(([key, value]) => {
if(!('monitor' in pulled_data) || ('monitor' in pulled_data && value.status !== pulled_data['monitor'][key]['status'])){
onStateChange(value.id,value.status )
}
});
pulled_data['monitor'] = d['monitor'][config.MONITOR_ID]
}
}
}
_pulled_data = await pull()
if(_pulled_data === null){
global.logger.info('_pulled_data === null, reauth')
_auth = await auth()
_pulled_data = await pull()
if(_pulled_data === null){
global.logger.info('_pulled_data === null after reauth, EXIT!!')
}
}
}
}
}