import { Request, Response } from "express"; import logger from "../logger/logger"; import User from "../models/user"; import { isAccountNameValid, isPasswordValid, isUsernameValid, } from "../validator/validator"; import { CALENDAR_MAX_FUTURE_BOOKING_DAYS, CALENDAR_MAX_SERVICE_DURATION, CALENDAR_MIN_EARLIEST_BOOKING_TIME, Roles, } from "../utils/constants"; import { decodeBase64, getUserSession, hashPassword, matchPassword, newStoreId, newUserId, saveSession, } from "../utils/utils"; import Store from "../models/store"; export async function SignUp(req: Request, res: Response) { try { let { username, accountName, password } = req.body; // validate request if (!username || !accountName || !password) { return res.status(400).send({ err: "invalid request" }); } if (!isUsernameValid(username)) { return res.status(400).send({ err: "invalid request" }); } if (!isAccountNameValid(accountName)) { return res.status(400).send({ err: "invalid request" }); } accountName = accountName.toLowerCase(); // check if user already exists const existingUser = await User.findOne({ where: { account_name: accountName, }, }); if (existingUser) { logger.debug( "User already exists with this accountName: %s", accountName ); return res.status(400).send({ err: "invalid request" }); } // decode password const decodedPassword = decodeBase64(password); if (!isPasswordValid(decodedPassword)) { logger.debug("Password is not valid"); return res.status(400).send({ err: "invalid request" }); } // hash password const hashedPassword = await hashPassword(decodedPassword); // create store let userId = newUserId(); Store.create({ store_id: newStoreId(), owner_user_id: userId, name: username, calendar_max_future_booking_days: CALENDAR_MAX_FUTURE_BOOKING_DAYS, calendar_min_earliest_booking_time: CALENDAR_MIN_EARLIEST_BOOKING_TIME, //calendar_using_primary_calendar: CALENDAR_USING_PRIMARY_CALENDAR, calendar_max_service_duration: CALENDAR_MAX_SERVICE_DURATION, }) .then(async (store) => { logger.debug( "Store created with storeId: %s storeName: %s", store.store_id, store.name ); // create user await User.create({ user_id: userId, store_id: store.store_id, role: Roles.Master, account_name: accountName, username: username, password: hashedPassword, language: "en", // TODO: get language from request analytics_enabled: true, }) .then((user) => { logger.debug( "User created with accountName: %s username: %s", user.account_name, user.username ); // create session saveSession(res, user.user_id, user.username); }) .catch((err) => { logger.error(err); res.status(500).send({ err: "invalid request" }); }); }) .catch((err) => { logger.error(err); res.status(500).send({ err: "invalid request" }); }); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function Login(req: Request, res: Response) { try { let { accountName, password } = req.body; // validate request if (!accountName || !password) { return res.status(400).send({ err: "invalid request" }); } accountName = accountName.toLowerCase(); if (!isAccountNameValid(accountName)) { return res.status(400).send({ err: "invalid request" }); } // check if user exists const user = await User.findOne({ where: { account_name: accountName, }, }); if (!user) { logger.debug( "User does not exist with this accountName: %s", accountName ); return res.status(400).send({ err: "invalid request" }); } // decode password const decodedPassword = decodeBase64(password); if (!isPasswordValid(decodedPassword)) { logger.debug("Password is not valid"); return res.status(400).send({ err: "invalid request" }); } // compare password const match = await matchPassword(decodedPassword, user.password); if (!match) { logger.debug("Password is not valid"); return res.status(400).send({ err: "invalid request" }); } // create session saveSession(res, user.user_id, user.username); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function Logout(req: Request, res: Response) { try { const session = await getUserSession(req); if (!session) { return res.status(401).send({ err: "unauthorized" }); } await session.destroy(); res.status(200).send({ msg: "logout successful" }); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function GetUser(req: Request, res: Response) { try { const session = await getUserSession(req); if (!session) { return res.status(401).send({ err: "unauthorized" }); } const user = await User.findOne({ where: { user_id: session.user_id, }, attributes: [ "user_id", "username", "store_id", "language", "analytics_enabled", ], }); if (!user) { return res.status(401).send({ err: "unauthorized" }); } const stores = await Store.findAll({ where: { owner_user_id: user.user_id, }, attributes: ["store_id", "name"], }); let respData = { user: user, stores: stores, // only temporary until we have a proper permissions system permissions: [] as string[], }; // if user is not a store master, then check if user is a worker if (!stores || stores.length === 0) { const store = await Store.findOne({ where: { store_id: user.store_id, }, attributes: ["store_id", "name"], }); if (!store) { return res.status(401).send({ err: "unauthorized" }); } stores.push(store); respData.stores = stores; respData.permissions.push("calendar"); } else { respData.permissions.push( "settings", "employees", "services", "calendar", "website" ); } res.status(200).send(respData); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function IsAccountNameAvailable(req: Request, res: Response) { try { let { accountName } = req.body; // validate request if (!accountName) { return res.status(400).send({ err: "invalid request" }); } accountName = accountName.toLowerCase(); if (!isAccountNameValid(accountName)) { return res.status(400).send({ err: "invalid request" }); } // check if user exists const user = await User.findOne({ where: { account_name: accountName, }, }); if (user) { logger.debug( "User already exists with this accountName: %s", accountName ); return res.status(400).send({ err: "invalid request" }); } res.status(200).send({ msg: "account name available" }); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function GetUserProfileSettings(req: Request, res: Response) { try { const session = await getUserSession(req); if (!session) { return res.status(401).send({ err: "unauthorized" }); } const user = await User.findOne({ where: { user_id: session.user_id, }, attributes: ["language", "analytics_enabled"], }); res.status(200).json(user); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } } export async function UpdateUserProfileSettings(req: Request, res: Response) { try { const { language, analyticsEnabled } = req.body; if (!language && analyticsEnabled === undefined) { return res.status(400).send({ err: "invalid request" }); } const session = await getUserSession(req); if (!session) { return res.status(401).send({ err: "unauthorized" }); } const user = await User.findOne({ where: { user_id: session.user_id, }, }); if (!user) { return res.status(401).send({ err: "unauthorized" }); } if (language) { user.language = language; } if (analyticsEnabled !== undefined) { user.analytics_enabled = analyticsEnabled; } await user.save(); res.status(200).send({ msg: "user profile settings updated" }); } catch (error) { logger.error(error); res.status(500).send({ err: "invalid request" }); } }