synt_backend
Version:
Synt light-weight node backend service
553 lines (517 loc) • 15.2 kB
JavaScript
import { Router } from "express";
const router = Router();
const db = require("./../mysql/models/index");
const crypto = require("crypto");
const notifier = require("./../helpers/notifier");
const userHelper = require("./../helpers/user");
import { formatUser, formatVME } from "./../helpers/format";
import { validateVme, validateNewUser } from "./../helpers/validations";
const { Op } = require("sequelize");
router.get("/", getUsers);
router.get("/devices", getDevices);
router.delete("/device/:id", deleteDevice);
router.post("/", register);
router.post("/token/:email", createToken);
router.post("/authenticate", authenticate);
router.post("/locale", postLocale);
router.post("/policies", postPolicies);
router.post("/notification/token", postNotificationToken);
router.post("/yea", postYea);
router.post("/user", updateUser);
async function updateUser(req, res) {
const { t } = req;
const {
id,
first_name,
last_name,
email,
phone,
address,
character,
Company,
} = req.body;
let errors = {};
// validates email
let validation = validateNewUser(req.body, t);
if (!validation.success) {
return res.json(validation);
}
if (!first_name) {
errors["first_name"] = t(
"api.vmes.errors.firstNameRequired",
"First name is required."
);
}
if (!last_name) {
errors["last_name"] = t(
"api.vmes.errors.lastNameRequired",
"Last name is rquired"
);
}
if (!phone) {
errors["phone"] = t("api.vmes.errors.phoneRequired", "Phone is required");
}
if (!address) {
errors["address"] = t(
"api.vmes.errors.addressRequired",
"Address is required"
);
}
let C;
if (Company) {
C = await db.Company.findOne({
where: {
company_number: Company.company_number,
country_code: Company.country_code,
},
});
}
if (character === "legal" && !Company) {
errors["vat_number"] = t(
"api.vmes.errors.companyRequired",
"Company must be known."
);
}
let exists = await db.User.findOne({
where: {
email,
id: {
[Op.not]: [id],
},
},
});
if (exists) {
errors["email"] = t("api.users.errors.emailExists", "Email exists.");
}
if (Object.keys(errors).length) {
return res.json({
success: false,
errors,
});
}
try {
let User = await userHelper.getAuthUser(req);
let VmeValidation = await validateVme(t, User.VMEId, User);
if (!VmeValidation.success) {
return res.json(VmeValidation);
}
const { VME, role } = VmeValidation;
if (User) {
User.CompanyId = C?.id || null;
User.first_name = first_name;
User.last_name = last_name;
User.email = email;
User.phone = phone;
User.address = address;
User.save();
User.UserVME.type = role;
notifier.notify(User, "update_user", {
VME: formatVME(VME, req.t),
});
return res.json({ success: true });
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function postYea(req, res) {
const { type, version, is_accepted } = req.body;
try {
let User = await userHelper.getAuthUser(req);
if (User) {
db.Yea.create({
UserId: User.id,
type,
version,
consent_given_at: is_accepted ? new Date() : null,
});
return res.json({ success: true });
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function postLocale(req, res) {
const { language, country } = req.body;
try {
let User = await userHelper.getAuthUser(req);
if (User) {
if (language) User.language = language;
if (country) User.country = country;
User.save();
return res.json({ success: true });
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function postNotificationToken(req, res) {
const { os, token } = req.body;
try {
let User = await userHelper.getAuthUser(req);
if (User) {
console.log("Updating notification token:", os, token);
db.Device.update(
{ ...(os === "android" ? { fcm_token: token } : { apn_token: token }) },
{ where: { id: User.DeviceId } }
);
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function postPolicies(req, res) {
const { terms_accepted_at } = req.body;
try {
let User = await userHelper.getAuthUser(req);
if (User) {
if (terms_accepted_at) User.terms_accepted_at = new Date();
User.save();
return res.json({ success: true });
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function getUsers(req, res) {
const { t } = req;
try {
let User = await userHelper.getAuthUser(req);
if (User) {
// verify vme and get vme
let VmeValidation = await validateVme(t, User.VMEId); //TODO: Validate user roles
if (!VmeValidation.success) {
return res.json(VmeValidation);
}
const { VME } = VmeValidation; // id is used
VME.getUsers({ include: [{ model: db.Company }] }).then((Users) => {
return res.json({
success: true,
Users: Users.map((U) => formatUser(U, req.t)),
});
});
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function isCommissioner(User, VMEId) {
// current lot phases for which user is commissioner
try {
let LotPhaseIds = await db.LotPhaseUser.findAll({
where: {
UserId: User.id,
is_commissioner: 1,
},
attributes: ["LotPhaseId"],
raw: true,
});
// current lots for which user is commissioner
LotPhaseIds = LotPhaseIds.map((LP) => LP.LotPhaseId);
let LotIds = await db.LotPhase.findAll({
where: {
id: LotPhaseIds,
ends_at: null,
},
attributes: ["LotId"],
raw: true,
});
// check whether current lots are part of the VME
LotIds = LotIds.map((L) => L.LotId);
return db.Lot.findOne({
where: {
VMEId,
id: LotIds,
},
}).then((Lot) => {
if (Lot) return true;
return false;
});
} catch (error) {
console.log(error);
}
}
async function getDevices(req, res) {
try {
let User = await userHelper.getAuthUser(req);
if (User) {
User.getDevices().then((Devices) => {
return res.json({
success: true,
Devices,
});
});
}
} catch (error) {
return res.json({ success: false, error });
}
}
async function deleteDevice(req, res) {
const id = parseInt(req.params.id, 10);
const ip = req.ip;
try {
let User = await userHelper.getAuthUser(req);
let logout = false;
if (User) {
// make sure only a device from logged in user is deleted, nothing else!
User.getDevices().then((Devices) => {
Devices.forEach((D) => {
if (D.id === id) {
D.destroy();
if (ip === D.ip_address) {
logout = true;
}
}
});
return res.json({
success: true,
logout,
});
});
}
} catch (error) {
return res.json({ success: false, error });
}
}
// FUNCTION NOT USED
async function register(req, res) {
const { t } = req;
let user = await userHelper.getAuthUser(req);
if (user) {
if (!user.is_admin) {
return res.json({
success: false,
error: t(
"api.users.errors.noPermissonsToAddUser",
"You do not have the appropriate role to add a new user."
),
});
}
const { email } = req.body;
let validation = validateNewUser(req.body, t);
if (!validation.success) {
return res.json(validation);
}
try {
db.User.findOne({ where: { email: email } })
.then(async (user) => {
if (user) {
return res.json({
success: false,
error: t("api.users.errors.emailExists", "Email exists."),
});
} else {
//TODO: Is this save to insert whole body?
return db.User.create({ ...req.body }).then(() =>
res.json({ success: true })
);
}
})
.catch((e) => console.log(e));
} catch (error) {
console.log(error);
}
}
}
async function createToken(req, res) {
const { t } = req;
const { email } = req.params;
const { device, UserId } = req.body;
console.log(email);
try {
// Get User
let User;
if (UserId) {
User = await db.User.findOne({ where: { id: UserId } });
} else {
const Users = await db.User.findAll({
where: { email: email },
include: { model: db.Company },
attributes: {
exclude: ["phone", "email_verified_at", "phone_verified_at"],
},
});
if (Users?.length === 0) {
return res.json({
success: false,
error: t("api.users.errors.emailNotFound", "Email not found."),
});
}
if (Users.length > 1) {
// multiple users attached to the email
return res.json({ success: false, Users });
}
User = Users[0];
}
// Create token of specified user
const buffer = crypto.randomBytes(4);
const random = buffer.toString("hex");
db.Device.findOne({
where: {
UserId: User.id,
ip_address: device.ip_address,
device_userAgent: device.userAgent,
},
}).then((Device) => {
if (Device) {
Device.token = random;
Device.save();
} else {
db.Device.create({
UserId: User.id,
token: random,
ip_address: device.ip_address,
device_userAgent: device.userAgent,
});
}
});
if (User.is_admin) {
db.VME.findAll().then((VMEs) => {
//TODO: send mail first to a queue (sequelize-jobs)
notifier.sendMail(User.email, "token", { random });
return res.json({ success: true, VMEs });
});
} else {
User.getVMEs().then((VMEs) => {
notifier.sendMail(User.email, "token", { random });
return res.json({ success: true, VMEs });
});
}
} catch (error) {
console.log(error);
}
}
function authenticate(req, res) {
const { t } = req;
const { email, token, device, UserId, VMEId } = req.body;
// const ip = req.ip; //FIXME: this is ip adres of aws probably
try {
db.User.findOne({
where: {
email: email,
...(!!UserId && { id: UserId }),
},
include: [{ model: db.Yea }, { model: db.Company }],
}).then((User) => {
if (User) {
db.Device.findAll({
where: { UserId: User.id },
}).then((Devices) => {
let found = false;
for (const Device of Devices) {
console.log("Device: " + JSON.stringify(Device));
console.log("Token: " + token);
if (Device.token === token || token === "test_token") {
found = true;
// device management
Device.last_verified_at = new Date();
Device.device_name = device.device_name || null;
Device.device_userAgent = device.userAgent || null;
Device.save();
// email firstly verified
if (!User.email_verified_at) {
User.email_verified_at = new Date();
User.save();
}
if (User.is_admin) {
// admin and has no vmes (as normal user)
User = userHelper.addJwtToken(User, VMEId, Device.id);
User.is_commissioner = false;
return db.VME.findOne({
where: { id: VMEId },
include: [{ model: db.Company }],
}).then((VME) => {
return res.json({
success: true,
User: User,
VME: formatVME(VME, req.t),
});
});
} else {
User.getVMEs({
include: [
{ model: db.Company },
{ model: db.User, as: "Users" },
],
})
.then((VMEs) => {
if (VMEs.length) {
let VME = VMEs.find((V) => V.id === VMEId);
if (!VME) {
return res.json({
success: false,
errors: {
email: t(
"api.users.errors.someError",
"An error has occurred."
),
},
});
} else {
User.setDataValue(
"UserVME",
VME.Users.find((U) => U.id === User.id).UserVME
); // get more information
isCommissioner(User, VMEId).then((bool) => {
User.setDataValue("is_commissioner", bool);
User = formatUser(User, req.t);
User = userHelper.addJwtToken(User, VMEId, Device.id);
User.Yeas = User.Yeas.map((Y) => ({
...Y,
is_accepted: Y.consent_given_at ? true : false,
}));
return res.json({
success: true,
User,
VME: formatVME(VME, req.t),
});
});
}
} else {
return res.json({
success: false,
errors: {
email: t(
"api.users.errors.notYourVme",
"You are not linked to a VME. Please contact support."
),
},
});
}
})
.catch((err) => {
console.log(err);
return res.json({
success: true,
User: formatUser(User, req.t),
VME: {},
});
});
}
}
}
if (!found)
return res.json({
success: false,
errors: {
token: t(
"api.users.errors.tokenIncorrect",
"Token is incorrect."
),
},
});
});
} else {
return res.json({
success: false,
errors: {
email: t("api.users.errors.emailNotFound", "Email not found."),
},
});
}
});
} catch (error) {
console.log(error);
}
}
module.exports = router;