492 lines
11 KiB
TypeScript
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" });
|
|
}
|
|
}
|