mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-12 16:57:39 -05:00
adding Admin server
This commit is contained in:
86
admin/server/config/express.js
Normal file
86
admin/server/config/express.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const path = require("path");
|
||||
const express = require("express");
|
||||
const session = require("express-session");
|
||||
const bodyParser = require("body-parser");
|
||||
const connectMongo = require("connect-mongo");
|
||||
const secrets = require("./secrets");
|
||||
|
||||
const MongoStore = connectMongo(session)
|
||||
var cookie_domain = process.env['REACT_APP_COOKIE_DOMAIN'] != null ? process.env['REACT_APP_COOKIE_DOMAIN'] : '.openmhz.com'; //'https://s3.amazonaws.com/robotastic';
|
||||
var backend_server = process.env['REACT_APP_BACKEND_SERVER'] != null ? process.env['REACT_APP_BACKEND_SERVER'] : 'https://api.openmhz.com';
|
||||
var frontend_server = process.env['REACT_APP_FRONTEND_SERVER'] != null ? process.env['REACT_APP_FRONTEND_SERVER'] : 'https://openmhz.com';
|
||||
var socket_server = process.env['REACT_APP_SOCKET_SERVER'] != null ? process.env['REACT_APP_SOCKET_SERVER'] : 'wss://socket.openmhz.com'; //'https://s3.amazonaws.com/robotastic';
|
||||
var account_server = process.env['REACT_APP_ACCOUNT_SERVER'] != null ? process.env['REACT_APP_ACCOUNT_SERVER'] : 'https://account.openmhz.com'; //'https://s3.amazonaws.com/robotastic';
|
||||
|
||||
module.exports = function(app, passport) {
|
||||
app.set("port", 3008)
|
||||
|
||||
// X-Powered-By header has no functional value.
|
||||
// Keeping it makes it easier for an attacker to build the site's profile
|
||||
// It can be removed safely
|
||||
app.disable("x-powered-by")
|
||||
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
app.use(express.static(path.join(process.cwd(), 'public')));
|
||||
|
||||
const sess = {
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
secret: secrets.sessionSecret,
|
||||
proxy: true,
|
||||
name: "sessionId",
|
||||
cookie: {
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
domain: cookie_domain
|
||||
},
|
||||
store: new MongoStore({
|
||||
url: secrets.db,
|
||||
autoReconnect: true
|
||||
})
|
||||
}
|
||||
|
||||
var node_env = process.env.NODE_ENV;
|
||||
console.log('--------------------------');
|
||||
console.log('===> 😊 Starting Server . . .');
|
||||
console.log('===> Environment: ' + node_env);
|
||||
/*
|
||||
if(node_env === 'production') {
|
||||
console.log('===> 🚦 Note: In order for authentication to work in production');
|
||||
console.log('===> you will need a secure HTTPS connection');
|
||||
sess.cookie.secure = true; // Serve secure cookies
|
||||
}*/
|
||||
|
||||
app.use(session(sess))
|
||||
|
||||
app.use(passport.initialize())
|
||||
app.use(passport.session())
|
||||
|
||||
app.use('/*', function(req, res, next) {
|
||||
var allowedOrigins = [ account_server];
|
||||
allowedOrigins.push(frontend_server);
|
||||
allowedOrigins.push(backend_server);
|
||||
allowedOrigins.push(socket_server);
|
||||
|
||||
var origin = req.headers.origin;
|
||||
|
||||
|
||||
if (allowedOrigins.indexOf(origin) > -1) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
} else if (req.headers["user-agent"] == 'TrunkRecorder1.0') {
|
||||
res.setHeader('Access-Control-Allow-Origin', "*");
|
||||
} else {
|
||||
res.setHeader('Access-Control-Allow-Origin', "*");
|
||||
if (origin) {
|
||||
console.warn("forcing CORS for: " + origin + " referer: " + req.headers.referer);
|
||||
}
|
||||
}
|
||||
res.header("Access-Control-Allow-Headers", "X-Requested-With");
|
||||
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS,WEBSOCKET');
|
||||
res.header('Access-Control-Allow-Credentials', 'true');
|
||||
res.header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Max-Age");
|
||||
res.header('Access-Control-Max-Age', '600');
|
||||
next();
|
||||
});
|
||||
}
|
||||
36
admin/server/config/passport-strategies/local.js
Normal file
36
admin/server/config/passport-strategies/local.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Configuring local strategy to authenticate strategies
|
||||
Code modified from : https://github.com/madhums/node-express-mongoose-demo/blob/master/config/passport/local.js
|
||||
*/
|
||||
|
||||
const mongoose = require("mongoose");
|
||||
const LocalStrategy = require("passport-local").Strategy;
|
||||
const User = require("../../models/user");
|
||||
|
||||
/*
|
||||
By default, LocalStrategy expects to find credentials in parameters named username and password.
|
||||
If your site prefers to name these fields differently, options are available to change the defaults.
|
||||
*/
|
||||
module.exports = new LocalStrategy({
|
||||
usernameField: "email"
|
||||
}, (email, password, done) => {
|
||||
User.findOne({
|
||||
$or: [{
|
||||
email
|
||||
}, {
|
||||
local: {
|
||||
email
|
||||
}
|
||||
}]
|
||||
}, (err, user) => {
|
||||
if(!user) return done(null, false, { message: `Email ${email} not found` })
|
||||
|
||||
user.comparePassword(password, (err, isMatch) => {
|
||||
if (isMatch) {
|
||||
return done(null, user)
|
||||
} else {
|
||||
return done(null, false, { message: "Invalid email or password" })
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
26
admin/server/config/passport.js
Normal file
26
admin/server/config/passport.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Initializing PassportJS */
|
||||
const User = require("../models/user");
|
||||
const local = require("./passport-strategies/local");
|
||||
|
||||
module.exports = function (app, passport) {
|
||||
// Configure Passport authenticated session persistence.
|
||||
//
|
||||
// In order to restore authentication state across HTTP requests, Passport needs
|
||||
// to serialize users into and deserialize users out of the session. The
|
||||
// typical implementation of this is as simple as supplying the user ID when
|
||||
// serializing, and querying the user record by ID from the database when
|
||||
// deserializing.
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user.id)
|
||||
})
|
||||
|
||||
passport.deserializeUser((id, done) => {
|
||||
User.findById(id, (err, user) => {
|
||||
done(err, user)
|
||||
})
|
||||
})
|
||||
|
||||
// use the following strategies
|
||||
passport.use(local)
|
||||
}
|
||||
|
||||
14
admin/server/config/secrets.js
Normal file
14
admin/server/config/secrets.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/** Important **/
|
||||
/** You should not be committing this file to GitHub **/
|
||||
/** Repeat: DO! NOT! COMMIT! THIS! FILE! TO! YOUR! REPO! **/
|
||||
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
|
||||
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;
|
||||
var mongoUrl = 'mongodb://' + host + ':' + port + '/scanner';
|
||||
|
||||
|
||||
|
||||
module.exports = secrets = {
|
||||
db: mongoUrl,
|
||||
sessionSecret: "letthisbeyoursecret"
|
||||
}
|
||||
|
||||
296
admin/server/controllers/groups.js
Normal file
296
admin/server/controllers/groups.js
Normal file
@@ -0,0 +1,296 @@
|
||||
const Group = require("../models/group");
|
||||
const System = require("../models/system");
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
//router.get('/system/:shortName/group/:groupId?', isLoggedIn, function(req, res) {
|
||||
|
||||
exports.getGroups = function(req, res, next) {
|
||||
process.nextTick(function() {
|
||||
System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, system) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.groupId) {
|
||||
var groupId = req.params.groupId.toLowerCase();
|
||||
|
||||
Group.findOne(
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(groupId),
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
{ sort: { position: -1 } },
|
||||
function(err, group) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.json({
|
||||
success: true,
|
||||
group: group
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
Group.find(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
}).sort("position").exec(
|
||||
function(err, groups) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.json({
|
||||
success: true,
|
||||
groups: groups
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
exports.deleteGroup = function(req, res, next) {
|
||||
//router.get('/system/:shortName/remove_group/:groupId', isLoggedIn, function(req, res) {
|
||||
System.findOne({
|
||||
'shortName': req.params.shortName.toLowerCase()
|
||||
}, function(err, system) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
Group.findOneAndRemove({
|
||||
shortName: req.params.shortName.toLowerCase(),
|
||||
'_id': new mongoose.Types.ObjectId(req.params.groupId)
|
||||
}, function(err) {
|
||||
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// removed!
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
exports.reorderGroups = function(req, res, next) {
|
||||
//router.post('/system/:shortName/group_order', isLoggedIn, function(req, res) {
|
||||
process.nextTick(function() {
|
||||
System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, system) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var groupOrder = JSON.parse(req.body.groupOrder);
|
||||
for (var i = 0; i < groupOrder.length; i++) {
|
||||
|
||||
console.log("in group: " + groupOrder[i] + " position: " + i);
|
||||
Group.findOneAndUpdate(
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(groupOrder[i]),
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
{
|
||||
position: i
|
||||
},
|
||||
{
|
||||
new: true,
|
||||
upsert: false
|
||||
},
|
||||
function(err, group) {
|
||||
console.log("Save group: " + group._id + " position: " + group.position);
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Error: Group Order - " +
|
||||
err +
|
||||
" Shortname: " +
|
||||
req.params.shortName.toLowerCase()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
exports.upsertGroup = function(req, res, next) {
|
||||
//router.post('/system/:shortName/group/:groupId?', isLoggedIn, function(req, res) {
|
||||
process.nextTick(function() {
|
||||
System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, system) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
var message = "";
|
||||
var groupName = req.body.groupName.replace(/[^\w\s]/g, "");
|
||||
var talkgroups = JSON.parse(req.body.talkgroups);
|
||||
console.log(
|
||||
"Talkgroups: " +
|
||||
talkgroups +
|
||||
" for group: " +
|
||||
groupName +
|
||||
" array: " +
|
||||
Array.isArray(talkgroups)
|
||||
);
|
||||
if (!talkgroups.length || !Array.isArray(talkgroups)) {
|
||||
message = "Talkgroups need to be selected, group can not be empty ";
|
||||
}
|
||||
if (!groupName.length) {
|
||||
message = message + "Group Name is required";
|
||||
}
|
||||
|
||||
if (message.length) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: message
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if we got here, that means that everything is good for updating/inserting
|
||||
|
||||
var groupId = req.params.groupId;
|
||||
|
||||
Group.findOneAndUpdate(
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(groupId),
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
{
|
||||
groupName: groupName,
|
||||
talkgroups: talkgroups
|
||||
},
|
||||
{
|
||||
new: true,
|
||||
upsert: true
|
||||
},
|
||||
function(err, group) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.json({
|
||||
success: true,
|
||||
group: group
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
241
admin/server/controllers/permissions.js
Normal file
241
admin/server/controllers/permissions.js
Normal file
@@ -0,0 +1,241 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Permission = require("../models/permission");
|
||||
const System = require("../models/system");
|
||||
const User = require("../models/user");
|
||||
|
||||
exports.fetchPermissions = function(req, res, next) {
|
||||
Permission.find(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, permissions) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
var userIds = permissions.map(permission => {return permission.userId});
|
||||
User.find(
|
||||
{
|
||||
_id: {
|
||||
$in: userIds
|
||||
}
|
||||
},
|
||||
function(err, users) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
var returnUsers = users.map(user =>{
|
||||
var permission = permissions.find(obj => {
|
||||
|
||||
if (obj.userId.toString() == user._id.toString()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!permission) {
|
||||
console.error("Error - Permission not found for user: " + user._id);
|
||||
res.json({ success: false, message: "Permission not found" });
|
||||
return;
|
||||
}
|
||||
return {_id: permission._id, userId: user._id, firstName: user.firstName, lastName: user.lastName, email: user.email, role: permission.role };
|
||||
});
|
||||
|
||||
res.json({ success: true, permissions: returnUsers });
|
||||
});
|
||||
return;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
exports.addPermission = async (req, res, next) => {
|
||||
//router.post('/system/:shortName/group/:groupId?', isLoggedIn, function(req, res) {
|
||||
|
||||
|
||||
let role = req.body.role;
|
||||
var system = false;
|
||||
var user = false;
|
||||
var existing = false;
|
||||
var saved = false;
|
||||
if (!role || (role >= 20) || (role <1)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Invalid Role"
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("role looks good");
|
||||
try {
|
||||
system = await System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!system) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That System does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("system looks good")
|
||||
try {
|
||||
user = await User.findOne(
|
||||
{
|
||||
email: req.body.email
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
res.json({ success: false, message: "User not found" });
|
||||
return;
|
||||
}
|
||||
console.log("user looks good")
|
||||
try {
|
||||
existing = await Permission.findOne({userId: user._id, systemId: system._id});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (existing) {
|
||||
res.json({ success: false, message: "User already has acccess" });
|
||||
return;
|
||||
}
|
||||
console.log("no existing")
|
||||
var permission = new Permission({
|
||||
userId: user._id,
|
||||
systemId: system._id,
|
||||
shortName: system.shortName,
|
||||
role: role
|
||||
});
|
||||
|
||||
|
||||
try {
|
||||
saved = await permission.save()
|
||||
} catch(err) {
|
||||
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("saved it")
|
||||
var newPermission = saved.toObject();
|
||||
newPermission.firstName = user.firstName;
|
||||
newPermission.lastName = user.lastName;
|
||||
newPermission.email = user.email;
|
||||
|
||||
|
||||
console.log("Add Permission to: " + system.shortName + " for: " + newPermission.email + " by: " + req.user.email);
|
||||
res.json({
|
||||
success: true,
|
||||
permission: newPermission
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.updatePermission = function(req, res, next) {
|
||||
process.nextTick(function() {
|
||||
Permission.findOne(
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(req.params.permissionId),
|
||||
shortName: req.params.shortName.toLowerCase(req.params.shortName)
|
||||
},
|
||||
|
||||
function(err, permission) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (permission.role >= 20) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Cannot change permissions of system owner"
|
||||
});
|
||||
return;
|
||||
}
|
||||
var newRole = req.body.role;
|
||||
if (!newRole || (newRole >= 20) || (newRole <1)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Invalid Role"
|
||||
});
|
||||
return;
|
||||
}
|
||||
permission.role = newRole;
|
||||
permission.save(function(err, saved) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
permission: saved.toJSON()
|
||||
});
|
||||
return;
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.deletePermission = function(req, res, next) {
|
||||
//router.get('/system/:shortName/remove_group/:groupId', isLoggedIn, function(req, res) {
|
||||
|
||||
Permission.findOneAndRemove({
|
||||
shortName: req.params.shortName.toLowerCase(),
|
||||
'_id': new mongoose.Types.ObjectId(req.params.permissionId),
|
||||
role: { $lt : 20}
|
||||
}, function(err, permission) {
|
||||
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!permission) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Permission not found"
|
||||
});
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// removed!
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
507
admin/server/controllers/systems.js
Normal file
507
admin/server/controllers/systems.js
Normal file
@@ -0,0 +1,507 @@
|
||||
const mongoose = require("mongoose");
|
||||
const System = require("../models/system");
|
||||
const SystemStat = require("../models/system_stat");
|
||||
const Talkgroup = require("../models/talkgroup");
|
||||
const Group = require("../models/group");
|
||||
const crypto = require("crypto");
|
||||
|
||||
exports.isLoggedIn = function (req, res, next) {
|
||||
if (req.isAuthenticated()) return next();
|
||||
res.redirect(account_server + "/login");
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.listSystems = function (req, res, next) {
|
||||
console.log("Listing Systems for: " + req.user._id);
|
||||
System.find({
|
||||
userId: mongoose.Types.ObjectId(req.user._id)
|
||||
},
|
||||
function (err, systems) {
|
||||
if (err) {
|
||||
console.error("Error - ListSystems: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var shortNames = new Array();
|
||||
for (var i = 0; i < systems.length; i++) {
|
||||
shortNames.push(systems[i].shortName);
|
||||
}
|
||||
|
||||
SystemStat.find({
|
||||
shortName: {
|
||||
$in: shortNames
|
||||
}
|
||||
},
|
||||
function (err, stats) {
|
||||
var returnSys = systems.map(obj => {
|
||||
var rObj = (({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
key,
|
||||
planType,
|
||||
showScreenName
|
||||
}) => ({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
key,
|
||||
planType,
|
||||
showScreenName
|
||||
}))(obj);
|
||||
if (obj.showScreenName) {
|
||||
rObj.screenName = req.user.screenName;
|
||||
} else {
|
||||
rObj.screenName = null;
|
||||
}
|
||||
rObj.id = obj._id;
|
||||
return rObj;
|
||||
});
|
||||
var sys_stats = {}
|
||||
var MS_PER_MINUTE = 60000;
|
||||
var now = new Date();
|
||||
for (var i = 0; i < stats.length; i++) {
|
||||
sys_stats[stats[i].shortName] = {};
|
||||
|
||||
sys_stats[stats[i].shortName].callTotals = stats[i].callTotals;
|
||||
sys_stats[stats[i].shortName].errorTotals = stats[i].errorTotals;
|
||||
sys_stats[stats[i].shortName].errorStats = stats[i].errorStats;
|
||||
sys_stats[stats[i].shortName].usageBytes = stats[i].usageBytes;
|
||||
sys_stats[stats[i].shortName].usageMb = stats[i].usageMb;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
systems: returnSys,
|
||||
stats: sys_stats
|
||||
});
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function remove_system(shortName) {
|
||||
/*
|
||||
var sysDir = config.mediaDirectory + "/" + shortName + "/"
|
||||
console.log("Removing DIR: " + sysDir);
|
||||
fs.remove(sysDir, function(err) {
|
||||
if (err) return console.error(err)
|
||||
});
|
||||
|
||||
Transmission.remove({
|
||||
shortName: shortName
|
||||
}, function(err) {
|
||||
if (err) return console.error(err);
|
||||
// removed!
|
||||
});
|
||||
*/
|
||||
System.remove({
|
||||
shortName: shortName
|
||||
},
|
||||
function (err) {
|
||||
if (err) return console.error(err);
|
||||
// removed!
|
||||
}
|
||||
);
|
||||
|
||||
Talkgroup.remove({
|
||||
shortName: shortName
|
||||
},
|
||||
function (err) {
|
||||
if (err) return console.error(err);
|
||||
// removed!
|
||||
}
|
||||
);
|
||||
|
||||
Group.remove({
|
||||
shortName: shortName
|
||||
},
|
||||
function (err) {
|
||||
if (err) return console.error(err);
|
||||
// removed!
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
exports.deleteSystem = function (req, res, next) {
|
||||
//router.get('/delete_system/:shortName', isLoggedIn, function(req, res) {
|
||||
System.findOne({
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function (err, system) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
console.log("Error deleting syste - Wrong User - sys: " + system.userId + " profile: " + mongoose.Types.ObjectId(req.user._id));
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("Removing: " + system.name);
|
||||
remove_system(system.shortName);
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
exports.ownSystem = async function (req, res, next) {
|
||||
try {
|
||||
var system = await System.findOne({
|
||||
shortName: req.body.shortName.toLowerCase()
|
||||
});
|
||||
|
||||
if (!system) {
|
||||
console.error("ERROR: OwnSystem - system does not exist: " + req.body.shortName.toLowerCase());
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That System does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
console.error("ERROR: OwnSystem - not users system " + req.body.shortName.toLowerCase());
|
||||
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
console.error("System: " + system.userId + " User: " + req.user._id);
|
||||
return;
|
||||
}
|
||||
|
||||
res.locals.test = "Yoho!"
|
||||
res.locals.system = system;
|
||||
console.log(system);
|
||||
console.log(res.locals);
|
||||
next();
|
||||
|
||||
} catch (err) {
|
||||
console.error("ERROR: Unique ShortName - caught: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
exports.uniqueShortName = async function (req, res, next) {
|
||||
console.error("locals: " + res.locals.shortName + " body: " + req.body.shortName )
|
||||
try {
|
||||
var system = await System.findOne({
|
||||
shortName: res.locals.shortName.toLowerCase()
|
||||
});
|
||||
|
||||
if (system) {
|
||||
console.error("ERROR: Unique Shortname already in use: " + req.body.shortName.toLowerCase());
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Short Name already in use"
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.error("ERROR: Unique ShortName - caught: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.updateSystem = async function (req, res, next) {
|
||||
|
||||
console.log(res.locals)
|
||||
res.locals.system.name = res.locals.name;
|
||||
res.locals.system.city = res.locals.city;
|
||||
res.locals.system.state = res.locals.state;
|
||||
res.locals.system.county = res.locals.county;
|
||||
res.locals.system.country = res.locals.country;
|
||||
res.locals.system.description = res.locals.description;
|
||||
res.locals.system.systemType = res.locals.systemType;
|
||||
res.locals.system.showScreenName = res.locals.showScreenName;
|
||||
|
||||
res.locals.system.save(function (err) {
|
||||
if (err) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
var returnSys = (({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
key,
|
||||
showScreenName
|
||||
}) => ({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
key,
|
||||
showScreenName
|
||||
}))(res.locals.system);
|
||||
returnSys.id = res.locals.system._id;
|
||||
res.json({
|
||||
success: true,
|
||||
system: returnSys
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.validateSystem = async function (req, res, next) {
|
||||
try {
|
||||
res.locals.showScreenName = req.body.showScreenName;
|
||||
|
||||
if (!req.body.name || (req.body.name.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.name");
|
||||
res.json({
|
||||
success: false,
|
||||
message: "System Name is Required"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.name = req.body.name.replace(/[^\w\s\.\,\-\_]/gi, '');
|
||||
|
||||
if (!req.body.description || (req.body.description.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.description");
|
||||
res.json({
|
||||
success: false,
|
||||
message: "System Description is Required"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.description = req.body.description.replace(/[^\w\s\.\,\-\_]/gi, '');
|
||||
|
||||
if (!req.body.shortName || (req.body.shortName.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.shortName");
|
||||
res.json({
|
||||
success: false,
|
||||
message: "System ShortName is Required"
|
||||
});
|
||||
return;
|
||||
}
|
||||
var tempShortName = req.body.shortName.replace(/[^\w]/gi, '');
|
||||
res.locals.shortName = tempShortName.toLowerCase();
|
||||
|
||||
// -------------------- Handle all the different SystemTypes of Locations
|
||||
|
||||
|
||||
// make sure it is one of the expected types
|
||||
if ((req.body.systemType != "state") && (req.body.systemType != "city") && (req.body.systemType != "county") && (req.body.systemType != "international")) {
|
||||
console.error("ERROR: Validate System - req.body.systemType: " + req.body.systemType);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Select system location"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// copy it over
|
||||
res.locals.systemType = req.body.systemType;
|
||||
|
||||
// now check to make sure the correct things for location is filled out
|
||||
if (req.body.systemType === "state" ||
|
||||
req.body.systemType === "city" ||
|
||||
req.body.systemType === "county") {
|
||||
if (!req.body.state || (req.body.state === "") || (req.body.state.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.state: " + req.body.state);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Select the State for the System"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.state = req.body.state;
|
||||
}
|
||||
|
||||
if (req.body.systemType === "city") {
|
||||
if (!req.body.city || (req.body.city === "") || (req.body.city.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.systemType: " + req.body.systemType);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Enter the city for the System"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.city = req.body.city.replace(/[^\w\s\.\,\-\_]/gi, '');
|
||||
}
|
||||
|
||||
if (req.body.systemType === "county") {
|
||||
if (!req.body.county || (req.body.county === "") || (req.body.county.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.county: " + req.body.county);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Enter the county for the System"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.county = req.body.county.replace(/[^\w\s\.\,\-\_]/gi, '');
|
||||
}
|
||||
|
||||
if (req.body.systemType === "international") {
|
||||
if (!req.body.country || (req.body.country === "") || (req.body.country.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.country: " + req.body.country);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Enter the country for the System"
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.locals.country = req.body.country.replace(/[^\w\s\.\,\-\_]/gi, '');
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.error("ERROR: Validate System - caught: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.createSystem = async function (req, res, next) {
|
||||
|
||||
var key = uuid.v4();
|
||||
key = crypto
|
||||
.createHash("sha256")
|
||||
.update(key)
|
||||
.update("salt")
|
||||
.digest("hex");
|
||||
const system = (({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
showScreenName
|
||||
}) => ({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
showScreenName
|
||||
}))(res.locals);
|
||||
system.key = key;
|
||||
system.userId = mongoose.Types.ObjectId(req.user._id);
|
||||
System.create(system, function (err, newSys) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
var returnSys = (({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
showScreenName,
|
||||
key
|
||||
}) => ({
|
||||
name,
|
||||
shortName,
|
||||
description,
|
||||
systemType,
|
||||
city,
|
||||
state,
|
||||
county,
|
||||
country,
|
||||
userId,
|
||||
showScreenName,
|
||||
key
|
||||
}))(newSys);
|
||||
returnSys.id = newSys._id;
|
||||
res.json({
|
||||
success: true,
|
||||
system: returnSys
|
||||
});
|
||||
return;
|
||||
});
|
||||
}
|
||||
250
admin/server/controllers/talkgroups.js
Normal file
250
admin/server/controllers/talkgroups.js
Normal file
@@ -0,0 +1,250 @@
|
||||
const Talkgroup = require("../models/talkgroup");
|
||||
const System = require("../models/system");
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const crypto = require("crypto");
|
||||
var parse = require('csv-parse');
|
||||
|
||||
exports.isLoggedIn = function(req, res, next) {
|
||||
if (req.isAuthenticated()) return next();
|
||||
res.redirect(account_server + "/login");
|
||||
};
|
||||
|
||||
//router.get("/tg_export/:shortName", isLoggedIn, function(req, res) {
|
||||
exports.exportTalkgroups = function(req, res, next) {
|
||||
process.nextTick(function() {
|
||||
System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, system) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
Talkgroup.find(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, talkgroups) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!talkgroups || !Array.isArray(talkgroups)) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Talkgroups were not found."
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.statusCode = 200;
|
||||
res.setHeader("Content-Type", "text/csv");
|
||||
talkgroups.forEach(function(item) {
|
||||
/* res.write('"' + item.num + '", "'
|
||||
+ item.mode + '", "'
|
||||
+ item.alpha + '", "'
|
||||
+ item.description + '", "'
|
||||
+ item.tag + '", "'
|
||||
+ item.group + '", "'
|
||||
+ item.priority+ '"\r\n');*/
|
||||
if (item) {
|
||||
var sending = "";
|
||||
sending = item.num + ", ";
|
||||
if (item.mode) {
|
||||
sending = sending + item.mode.toString().replace(/\,/g, "") + ", ";
|
||||
} else {
|
||||
sending = sending + " ,";
|
||||
}
|
||||
if (item.alpa) {
|
||||
sending = sending + item.alpha.toString().replace(/\,/g, "") + ", ";
|
||||
} else {
|
||||
sending = sending + " ,";
|
||||
}
|
||||
if (item.description) {
|
||||
sending = sending + item.description.toString().replace(/\,/g, "") + ", ";
|
||||
} else {
|
||||
sending = sending + " ,";
|
||||
}
|
||||
if (item.tag) {
|
||||
sending = sending + item.tag.toString().replace(/\,/g, "") + ", ";
|
||||
} else {
|
||||
sending = sending + " ,";
|
||||
}
|
||||
if (item.group) {
|
||||
sending = sending + item.group.toString().replace(/\,/g, "") + ", ";
|
||||
} else {
|
||||
sending = sending + " ,";
|
||||
}
|
||||
if (item.priority) {
|
||||
sending = sending + item.priority.toString().replace(/\,/g, "") + "\r\n";
|
||||
} else {
|
||||
sending = sending + "\r\n";
|
||||
}
|
||||
res.write(sending);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
res.end();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
function csv_import(shortName, filename, callback) {
|
||||
var talkgroups = [];
|
||||
Talkgroup.remove(
|
||||
{
|
||||
shortName: shortName
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
console.error("Error: csv import: " + err);
|
||||
callback(err, null);
|
||||
} else {
|
||||
var parser = parse(
|
||||
{
|
||||
columns: [
|
||||
"num",
|
||||
"mode",
|
||||
"alpha",
|
||||
"description",
|
||||
"tag",
|
||||
"group",
|
||||
"priority"
|
||||
]
|
||||
},
|
||||
async function(err, data) {
|
||||
if (err) {
|
||||
console.error("Error: csv import 2: " + err);
|
||||
callback(err, null);
|
||||
} else {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var row = data[i];
|
||||
var newTg = new Talkgroup();
|
||||
newTg.num = parseInt(row.num);
|
||||
newTg.alpha = row.alpha;
|
||||
newTg.mode = row.mode;
|
||||
newTg.description = row.description;
|
||||
newTg.tag = row.tag.toLowerCase();
|
||||
newTg.group = row.group.toLowerCase();
|
||||
newTg.priority = row.priority;
|
||||
newTg.shortName = shortName;
|
||||
|
||||
await newTg.save(function(err) {
|
||||
if (err) {
|
||||
console.log("Error: CSV import: " + err);
|
||||
callback(err, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
callback(null, data);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
fs.createReadStream(filename).pipe(parser);
|
||||
// removed!
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//router.post("/tg_import/:shortName", isLoggedIn, upload.single('file'), function(req, res, next) {
|
||||
exports.importTalkgroups = function(req, res, next) {
|
||||
process.nextTick(function() {
|
||||
System.findOne(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, system) {
|
||||
if (err) {
|
||||
console.error("Error - importTalkgroups: " + err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
if (!system) {
|
||||
console.error("Error - importTalkgroups: System not found - " + req.params.shortName.toLowerCase());
|
||||
res.json({
|
||||
success: false,
|
||||
message: "That Short Name does not exist."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!system.userId.equals(req.user._id)) {
|
||||
console.error("Error - importTalkgroups: you are not the user for hte system: " + req.user._id);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "You are not the user associated with this system."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!req.file || req.file.size === 0) {
|
||||
res.json({ success: false, message: "Please select a file." });
|
||||
return;
|
||||
}
|
||||
|
||||
fs.exists(req.file.path, function(exists) {
|
||||
if (exists) {
|
||||
csv_import(system.shortName, req.file.path, function(err, data) {
|
||||
if (err) {
|
||||
console.error("Erorr - CSV import, callback: " + err);
|
||||
res.json({ success: false, message: err });
|
||||
res.end();
|
||||
return;
|
||||
} else {
|
||||
res.json({ success: true, talkgroups: data });
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error("Error - importTalkgroups: no file");
|
||||
res.end(
|
||||
"Well, there is no magic for those who don’t believe in it!"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.fetchTalkgroups = function(req, res, next) {
|
||||
Talkgroup.find(
|
||||
{
|
||||
shortName: req.params.shortName.toLowerCase()
|
||||
},
|
||||
function(err, talkgroups) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({ success: false, message: err });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, talkgroups: talkgroups });
|
||||
return;
|
||||
}
|
||||
);
|
||||
};
|
||||
155
admin/server/index.js
Normal file
155
admin/server/index.js
Normal file
@@ -0,0 +1,155 @@
|
||||
const mongoose = require("mongoose");
|
||||
const express = require("express");
|
||||
const passport = require("passport");
|
||||
const path = require("path");
|
||||
const secrets = require("./config/secrets");
|
||||
const configurePassport = require("./config/passport");
|
||||
const configureExpress = require("./config/express");
|
||||
const systems = require("./controllers/systems");
|
||||
const groups = require("./controllers/groups");
|
||||
const talkgroups = require("./controllers/talkgroups");
|
||||
const Permission = require("./models/permission");
|
||||
require("./models/user");
|
||||
const multer = require('multer');
|
||||
|
||||
var upload = multer({
|
||||
dest: 'uploads/'
|
||||
});
|
||||
// -------------------------------------------
|
||||
|
||||
const app = express()
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
const connect = () => {
|
||||
mongoose.connect(secrets.db, (err, res) => {
|
||||
if (err) {
|
||||
console.log(`Error connecting to ${secrets.db}. ${err}`)
|
||||
} else {
|
||||
console.log(`Successfully connected to ${secrets.db}.`)
|
||||
}
|
||||
})
|
||||
}
|
||||
connect()
|
||||
|
||||
mongoose.connection.on("error", console.error)
|
||||
mongoose.connection.on("disconnected", connect)
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development"
|
||||
|
||||
|
||||
/*
|
||||
async function getRole(req) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
if (req.params.shortName && req.user) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
var userId = req.user._id;
|
||||
Permission.findOne({'userId': userId, 'shortName': short_name}, function(err, permission) {
|
||||
if (err) {
|
||||
console.error('Error - getRole userId: ' + userId + ' shortName: ' + short_name + ' error: ' + err);
|
||||
reject(-1);
|
||||
}
|
||||
console.log('Found - getRole userId: ' + userId + ' shortName: ' + short_name + ' role: ' + permission.role);
|
||||
|
||||
resolve(permission.role);
|
||||
});
|
||||
} else {
|
||||
reject(-1);
|
||||
}});
|
||||
return promise;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
function isOwner(req, res, next) {
|
||||
if (req.params.shortName && req.user) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
var userId = req.user._id;
|
||||
Permission.findOne({'userId': userId, 'shortName': short_name}, function(err, permission) {
|
||||
if (err) {
|
||||
console.error('Error - getRole userId: ' + userId + ' shortName: ' + short_name + ' error: ' + err);
|
||||
}
|
||||
console.log('Found - getRole userId: ' + userId + ' shortName: ' + short_name + ' role: ' + permission.role);
|
||||
if ( permission.role >= 15) {
|
||||
return next();
|
||||
} else {
|
||||
res.status(401).send({
|
||||
success: false,
|
||||
message: "Insufficent Permission, role: " + permission.role
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isAdmin(req, res, next) {
|
||||
if (req.params.shortName && req.user) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
var userId = req.user._id;
|
||||
Permission.findOne({'userId': userId, 'shortName': short_name}, function(err, permission) {
|
||||
if (err) {
|
||||
console.error('Error - getRole userId: ' + userId + ' shortName: ' + short_name + ' error: ' + err);
|
||||
}
|
||||
console.log('Found - getRole userId: ' + userId + ' shortName: ' + short_name + ' role: ' + permission.role);
|
||||
if (permission.role >= 10) {
|
||||
return next();
|
||||
} else {
|
||||
res.status(401).send({
|
||||
success: false,
|
||||
message: "Insufficent Permission, role: " + permission.role
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isLoggedIn(req, res, next) {
|
||||
if (req.isAuthenticated()) return next();
|
||||
res.status(401).send({
|
||||
success: false,
|
||||
message: "Not Authenticated."
|
||||
});
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
configurePassport(app, passport)
|
||||
configureExpress(app, passport)
|
||||
|
||||
// -------------------------------------------
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
app.get("")
|
||||
|
||||
//app.get("/permissions/:shortname", isOwner, permissions.fetchPermissions)
|
||||
/*app.get("/permissions/:shortName", permissions.fetchPermissions);
|
||||
app.delete("/permissions/:shortName/:permissionId", isAdmin, permissions.deletePermission);
|
||||
app.post("/permissions/:shortName/:permissionId", isAdmin, permissions.updatePermission);
|
||||
app.post("/permissions/:shortName", isAdmin, permissions.addPermission);*/
|
||||
app.get("/talkgroups/:shortName", isLoggedIn, talkgroups.fetchTalkgroups)
|
||||
app.post("/talkgroups/:shortName/import", isLoggedIn, upload.single('file'), talkgroups.importTalkgroups)
|
||||
app.get("/talkgroups/:shortName/export", isLoggedIn, talkgroups.exportTalkgroups)
|
||||
app.post("/groups/:shortName/reorder", isLoggedIn, groups.reorderGroups);
|
||||
app.post("/groups/:shortName/:groupId?", isLoggedIn, groups.upsertGroup);
|
||||
app.get("/groups/:shortName/:groupId?", isLoggedIn, groups.getGroups);
|
||||
app.delete("/groups/:shortName/:groupId", isLoggedIn, groups.deleteGroup);
|
||||
app.get("/systems", isLoggedIn, systems.listSystems)
|
||||
app.delete("/systems/:shortName", isLoggedIn, systems.deleteSystem)
|
||||
app.post("/systems/:shortName", [isLoggedIn, systems.ownSystem, systems.validateSystem, systems.updateSystem])
|
||||
app.post("/systems", [isLoggedIn, systems.uniqueShortName, systems.validateSystem, systems.createSystem])
|
||||
|
||||
app.get("*", (req, res, next) => {
|
||||
res.sendFile('public/index.html');
|
||||
});
|
||||
|
||||
// start listening to incoming requests
|
||||
app.listen(app.get("port"), app.get("host"), (err) => {
|
||||
if (err) {
|
||||
console.err(err.stack)
|
||||
} else {
|
||||
console.log(`App listening on port ${app.get("port")} [${process.env.NODE_ENV} mode]`)
|
||||
}
|
||||
})
|
||||
14
admin/server/models/group.js
Normal file
14
admin/server/models/group.js
Normal file
@@ -0,0 +1,14 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
|
||||
|
||||
var groupSchema = mongoose.Schema({
|
||||
shortName: String,
|
||||
groupName: String,
|
||||
groupId: String,
|
||||
position: Number,
|
||||
talkgroups: [Number]
|
||||
});
|
||||
|
||||
|
||||
module.exports = mongoose.model('Group', groupSchema);
|
||||
24
admin/server/models/permission.js
Normal file
24
admin/server/models/permission.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Defining a User Model in mongoose
|
||||
// Code modified from https://github.com/sahat/hackathon-starter
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
|
||||
|
||||
|
||||
const PermissionSchema = new mongoose.Schema({
|
||||
userId: mongoose.Schema.Types.ObjectId,
|
||||
systemId: mongoose.Schema.Types.ObjectId,
|
||||
shortName: String,
|
||||
role: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
ver: {
|
||||
type: Number,
|
||||
default: 1.2
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
module.exports=mongoose.model("Permission", PermissionSchema)
|
||||
27
admin/server/models/system.js
Normal file
27
admin/server/models/system.js
Normal file
@@ -0,0 +1,27 @@
|
||||
var mongoose = require('mongoose');
|
||||
var bcrypt = require('bcrypt');
|
||||
|
||||
var systemSchema = mongoose.Schema({
|
||||
name: String,
|
||||
shortName: String,
|
||||
systemType: String,
|
||||
county: String,
|
||||
country: String,
|
||||
city: String,
|
||||
state: String,
|
||||
description: String,
|
||||
showScreenName: Boolean,
|
||||
planType: {type: Number, default: 0},
|
||||
userId: mongoose.Schema.Types.ObjectId,
|
||||
key: String
|
||||
});
|
||||
|
||||
systemSchema.methods.generateHash = function(password) {
|
||||
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
|
||||
};
|
||||
|
||||
systemSchema.methods.validPassword = function(password) {
|
||||
return bcrypt.compareSync(password, this.local.password);
|
||||
};
|
||||
|
||||
module.exports = mongoose.model('System', systemSchema);
|
||||
12
admin/server/models/system_stat.js
Normal file
12
admin/server/models/system_stat.js
Normal file
@@ -0,0 +1,12 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var systemStatSchema = mongoose.Schema({
|
||||
callTotals: [Number],
|
||||
errorTotals: [Number],
|
||||
usageBytes: Number,
|
||||
usageMb: Number,
|
||||
shortName: String
|
||||
}, { collection: 'system_stats' });
|
||||
|
||||
|
||||
module.exports = mongoose.model('SystemStat', systemStatSchema);
|
||||
16
admin/server/models/talkgroup.js
Normal file
16
admin/server/models/talkgroup.js
Normal file
@@ -0,0 +1,16 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var talkgroupSchema = mongoose.Schema({
|
||||
shortName: String,
|
||||
userId: String,
|
||||
num: Number,
|
||||
mode: String,
|
||||
alpha: String,
|
||||
description: String,
|
||||
tag: String,
|
||||
group: String,
|
||||
priority: Number
|
||||
});
|
||||
|
||||
|
||||
module.exports = mongoose.model('Talkgroup', talkgroupSchema);
|
||||
91
admin/server/models/user.js
Normal file
91
admin/server/models/user.js
Normal file
@@ -0,0 +1,91 @@
|
||||
// Defining a User Model in mongoose
|
||||
// Code modified from https://github.com/sahat/hackathon-starter
|
||||
const bcrypt = require("bcrypt");
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
|
||||
|
||||
const UserSchema = new mongoose.Schema({
|
||||
local: {
|
||||
name: String,
|
||||
email: String,
|
||||
password: String
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
unique: true,
|
||||
lowercase: true
|
||||
},
|
||||
password: String,
|
||||
screenName: {
|
||||
type: String,
|
||||
unique: true,
|
||||
lowercase: true
|
||||
},
|
||||
firstName: String,
|
||||
lastName: String,
|
||||
location: String,
|
||||
email: String,
|
||||
resetPasswordToken: String,
|
||||
resetPasswordTTL: Date,
|
||||
confirmEmail: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
customerId: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
confirmEmailToken: String,
|
||||
confirmEmailTTL: Date,
|
||||
admin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
terms: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
ver: {
|
||||
type: Number,
|
||||
default: 1.1
|
||||
},
|
||||
sysCount: Number,
|
||||
lastLogin: { type : Date, default: Date.now }
|
||||
})
|
||||
|
||||
/**
|
||||
* Password hash middleware.
|
||||
*/
|
||||
UserSchema.pre("save", function(next) {
|
||||
var user = this
|
||||
if (!user.isModified("password")) return next()
|
||||
bcrypt.genSalt(8, (err, salt) => {
|
||||
if (err) return next(err)
|
||||
bcrypt.hash(user.password, salt, null, (err, hash) => {
|
||||
if (err) return next(err)
|
||||
user.password = hash;
|
||||
user.local.password = hash;
|
||||
next()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Defining our own custom document instance method
|
||||
*/
|
||||
UserSchema.methods = {
|
||||
comparePassword: function(candidatePassword, cb) {
|
||||
bcrypt.compare(candidatePassword, this.local.password, (err, isMatch) => {
|
||||
if (err) return cb(err)
|
||||
cb(null, isMatch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statics
|
||||
*/
|
||||
UserSchema.statics = {}
|
||||
|
||||
module.exports = mongoose.model("User", UserSchema)
|
||||
5
admin/server/public/style/style.css
Normal file
5
admin/server/public/style/style.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.field {
|
||||
padding-top: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
Reference in New Issue
Block a user