update Di 16. Jun 09:31:02 CEST 2020
This commit is contained in:
parent
de2a953acc
commit
95c723485f
18
server.js
18
server.js
@ -21,6 +21,14 @@ const { v4: uuidv4 } = require('uuid');
|
|||||||
var app_cfg = require('./server/app_cfg.js');
|
var app_cfg = require('./server/app_cfg.js');
|
||||||
app_cfg.global.app_id = uuidv4();
|
app_cfg.global.app_id = uuidv4();
|
||||||
|
|
||||||
|
// Remote-Api aktivieren
|
||||||
|
var remote_api;
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
remote_api = io_api.connect(app_cfg.endpoint.host, {
|
||||||
|
reconnect: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Express-Einstellungen
|
// Express-Einstellungen
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
app.locals.basedir = app.get('views');
|
app.locals.basedir = app.get('views');
|
||||||
@ -35,20 +43,12 @@ app.use(bodyParser.urlencoded({
|
|||||||
extended: false
|
extended: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Remote-Api aktivieren
|
|
||||||
var remote_api
|
|
||||||
if (app_cfg.endpoint.enabled) {
|
|
||||||
remote_api = io_api.connect(app_cfg.endpoint.host, {
|
|
||||||
reconnect: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Scripte einbinden
|
// Scripte einbinden
|
||||||
var sql_cfg = require('./server/sql_cfg')(fs, bcrypt, app_cfg);
|
var sql_cfg = require('./server/sql_cfg')(fs, bcrypt, app_cfg);
|
||||||
var sql = require('./server/sql_qry')(sql_cfg, app_cfg);
|
var sql = require('./server/sql_qry')(sql_cfg, app_cfg);
|
||||||
var brk = require('./server/broker')(app_cfg, sql, uuidv4);
|
var brk = require('./server/broker')(app_cfg, sql, uuidv4);
|
||||||
var waip = require('./server/waip')(io, sql, fs, brk, async, app_cfg);
|
var waip = require('./server/waip')(io, sql, fs, brk, async, app_cfg);
|
||||||
var saver = require('./server/saver')(app_cfg, sql, waip, uuidv4, io);
|
var saver = require('./server/saver')(app_cfg, sql, waip, uuidv4, io, remote_api);
|
||||||
var api = require('./server/api')(io, sql, app_cfg, remote_api, saver);
|
var api = require('./server/api')(io, sql, app_cfg, remote_api, saver);
|
||||||
var socket = require('./server/socket')(io, sql, app_cfg, waip);
|
var socket = require('./server/socket')(io, sql, app_cfg, waip);
|
||||||
var udp = require('./server/udp')(app_cfg, sql, saver);
|
var udp = require('./server/udp')(app_cfg, sql, saver);
|
||||||
|
|||||||
122
server/api.js
122
server/api.js
@ -1,10 +1,4 @@
|
|||||||
module.exports = function (io, sql, app_cfg, saver) {
|
module.exports = function (io, sql, app_cfg, remote_api, saver) {
|
||||||
|
|
||||||
// Module laden
|
|
||||||
const io_api = require('socket.io-client');
|
|
||||||
|
|
||||||
// Variablen festlegen
|
|
||||||
var uuid_pattern = new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', 'i');
|
|
||||||
|
|
||||||
// ###
|
// ###
|
||||||
// Server Socket.IO Empfangs-API (anderer Server stellt Verbindung her und sendet Daten)
|
// Server Socket.IO Empfangs-API (anderer Server stellt Verbindung her und sendet Daten)
|
||||||
@ -36,11 +30,8 @@ module.exports = function (io, sql, app_cfg, saver) {
|
|||||||
var app_id = raw_data.app_id;
|
var app_id = raw_data.app_id;
|
||||||
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
if (app_id != app_cfg.global.app_id) {
|
if (app_id != app_cfg.global.app_id) {
|
||||||
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
saver.save_new_waip(data, remote_ip, app_id);
|
||||||
filter_api_data(data, remote_ip, function (data_filtered) {
|
sql.db_log('API', 'Neuer Wachalarm von ' + remote_ip + ': ' + data);
|
||||||
saver.save_new_waip(data_filtered, remote_ip, app_id);
|
|
||||||
sql.db_log('API', 'Neuer Wachalarm von ' + remote_ip + ': ' + data_filtered);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,36 +57,6 @@ module.exports = function (io, sql, app_cfg, saver) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function server_to_client_new_waip(data, app_id) {
|
|
||||||
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
|
||||||
if (app_cfg.api.enabled) {
|
|
||||||
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
|
||||||
if (!uuid_pattern.test(app_id)) {
|
|
||||||
app_id = app_cfg.global.app_id;
|
|
||||||
};
|
|
||||||
nsp_api.emit('from_server_to_client_new_waip', {
|
|
||||||
data: data,
|
|
||||||
app_id: app_id
|
|
||||||
});
|
|
||||||
sql.db_log('API', 'Einsatz an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function server_to_client_new_rmld(data, app_id) {
|
|
||||||
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
|
||||||
if (app_cfg.api.enabled) {
|
|
||||||
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
|
||||||
if (!uuid_pattern.test(app_id)) {
|
|
||||||
app_id = app_cfg.global.app_id;
|
|
||||||
};
|
|
||||||
nsp_api.emit('from_server_to_client_new_rmld', {
|
|
||||||
data: data,
|
|
||||||
app_id: app_id
|
|
||||||
});
|
|
||||||
sql.db_log('API', 'Rückmeldung an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ###
|
// ###
|
||||||
// Client Socket.IO Sende-API (Daten an Server senden, zu denen eine Verbindung hergestellt wurde)
|
// Client Socket.IO Sende-API (Daten an Server senden, zu denen eine Verbindung hergestellt wurde)
|
||||||
// ###
|
// ###
|
||||||
@ -103,9 +64,6 @@ module.exports = function (io, sql, app_cfg, saver) {
|
|||||||
if (app_cfg.endpoint.enabled) {
|
if (app_cfg.endpoint.enabled) {
|
||||||
// Verbindung zu anderem Server aufbauen
|
// Verbindung zu anderem Server aufbauen
|
||||||
// TODO API: Verbindungsaufbau mit passendem Geheimnis absichern, IP-Adresse senden
|
// TODO API: Verbindungsaufbau mit passendem Geheimnis absichern, IP-Adresse senden
|
||||||
var remote_api = io_api.connect(app_cfg.endpoint.host, {
|
|
||||||
reconnect: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verbindungsaufbau protokollieren
|
// Verbindungsaufbau protokollieren
|
||||||
remote_api.on('connect', function () {
|
remote_api.on('connect', function () {
|
||||||
@ -129,11 +87,8 @@ module.exports = function (io, sql, app_cfg, saver) {
|
|||||||
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
if (app_id != app_cfg.global.app_id) {
|
if (app_id != app_cfg.global.app_id) {
|
||||||
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
||||||
app_cfg.endpoint.host
|
saver.save_new_waip(data, app_cfg.endpoint.host, app_id);
|
||||||
filter_api_data(data, app_cfg.endpoint.host, function (data_filtered) {
|
sql.db_log('API', 'Neuer Wachalarm von ' + app_cfg.endpoint.host + ': ' + data);
|
||||||
saver.save_new_waip(data_filtered, app_cfg.endpoint.host, app_id);
|
|
||||||
sql.db_log('API', 'Neuer Wachalarm von ' + app_cfg.endpoint.host + ': ' + data_filtered);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -152,71 +107,4 @@ module.exports = function (io, sql, app_cfg, saver) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function client_to_server_new_waip(data, app_id) {
|
|
||||||
// Alarm an Remote-Server senden, falls funktion aktiviert
|
|
||||||
if (app_cfg.endpoint.enabled) {
|
|
||||||
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
|
||||||
if (!uuid_pattern.test(app_id)) {
|
|
||||||
app_id = app_cfg.global.app_id;
|
|
||||||
};
|
|
||||||
remote_api.emit('from_client_to_server_new_waip', {
|
|
||||||
data: data,
|
|
||||||
app_id: app_id
|
|
||||||
});
|
|
||||||
sql.db_log('API', 'Neuen Wachalarm an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function client_to_server_new_rmld(data, app_id) {
|
|
||||||
// Rückmeldung an Remote-Server senden, falls funktion aktiviert
|
|
||||||
if (app_cfg.endpoint.enabled) {
|
|
||||||
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
|
||||||
if (!uuid_pattern.test(app_id)) {
|
|
||||||
app_id = app_cfg.global.app_id;
|
|
||||||
};
|
|
||||||
remote_api.emit('from_client_to_server_new_rmld', {
|
|
||||||
data: data,
|
|
||||||
app_id: app_id
|
|
||||||
});
|
|
||||||
sql.db_log('API', 'Rückmeldung an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function filter_api_data(data, remote_ip, callback) {
|
|
||||||
// unnoetige Zeichen aus socket_id entfernen, um diese als Dateinamen zu verwenden
|
|
||||||
if (app_cfg.filter.enabled) {
|
|
||||||
// Filter nur anwenden wenn Einsatzdaten von bestimmten IP-Adressen kommen
|
|
||||||
if (app_cfg.filter.on_message_from.includes(remote_ip)) {
|
|
||||||
var data_filtered = data;
|
|
||||||
// Schleife definieren
|
|
||||||
function loop_done(data_filtered) {
|
|
||||||
callback && callback(data_filtered);
|
|
||||||
};
|
|
||||||
var itemsProcessed = 0;
|
|
||||||
// nicht gewollte Daten entfernen
|
|
||||||
app_cfg.filter.remove_data.forEach(function (item, index, array) {
|
|
||||||
data_filtered.einsatzdaten[item] = '';
|
|
||||||
data_filtered.ortsdaten[item] = '';
|
|
||||||
// Schleife erhoehen
|
|
||||||
itemsProcessed++;
|
|
||||||
if (itemsProcessed === array.length) {
|
|
||||||
// Schleife beenden
|
|
||||||
loop_done(data_filtered);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback && callback(data);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
callback && callback(data);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
server_to_client_new_waip: server_to_client_new_waip,
|
|
||||||
server_to_client_new_rmld: server_to_client_new_rmld,
|
|
||||||
client_to_server_new_waip: client_to_server_new_waip,
|
|
||||||
client_to_server_new_rmld: client_to_server_new_rmld
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
124
server/saver.js
124
server/saver.js
@ -1,4 +1,4 @@
|
|||||||
module.exports = function (app_cfg, sql, waip, uuidv4) {
|
module.exports = function (app_cfg, sql, waip, uuidv4, io, remote_api) {
|
||||||
|
|
||||||
// Module laden
|
// Module laden
|
||||||
const turf = require('@turf/turf');
|
const turf = require('@turf/turf');
|
||||||
@ -15,6 +15,20 @@ module.exports = function (app_cfg, sql, waip, uuidv4) {
|
|||||||
// Daten validieren
|
// Daten validieren
|
||||||
validate_waip(waip_data, function (valid) {
|
validate_waip(waip_data, function (valid) {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
||||||
|
filter_api_data(data, remote_ip, function (data_filtered) {
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Polygon erzeugen und zuweisen falls nicht vorhanden
|
// Polygon erzeugen und zuweisen falls nicht vorhanden
|
||||||
if (!waip_data.ortsdaten.wgs84_area) {
|
if (!waip_data.ortsdaten.wgs84_area) {
|
||||||
var wgs_x = parseFloat(waip_data.ortsdaten.wgs84_x);
|
var wgs_x = parseFloat(waip_data.ortsdaten.wgs84_x);
|
||||||
@ -35,7 +49,7 @@ module.exports = function (app_cfg, sql, waip, uuidv4) {
|
|||||||
waip_data.ortsdaten.wgs84_area = JSON.stringify(new_buffer);
|
waip_data.ortsdaten.wgs84_area = JSON.stringify(new_buffer);
|
||||||
};
|
};
|
||||||
// pruefen, ob vielleicht schon ein Einsatz mit einer UUID gespeichert ist
|
// pruefen, ob vielleicht schon ein Einsatz mit einer UUID gespeichert ist
|
||||||
sql.db_einsatz_get_uuid_by_enr(waip_data.einsatzdaten.nummer, function(waip_uuid) {
|
sql.db_einsatz_get_uuid_by_enr(waip_data.einsatzdaten.nummer, function (waip_uuid) {
|
||||||
if (waip_uuid) {
|
if (waip_uuid) {
|
||||||
// wenn ein Einsatz mit UUID schon vorhanden ist, dann diese setzten / ueberschreiben
|
// wenn ein Einsatz mit UUID schon vorhanden ist, dann diese setzten / ueberschreiben
|
||||||
waip_data.einsatzdaten.uuid = waip_uuid;
|
waip_data.einsatzdaten.uuid = waip_uuid;
|
||||||
@ -47,11 +61,11 @@ module.exports = function (app_cfg, sql, waip, uuidv4) {
|
|||||||
};
|
};
|
||||||
// Einsatz in DB Speichern
|
// Einsatz in DB Speichern
|
||||||
waip.waip_speichern(waip_data, app_id);
|
waip.waip_speichern(waip_data, app_id);
|
||||||
sql.db_log('WAIP', 'Neuer Einsatz von ' + remote_addr + ' wird jetzt verarbeitet: ' + waip_data);
|
sql.db_log('WAIP', 'Neuer Einsatz von ' + remote_addr + ' wird jetzt verarbeitet: ' + waip_data);
|
||||||
// Einsatzdaten per API weiterleiten (entweder zum Server oder zum verbunden Client)
|
// Einsatzdaten per API weiterleiten (entweder zum Server oder zum verbunden Client)
|
||||||
// TODO TEST: Api WAIP
|
// TODO TEST: Api WAIP
|
||||||
api.server_to_client_new_waip(waip_data, app_id);
|
api.server_to_client_new_waip(waip_data, app_id);
|
||||||
api.client_to_server_new_waip(waip_data, app_id);
|
api.client_to_server_new_waip(waip_data, app_id);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
sql.db_log('WAIP', 'Fehler: Einsatz von ' + remote_addr + ' nicht valide: ' + waip_data);
|
sql.db_log('WAIP', 'Fehler: Einsatz von ' + remote_addr + ' nicht valide: ' + waip_data);
|
||||||
@ -74,9 +88,9 @@ module.exports = function (app_cfg, sql, waip, uuidv4) {
|
|||||||
callback && callback(result);
|
callback && callback(result);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// TODO TEST: Api WAIP
|
// TODO TEST: Api WAIP
|
||||||
api.server_to_client_new_rmld(req.body, app_id);
|
api.server_to_client_new_rmld(req.body, app_id);
|
||||||
api.client_to_server_new_rmld(req.body, app_id);
|
api.client_to_server_new_rmld(req.body, app_id);
|
||||||
} else {
|
} else {
|
||||||
sql.db_log('RMLD', 'Fehler: Rückmeldung von ' + remote_addr + ' nicht valide: ' + waip_data);
|
sql.db_log('RMLD', 'Fehler: Rückmeldung von ' + remote_addr + ' nicht valide: ' + waip_data);
|
||||||
};
|
};
|
||||||
@ -117,6 +131,96 @@ module.exports = function (app_cfg, sql, waip, uuidv4) {
|
|||||||
// SQL-Log
|
// SQL-Log
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function server_to_client_new_waip(data, app_id) {
|
||||||
|
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.api.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
io.of('/api').emit('from_server_to_client_new_waip', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Einsatz an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function server_to_client_new_rmld(data, app_id) {
|
||||||
|
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.api.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
io.of('/api').emit('from_server_to_client_new_rmld', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Rückmeldung an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function client_to_server_new_waip(data, app_id) {
|
||||||
|
// Alarm an Remote-Server senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
remote_api.emit('from_client_to_server_new_waip', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Neuen Wachalarm an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function client_to_server_new_rmld(data, app_id) {
|
||||||
|
// Rückmeldung an Remote-Server senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
remote_api.emit('from_client_to_server_new_rmld', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Rückmeldung an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function filter_api_data(data, remote_ip, callback) {
|
||||||
|
// unnoetige Zeichen aus socket_id entfernen, um diese als Dateinamen zu verwenden
|
||||||
|
if (app_cfg.filter.enabled) {
|
||||||
|
// Filter nur anwenden wenn Einsatzdaten von bestimmten IP-Adressen kommen
|
||||||
|
if (app_cfg.filter.on_message_from.includes(remote_ip)) {
|
||||||
|
var data_filtered = data;
|
||||||
|
// Schleife definieren
|
||||||
|
function loop_done(data_filtered) {
|
||||||
|
callback && callback(data_filtered);
|
||||||
|
};
|
||||||
|
var itemsProcessed = 0;
|
||||||
|
// nicht gewollte Daten entfernen
|
||||||
|
app_cfg.filter.remove_data.forEach(function (item, index, array) {
|
||||||
|
data_filtered.einsatzdaten[item] = '';
|
||||||
|
data_filtered.ortsdaten[item] = '';
|
||||||
|
// Schleife erhoehen
|
||||||
|
itemsProcessed++;
|
||||||
|
if (itemsProcessed === array.length) {
|
||||||
|
// Schleife beenden
|
||||||
|
loop_done(data_filtered);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback && callback(data);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
callback && callback(data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
save_new_waip: save_new_waip,
|
save_new_waip: save_new_waip,
|
||||||
save_new_rmld: save_new_rmld
|
save_new_rmld: save_new_rmld
|
||||||
|
|||||||
@ -95,7 +95,7 @@ module.exports = function (io, sql, fs, brk, async, app_cfg) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function rmld_speichern(rueckmeldung, app_id, callback) {
|
function rmld_speichern(rueckmeldung, callback) {
|
||||||
// Rueckmeldung speichern und verteilen
|
// Rueckmeldung speichern und verteilen
|
||||||
sql.db_rmld_save(rueckmeldung, function (saved) {
|
sql.db_rmld_save(rueckmeldung, function (saved) {
|
||||||
if (saved) {
|
if (saved) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user