customer-dashboard-api/src/controllers/usersController.ts

492 lines
11 KiB
TypeScript

import { Request, Response } from "express";
import logger, { storeLogger, userLogger } from "../logger/logger";
import {
isEmailValid,
isLanguageCodeValid,
isPasswordValid,
isUserIdValid,
isUsernameValid,
} from "../validator/validator";
import {
decodeBase64,
getUserSession,
hashPassword,
newUserId,
} from "../utils/utils";
import User from "../models/user";
import {
ACCOUNT_STATE,
PAYMENT_PLAN_SETTINGS,
Roles,
USER_ANALYTICS_ENABLED_DEFAULT,
} from "../utils/constants";
import Store from "../models/store";
import {
isTerminPlanerGoogleCalendarConnected,
terminPlanerRequest,
terminPlanerRequestChangeFutureBookingDays,
} from "../utils/terminPlaner";
export async function AddEmployee(req: Request, res: Response) {
try {
let {
storeId,
username,
email,
password,
calendarMaxFutureBookingDays,
calendarMinEarliestBookingTime,
language,
passwordSetOnInitLogging,
} = req.body;
// validate request
if (
!storeId ||
!username ||
!email ||
passwordSetOnInitLogging === undefined ||
(!password && passwordSetOnInitLogging === false) ||
!language ||
!isLanguageCodeValid(language)
) {
return res.status(400).send({ err: "invalid request" });
}
// verify if requester is a store master
const requesterSession = await getUserSession(req);
if (!requesterSession) {
return res.status(401).send({ err: "unauthorized" });
}
const store = await Store.findOne({
where: {
store_id: storeId,
},
});
if (!store) {
return res.status(400).send({ err: "invalid request" });
}
if (store.owner_user_id !== requesterSession.user_id) {
return res.status(401).send({ err: "unauthorized" });
}
// get payment plan of store owner
const storeOwner = await User.findOne({
where: {
user_id: store.owner_user_id,
},
attributes: ["payment_plan"],
});
if (!storeOwner) {
return res.status(400).send({ err: "invalid request" });
}
// check max employees limit by payment plan
const employees = await User.findAll({
where: {
store_id: storeId,
},
});
if (
employees.length - 1 >=
PAYMENT_PLAN_SETTINGS[storeOwner.payment_plan].maxEmployees
) {
return res.status(400).send({ err: "invalid request" });
}
// validate username and email
email = email.toLowerCase();
if (!isUsernameValid(username) || !(await isEmailValid(email))) {
return res.status(400).send({ err: "invalid request" });
}
// check if user already exists
const existingUser = await User.findOne({
where: {
email: email,
},
});
if (existingUser) {
return res.status(400).send({ err: "invalid request" });
}
// create user
const userId = newUserId();
let newUser = {
user_id: userId,
store_id: storeId,
role: Roles.Worker,
email: email,
username: username,
calendar_max_future_booking_days: calendarMaxFutureBookingDays,
calendar_min_earliest_booking_time: calendarMinEarliestBookingTime,
language: language,
analytics_enabled: USER_ANALYTICS_ENABLED_DEFAULT,
state: passwordSetOnInitLogging
? ACCOUNT_STATE.INIT_LOGIN
: ACCOUNT_STATE.ACTIVE,
payment_plan: storeOwner.payment_plan,
};
if (!passwordSetOnInitLogging) {
// decode password
const decodedPassword = decodeBase64(password);
if (!isPasswordValid(decodedPassword)) {
return res.status(400).send({ err: "invalid request" });
}
// hash password
const hashedPassword = await hashPassword(decodedPassword);
newUser = {
...newUser,
password: hashedPassword,
} as {
user_id: string;
store_id: any;
role: string;
email: any;
username: any;
calendar_max_future_booking_days: any;
calendar_min_earliest_booking_time: any;
language: any;
analytics_enabled: boolean;
password: string;
state: number;
payment_plan: number;
};
}
await User.create(newUser);
const googleCalendarConnected = await isTerminPlanerGoogleCalendarConnected(
store.owner_user_id
);
// only request terminplaner if google calendar is connected
if (googleCalendarConnected) {
try {
await terminPlanerRequest("/api/v1/addUser", "POST", {
userId: userId,
});
storeLogger.info(
storeId,
"Added employee with email:",
email,
"username:",
username,
"passwordSetOnInitLogging:",
passwordSetOnInitLogging
);
return res.status(200).send({ msg: "success" });
} catch (err) {
// remove user from database if terminplaner request failed
await User.destroy({
where: {
user_id: userId,
},
});
logger.error("terminPlanerRequest err on add employee:", err);
return res.status(500).send({ err: "invalid request" });
}
}
storeLogger.info(
storeId,
"Added employee with email:",
email,
"username:",
username,
"passwordSetOnInitLogging:",
passwordSetOnInitLogging
);
res.status(200).send({ msg: "success" });
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}
export async function GetEmployees(req: Request, res: Response) {
try {
let { storeId } = req.params;
const requesterSession = await getUserSession(req);
if (!requesterSession) {
logger.debug("Requester session not found");
return res.status(401).send({ err: "unauthorized" });
}
// verify if requester is a store master
const store = await Store.findOne({
where: {
store_id: storeId,
},
attributes: [
"owner_user_id",
"calendar_max_future_booking_days",
"calendar_min_earliest_booking_time",
],
});
if (!store) {
logger.debug("Store not found");
return res.status(400).send({ err: "invalid request" });
}
if (store.owner_user_id !== requesterSession.user_id) {
logger.debug("Requester is not the store owner");
return res.status(401).send({ err: "unauthorized" });
}
// find all employees of the requester
const employees = await User.findAll({
where: {
store_id: storeId,
},
attributes: [
"user_id",
"username",
"email",
"calendar_max_future_booking_days",
"calendar_min_earliest_booking_time",
],
});
// filter out the requester from the employees
const filteredEmployees = employees.filter(
(employee) => employee.user_id !== requesterSession.user_id
);
userLogger.info(requesterSession.user_id, "GetEmployees");
res.status(200).send({
storeSettings: {
calendar_max_future_booking_days:
store.calendar_max_future_booking_days,
calendar_min_earliest_booking_time:
store.calendar_min_earliest_booking_time,
},
employees: filteredEmployees,
});
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}
export async function UpdateEmployee(req: Request, res: Response) {
try {
let {
userId,
username,
email,
calendarMaxFutureBookingDays,
calendarMinEarliestBookingTime,
} = req.body;
if (!isUserIdValid(userId)) {
return res.status(400).send({ err: "invalid request" });
}
// verify if requester is a store master
const requesterSession = await getUserSession(req);
if (!requesterSession) {
return res.status(401).send({ err: "unauthorized" });
}
const store = await Store.findOne({
where: {
owner_user_id: requesterSession.user_id,
},
attributes: ["store_id"],
});
if (!store) {
return res.status(400).send({ err: "invalid request" });
}
// check if user exists
const existingUser = await User.findOne({
where: {
user_id: userId,
},
});
if (!existingUser) {
return res.status(400).send({ err: "invalid request" });
}
// update data
let update = {};
if (email) {
email = email.toLowerCase();
if (!(await isEmailValid(email))) {
res.status(400).send({ err: "invalid request" });
return;
}
update = {
...update,
email: email,
};
}
if (username) {
if (!isUsernameValid(username)) {
res.status(400).send({ err: "invalid request" });
return;
}
update = {
...update,
username: username,
};
}
if (calendarMaxFutureBookingDays) {
update = {
...update,
calendar_max_future_booking_days: calendarMaxFutureBookingDays,
};
}
if (calendarMinEarliestBookingTime) {
update = {
...update,
calendar_min_earliest_booking_time: calendarMinEarliestBookingTime,
};
await terminPlanerRequestChangeFutureBookingDays(store.store_id);
}
if (Object.keys(update).length === 0) {
return res.status(400).send({ err: "invalid request" });
}
// update user
await User.update(update, {
where: {
user_id: userId,
},
});
storeLogger.info(
store.store_id,
"Updated employee with user id:",
userId,
"username:",
username,
"email:",
email
);
res.status(200).send({ msg: "success" });
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}
export async function DeleteEmployee(req: Request, res: Response) {
try {
let { userId } = req.body;
// validate request
if (!userId) {
return res.status(400).send({ err: "invalid request" });
}
// verify if requester is a store master
const requesterSession = await getUserSession(req);
if (!requesterSession) {
return res.status(401).send({ err: "unauthorized" });
}
const store = await Store.findOne({
where: {
owner_user_id: requesterSession.user_id,
},
attributes: ["store_id", "owner_user_id"],
});
if (!store) {
return res.status(400).send({ err: "invalid request" });
}
// check if user exists
const existingUser = await User.findOne({
where: {
user_id: userId,
},
});
if (!existingUser) {
return res.status(400).send({ err: "invalid request" });
}
const googleCalendarConnected = await isTerminPlanerGoogleCalendarConnected(
store.owner_user_id
);
// only request terminplaner if google calendar is connected
if (googleCalendarConnected) {
await terminPlanerRequest("/api/v1/removeUser", "POST", {
userId: userId,
});
}
await User.destroy({
where: {
user_id: userId,
},
});
storeLogger.info(store.store_id, "Deleted employee with user id:", userId);
res.status(200).send({ msg: "success" });
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}