services
parent
366e3f3b23
commit
da0814bcf5
|
@ -4,6 +4,8 @@ import bodyParser from "body-parser";
|
||||||
import swaggerUI from "swagger-ui-express";
|
import swaggerUI from "swagger-ui-express";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
|
||||||
|
import storeRoutes from "./src/routes/storeRoutes";
|
||||||
|
import storeServicesRoutes from "./src/routes/storeServicesRoutes";
|
||||||
import userRoutes from "./src/routes/userRoutes";
|
import userRoutes from "./src/routes/userRoutes";
|
||||||
import usersRoutes from "./src/routes/usersRoutes";
|
import usersRoutes from "./src/routes/usersRoutes";
|
||||||
|
|
||||||
|
@ -44,6 +46,8 @@ const options = {
|
||||||
// TODO: add cors
|
// TODO: add cors
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
app.use("/api/v1/store", storeRoutes);
|
||||||
|
app.use("/api/v1/store/services", storeServicesRoutes);
|
||||||
app.use("/api/v1/user", userRoutes);
|
app.use("/api/v1/user", userRoutes);
|
||||||
app.use("/api/v1/users", usersRoutes);
|
app.use("/api/v1/users", usersRoutes);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import Store from "../models/store";
|
||||||
|
import { getUserSession } from "../utils/utils";
|
||||||
|
import logger from "../logger/logger";
|
||||||
|
|
||||||
|
export async function GetStore(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { storeId } = req.params;
|
||||||
|
|
||||||
|
if (!storeId) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if requester is the store owner
|
||||||
|
|
||||||
|
const userSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = await Store.findOne({
|
||||||
|
where: {
|
||||||
|
store_id: storeId,
|
||||||
|
},
|
||||||
|
attributes: ["owner_user_id", "name"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!store) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.owner_user_id !== userSession.user_id) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send({ store: { name: store.name } });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,338 @@
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import StoreService from "../models/storeService";
|
||||||
|
import {
|
||||||
|
getUserSession,
|
||||||
|
newStoreServiceActivityId,
|
||||||
|
newStoreServiceId,
|
||||||
|
} from "../utils/utils";
|
||||||
|
import {
|
||||||
|
isStoreServiceActivityDescriptionValid,
|
||||||
|
isStoreServiceActivityDurationValid,
|
||||||
|
isStoreServiceActivityNameValid,
|
||||||
|
isStoreServiceActivityPriceValid,
|
||||||
|
isStoreServiceNameValid,
|
||||||
|
} from "../validator/validator";
|
||||||
|
import Store from "../models/store";
|
||||||
|
import logger from "../logger/logger";
|
||||||
|
import StoreServiceActivity from "../models/storeServiceActivity";
|
||||||
|
import StoreServiceActivityUsers from "../models/storeServiceActivityUsers";
|
||||||
|
import User from "../models/user";
|
||||||
|
|
||||||
|
export async function GetStoreServices(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { storeId } = req.params;
|
||||||
|
|
||||||
|
if (!storeId) {
|
||||||
|
logger.debug("Invalid request");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const services = await StoreService.findAll({
|
||||||
|
where: {
|
||||||
|
store_id: storeId,
|
||||||
|
},
|
||||||
|
attributes: ["service_id", "name"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// get all users assigned to the store
|
||||||
|
// this user list will be used in the ui to show if no users are selected for a service activity
|
||||||
|
|
||||||
|
const users = await User.findAll({
|
||||||
|
where: {
|
||||||
|
store_id: storeId,
|
||||||
|
},
|
||||||
|
attributes: ["user_id", "username"],
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({ services, users });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function CreateStoreService(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { storeId, name } = req.body;
|
||||||
|
|
||||||
|
if (!storeId || !name || !isStoreServiceNameValid(name)) {
|
||||||
|
logger.debug("Invalid request");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if requester is the store owner
|
||||||
|
|
||||||
|
const userSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
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 !== userSession.user_id) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// create store service
|
||||||
|
|
||||||
|
const service = await StoreService.create({
|
||||||
|
service_id: newStoreServiceId(),
|
||||||
|
store_id: storeId,
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({ service });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function UpdateStoreService(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { serviceId, name } = req.body;
|
||||||
|
|
||||||
|
if (!serviceId || !name || !isStoreServiceNameValid(name)) {
|
||||||
|
logger.debug("Invalid request");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if requester is the store owner
|
||||||
|
|
||||||
|
const userSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = await StoreService.findOne({
|
||||||
|
where: {
|
||||||
|
service_id: serviceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = await Store.findOne({
|
||||||
|
where: {
|
||||||
|
store_id: service.store_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!store) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.owner_user_id !== userSession.user_id) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// update store service
|
||||||
|
|
||||||
|
await StoreService.update(
|
||||||
|
{
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
service_id: serviceId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
res.status(200).send({ msg: "success" });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function CreateStoreServiceActivity(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { serviceId, name, description, price, duration } = req.body;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!serviceId ||
|
||||||
|
!name ||
|
||||||
|
!isStoreServiceActivityNameValid(name) ||
|
||||||
|
!isStoreServiceActivityDescriptionValid(description) ||
|
||||||
|
!isStoreServiceActivityPriceValid(price) ||
|
||||||
|
!isStoreServiceActivityDurationValid(duration)
|
||||||
|
) {
|
||||||
|
logger.debug("Invalid request");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if requester is the store owner
|
||||||
|
|
||||||
|
const userSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = await StoreService.findOne({
|
||||||
|
where: {
|
||||||
|
service_id: serviceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = await Store.findOne({
|
||||||
|
where: {
|
||||||
|
store_id: service.store_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!store) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.owner_user_id !== userSession.user_id) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// create store service activity
|
||||||
|
|
||||||
|
const activity = await StoreServiceActivity.create({
|
||||||
|
activity_id: newStoreServiceActivityId(),
|
||||||
|
service_id: serviceId,
|
||||||
|
name: name,
|
||||||
|
description: description,
|
||||||
|
price: price,
|
||||||
|
duration: duration,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({ activity });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GetStoreServiceActivities(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { storeId, serviceId } = req.params;
|
||||||
|
|
||||||
|
if (!storeId || !serviceId) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const activities = await StoreServiceActivity.findAll({
|
||||||
|
where: {
|
||||||
|
service_id: serviceId,
|
||||||
|
},
|
||||||
|
attributes: ["activity_id", "name", "description", "price", "duration"],
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
activities.forEach(async (activity) => {
|
||||||
|
const assignedUsers = await StoreServiceActivityUsers.findAll({
|
||||||
|
where: {
|
||||||
|
activity_id: activity.activity_id,
|
||||||
|
},
|
||||||
|
attributes: ["user_id"],
|
||||||
|
});
|
||||||
|
}); */
|
||||||
|
|
||||||
|
res.status(200).send({ activities });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function UpdateStoreServiceActivity(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { activityId, name, description, price, duration } = req.body;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!activityId ||
|
||||||
|
!name ||
|
||||||
|
!isStoreServiceActivityNameValid(name) ||
|
||||||
|
!isStoreServiceActivityDescriptionValid(description) ||
|
||||||
|
!isStoreServiceActivityPriceValid(price) ||
|
||||||
|
!isStoreServiceActivityDurationValid(duration)
|
||||||
|
) {
|
||||||
|
logger.debug("Invalid request");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if requester is the store owner
|
||||||
|
|
||||||
|
const userSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const activity = await StoreServiceActivity.findOne({
|
||||||
|
where: {
|
||||||
|
activity_id: activityId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!activity) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = await StoreService.findOne({
|
||||||
|
where: {
|
||||||
|
service_id: activity.service_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = await Store.findOne({
|
||||||
|
where: {
|
||||||
|
store_id: service.store_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!store) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.owner_user_id !== userSession.user_id) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// update store service activity
|
||||||
|
|
||||||
|
await StoreServiceActivity.update(
|
||||||
|
{
|
||||||
|
name: name,
|
||||||
|
description: description,
|
||||||
|
price: price,
|
||||||
|
duration: duration,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
activity_id: activityId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
res.status(200).send({ msg: "success" });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,24 @@ import {
|
||||||
isPasswordValid,
|
isPasswordValid,
|
||||||
isUsernameValid,
|
isUsernameValid,
|
||||||
} from "../validator/validator";
|
} from "../validator/validator";
|
||||||
import { Roles } from "../utils/constants";
|
import {
|
||||||
|
CALENDAR_MAX_FUTURE_BOOKING_DAYS,
|
||||||
|
CALENDAR_MAX_SERVICE_DURATION,
|
||||||
|
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||||
|
CALENDAR_PRIMARY_CALENDAR_ID,
|
||||||
|
CALENDAR_USING_PRIMARY_CALENDAR,
|
||||||
|
Roles,
|
||||||
|
} from "../utils/constants";
|
||||||
import {
|
import {
|
||||||
decodeBase64,
|
decodeBase64,
|
||||||
getUserSession,
|
getUserSession,
|
||||||
hashPassword,
|
hashPassword,
|
||||||
matchPassword,
|
matchPassword,
|
||||||
|
newStoreId,
|
||||||
newUserId,
|
newUserId,
|
||||||
saveSession,
|
saveSession,
|
||||||
} from "../utils/utils";
|
} from "../utils/utils";
|
||||||
|
import Store from "../models/store";
|
||||||
|
|
||||||
export async function SignUp(req: Request, res: Response) {
|
export async function SignUp(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
|
@ -65,24 +74,51 @@ export async function SignUp(req: Request, res: Response) {
|
||||||
|
|
||||||
const hashedPassword = await hashPassword(decodedPassword);
|
const hashedPassword = await hashPassword(decodedPassword);
|
||||||
|
|
||||||
// create user
|
// create store
|
||||||
|
|
||||||
await User.create({
|
let userId = newUserId();
|
||||||
user_id: newUserId(),
|
|
||||||
role: Roles.Master,
|
Store.create({
|
||||||
account_name: accountName,
|
store_id: newStoreId(),
|
||||||
username: username,
|
owner_user_id: userId,
|
||||||
password: hashedPassword,
|
name: username,
|
||||||
|
calendar_max_future_booking_days: CALENDAR_MAX_FUTURE_BOOKING_DAYS,
|
||||||
|
calendar_min_earliest_booking_time: CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||||
|
calendar_primary_calendar_id: CALENDAR_PRIMARY_CALENDAR_ID,
|
||||||
|
calendar_using_primary_calendar: CALENDAR_USING_PRIMARY_CALENDAR,
|
||||||
|
calendar_max_service_duration: CALENDAR_MAX_SERVICE_DURATION,
|
||||||
})
|
})
|
||||||
.then((user) => {
|
.then(async (store) => {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"User created with accountName: %s username: %s",
|
"Store created with storeId: %s storeName: %s",
|
||||||
user.account_name,
|
store.store_id,
|
||||||
user.username
|
store.name
|
||||||
);
|
);
|
||||||
|
|
||||||
// create session
|
// create user
|
||||||
saveSession(res, user.user_id, user.username);
|
|
||||||
|
await User.create({
|
||||||
|
user_id: userId,
|
||||||
|
store_id: store.store_id,
|
||||||
|
role: Roles.Master,
|
||||||
|
account_name: accountName,
|
||||||
|
username: username,
|
||||||
|
password: hashedPassword,
|
||||||
|
})
|
||||||
|
.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) => {
|
.catch((err) => {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
|
@ -180,13 +216,60 @@ export async function GetUser(req: Request, res: Response) {
|
||||||
where: {
|
where: {
|
||||||
user_id: session.user_id,
|
user_id: session.user_id,
|
||||||
},
|
},
|
||||||
|
attributes: ["user_id", "username"],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(401).send({ err: "unauthorized" });
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send({ username: user.username });
|
const stores = await Store.findAll({
|
||||||
|
where: {
|
||||||
|
owner_user_id: user.user_id,
|
||||||
|
},
|
||||||
|
attributes: ["store_id", "name"],
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({ user, stores });
|
||||||
|
} 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) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
res.status(500).send({ err: "invalid request" });
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
|
|
@ -3,6 +3,7 @@ import logger from "../logger/logger";
|
||||||
import {
|
import {
|
||||||
isAccountNameValid,
|
isAccountNameValid,
|
||||||
isPasswordValid,
|
isPasswordValid,
|
||||||
|
isUserIdValid,
|
||||||
isUsernameValid,
|
isUsernameValid,
|
||||||
} from "../validator/validator";
|
} from "../validator/validator";
|
||||||
import {
|
import {
|
||||||
|
@ -16,11 +17,11 @@ import { Roles } from "../utils/constants";
|
||||||
|
|
||||||
export async function AddEmployee(req: Request, res: Response) {
|
export async function AddEmployee(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
let { username, accountName, password } = req.body;
|
let { storeId, username, accountName, password } = req.body;
|
||||||
|
|
||||||
// validate request
|
// validate request
|
||||||
|
|
||||||
if (!username || !accountName || !password) {
|
if (!storeId || !username || !accountName || !password) {
|
||||||
return res.status(400).send({ err: "invalid request" });
|
return res.status(400).send({ err: "invalid request" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +54,10 @@ export async function AddEmployee(req: Request, res: Response) {
|
||||||
|
|
||||||
accountName = accountName.toLowerCase();
|
accountName = accountName.toLowerCase();
|
||||||
|
|
||||||
if (!isUsernameValid(username)) {
|
if (
|
||||||
return res.status(400).send({ err: "invalid request" });
|
!isUsernameValid(username) ||
|
||||||
}
|
!(await isAccountNameValid(accountName))
|
||||||
|
) {
|
||||||
if (!isAccountNameValid(accountName)) {
|
|
||||||
return res.status(400).send({ err: "invalid request" });
|
return res.status(400).send({ err: "invalid request" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,11 +94,11 @@ export async function AddEmployee(req: Request, res: Response) {
|
||||||
|
|
||||||
await User.create({
|
await User.create({
|
||||||
user_id: newUserId(),
|
user_id: newUserId(),
|
||||||
|
store_id: storeId,
|
||||||
role: Roles.Worker,
|
role: Roles.Worker,
|
||||||
account_name: accountName,
|
account_name: accountName,
|
||||||
username: username,
|
username: username,
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
master_user_id: requester.user_id,
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.status(200).send({ msg: "success" });
|
res.status(200).send({ msg: "success" });
|
||||||
|
@ -115,6 +115,8 @@ export async function AddEmployee(req: Request, res: Response) {
|
||||||
|
|
||||||
export async function GetEmployees(req: Request, res: Response) {
|
export async function GetEmployees(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
|
let { storeId } = req.params;
|
||||||
|
|
||||||
const requesterSession = await getUserSession(req);
|
const requesterSession = await getUserSession(req);
|
||||||
|
|
||||||
if (!requesterSession) {
|
if (!requesterSession) {
|
||||||
|
@ -126,18 +128,191 @@ export async function GetEmployees(req: Request, res: Response) {
|
||||||
|
|
||||||
const employees = await User.findAll({
|
const employees = await User.findAll({
|
||||||
where: {
|
where: {
|
||||||
master_user_id: requesterSession.user_id,
|
store_id: storeId,
|
||||||
},
|
},
|
||||||
attributes: ["username", "account_name"],
|
attributes: ["user_id", "username", "account_name"],
|
||||||
});
|
});
|
||||||
|
|
||||||
// simulate a delay
|
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 4000));
|
|
||||||
|
|
||||||
res.status(200).send({ employees: employees });
|
res.status(200).send({ employees: employees });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
res.status(500).send({ err: "invalid request" });
|
res.status(500).send({ err: "invalid request" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function UpdateEmployee(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
let { userId, username, accountName } = req.body;
|
||||||
|
|
||||||
|
// validate request
|
||||||
|
// check if username or account name is provided
|
||||||
|
|
||||||
|
if (!userId || (!username && !accountName)) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate username and account name
|
||||||
|
|
||||||
|
if (!isUserIdValid(userId)) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
let update = {};
|
||||||
|
|
||||||
|
if (accountName) {
|
||||||
|
accountName = accountName.toLowerCase();
|
||||||
|
|
||||||
|
if (!(await isAccountNameValid(accountName))) {
|
||||||
|
res.status(400).send({ err: "invalid request" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
account_name: accountName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username) {
|
||||||
|
if (!isUsernameValid(username)) {
|
||||||
|
res.status(400).send({ err: "invalid request" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
username: username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify if requester is a store master
|
||||||
|
|
||||||
|
const requesterSession = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!requesterSession) {
|
||||||
|
logger.debug("Requester session not found");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const requester = await User.findOne({
|
||||||
|
where: {
|
||||||
|
user_id: requesterSession.user_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!requester) {
|
||||||
|
logger.debug("Requester not found");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requester.role !== Roles.Master) {
|
||||||
|
logger.debug("Requester is not a store master");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if user exists
|
||||||
|
|
||||||
|
const existingUser = await User.findOne({
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
logger.debug("User not found");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// update user
|
||||||
|
|
||||||
|
await User.update(
|
||||||
|
{
|
||||||
|
username: username,
|
||||||
|
account_name: accountName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
res.status(200).send({ msg: "success" });
|
||||||
|
})
|
||||||
|
.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 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) {
|
||||||
|
logger.debug("Requester session not found");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const requester = await User.findOne({
|
||||||
|
where: {
|
||||||
|
user_id: requesterSession.user_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!requester) {
|
||||||
|
logger.debug("Requester not found");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requester.role !== Roles.Master) {
|
||||||
|
logger.debug("Requester is not a store master");
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if user exists
|
||||||
|
|
||||||
|
const existingUser = await User.findOne({
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
logger.debug("User not found");
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete user
|
||||||
|
|
||||||
|
await User.destroy({
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
res.status(200).send({ msg: "success" });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.error(err);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
import Session from "./session";
|
import Session from "./session";
|
||||||
|
import Store from "./store";
|
||||||
|
import StoreService from "./storeService";
|
||||||
|
import StoreServiceActivity from "./storeServiceActivity";
|
||||||
|
import StoreServiceActivityUsers from "./storeServiceActivityUsers";
|
||||||
|
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
|
|
||||||
function syncModels() {
|
function syncModels() {
|
||||||
User.sync({ alter: true });
|
User.sync();
|
||||||
Session.sync({ alter: true });
|
Session.sync();
|
||||||
|
Store.sync();
|
||||||
|
StoreService.sync();
|
||||||
|
StoreServiceActivity.sync();
|
||||||
|
StoreServiceActivityUsers.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default syncModels;
|
export default syncModels;
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { DataTypes, Model } from "sequelize";
|
||||||
|
import sequelize from "../database/database";
|
||||||
|
|
||||||
|
interface StoreAttributes {
|
||||||
|
store_id: string;
|
||||||
|
owner_user_id: string;
|
||||||
|
name: string;
|
||||||
|
calendar_max_future_booking_days: number;
|
||||||
|
calendar_min_earliest_booking_time: number;
|
||||||
|
calendar_primary_calendar_id: string;
|
||||||
|
calendar_using_primary_calendar: boolean;
|
||||||
|
calendar_max_service_duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Store extends Model<StoreAttributes> implements StoreAttributes {
|
||||||
|
declare store_id: string;
|
||||||
|
declare owner_user_id: string;
|
||||||
|
declare name: string;
|
||||||
|
declare calendar_max_future_booking_days: number;
|
||||||
|
declare calendar_min_earliest_booking_time: number;
|
||||||
|
declare calendar_primary_calendar_id: string;
|
||||||
|
declare calendar_using_primary_calendar: boolean;
|
||||||
|
declare calendar_max_service_duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
Store.init(
|
||||||
|
{
|
||||||
|
// Model attributes are defined here
|
||||||
|
store_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
owner_user_id: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
calendar_max_future_booking_days: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
calendar_min_earliest_booking_time: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
calendar_primary_calendar_id: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
calendar_using_primary_calendar: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
calendar_max_service_duration: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: "stores",
|
||||||
|
sequelize, // passing the `sequelize` instance is required
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Store;
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { DataTypes, Model } from "sequelize";
|
||||||
|
import sequelize from "../database/database";
|
||||||
|
|
||||||
|
interface StoreServiceAttributes {
|
||||||
|
service_id: string;
|
||||||
|
store_id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StoreService
|
||||||
|
extends Model<StoreServiceAttributes>
|
||||||
|
implements StoreServiceAttributes
|
||||||
|
{
|
||||||
|
declare service_id: string;
|
||||||
|
declare store_id: string;
|
||||||
|
declare name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreService.init(
|
||||||
|
{
|
||||||
|
// Model attributes are defined here
|
||||||
|
service_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
store_id: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: "store_services",
|
||||||
|
sequelize, // passing the `sequelize` instance is required
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default StoreService;
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { DataTypes, Model } from "sequelize";
|
||||||
|
import sequelize from "../database/database";
|
||||||
|
|
||||||
|
interface StoreServiceActivityAttributes {
|
||||||
|
activity_id: string;
|
||||||
|
service_id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
price: number;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StoreServiceActivity
|
||||||
|
extends Model<StoreServiceActivityAttributes>
|
||||||
|
implements StoreServiceActivityAttributes
|
||||||
|
{
|
||||||
|
declare activity_id: string;
|
||||||
|
declare service_id: string;
|
||||||
|
declare name: string;
|
||||||
|
declare description: string;
|
||||||
|
declare price: number;
|
||||||
|
declare duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreServiceActivity.init(
|
||||||
|
{
|
||||||
|
// Model attributes are defined here
|
||||||
|
activity_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
service_id: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: DataTypes.FLOAT,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: "store_service_activities",
|
||||||
|
sequelize, // passing the `sequelize` instance is required
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default StoreServiceActivity;
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { DataTypes, Model } from "sequelize";
|
||||||
|
import sequelize from "../database/database";
|
||||||
|
|
||||||
|
interface StoreServiceActivityUsersAttributes {
|
||||||
|
activity_id: string;
|
||||||
|
user_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StoreServiceActivityUsers
|
||||||
|
extends Model<StoreServiceActivityUsersAttributes>
|
||||||
|
implements StoreServiceActivityUsersAttributes
|
||||||
|
{
|
||||||
|
declare activity_id: string;
|
||||||
|
declare user_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreServiceActivityUsers.init(
|
||||||
|
{
|
||||||
|
// Model attributes are defined here
|
||||||
|
activity_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
user_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: "store_service_activity_users",
|
||||||
|
sequelize, // passing the `sequelize` instance is required
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default StoreServiceActivityUsers;
|
|
@ -3,22 +3,29 @@ import sequelize from "../database/database";
|
||||||
|
|
||||||
interface UserAttributes {
|
interface UserAttributes {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
master_user_id?: string;
|
store_id: string;
|
||||||
|
// TODO: change to role_id
|
||||||
role: string;
|
role: string;
|
||||||
account_name: string;
|
account_name: string;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
calendar_settings?: string;
|
calendar_max_future_booking_days?: number;
|
||||||
|
calendar_min_earliest_booking_time?: number;
|
||||||
|
calendar_primary_calendar_id?: string;
|
||||||
|
calendar_using_primary_calendar?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class User extends Model<UserAttributes> implements UserAttributes {
|
class User extends Model<UserAttributes> implements UserAttributes {
|
||||||
declare user_id: string;
|
declare user_id: string;
|
||||||
declare master_user_id: string;
|
declare store_id: string;
|
||||||
declare role: string;
|
declare role: string;
|
||||||
declare account_name: string;
|
declare account_name: string;
|
||||||
declare username: string;
|
declare username: string;
|
||||||
declare password: string;
|
declare password: string;
|
||||||
declare calendar_settings: string;
|
declare calendar_max_future_booking_days: number;
|
||||||
|
declare calendar_min_earliest_booking_time: number;
|
||||||
|
declare calendar_primary_calendar_id: string;
|
||||||
|
declare calendar_using_primary_calendar: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
User.init(
|
User.init(
|
||||||
|
@ -29,13 +36,13 @@ User.init(
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
master_user_id: {
|
store_id: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
// allowNull defaults to true
|
allowNull: false,
|
||||||
},
|
},
|
||||||
role: {
|
role: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
// allowNull defaults to true
|
allowNull: false,
|
||||||
},
|
},
|
||||||
account_name: {
|
account_name: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
|
@ -49,9 +56,17 @@ User.init(
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
calendar_settings: {
|
calendar_max_future_booking_days: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
},
|
||||||
|
calendar_min_earliest_booking_time: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
},
|
||||||
|
calendar_primary_calendar_id: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
// allowNull defaults to true
|
},
|
||||||
|
calendar_using_primary_calendar: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import express from "express";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
import * as storeController from "../controllers/storeController";
|
||||||
|
|
||||||
|
router.get("/:storeId", storeController.GetStore);
|
||||||
|
|
||||||
|
export default router;
|
|
@ -0,0 +1,19 @@
|
||||||
|
import express from "express";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
import * as storeServicesController from "../controllers/storeServicesController";
|
||||||
|
|
||||||
|
router.get("/:storeId", storeServicesController.GetStoreServices);
|
||||||
|
router.post("/", storeServicesController.CreateStoreService);
|
||||||
|
router.post("/update", storeServicesController.UpdateStoreService);
|
||||||
|
router.post("/activity", storeServicesController.CreateStoreServiceActivity);
|
||||||
|
router.get(
|
||||||
|
"/activities/:storeId/:serviceId",
|
||||||
|
storeServicesController.GetStoreServiceActivities
|
||||||
|
);
|
||||||
|
router.post(
|
||||||
|
"/activity/update",
|
||||||
|
storeServicesController.UpdateStoreServiceActivity
|
||||||
|
);
|
||||||
|
|
||||||
|
export default router;
|
|
@ -8,5 +8,6 @@ router.post("/auth/signup", userController.SignUp);
|
||||||
router.post("/auth/login", userController.Login);
|
router.post("/auth/login", userController.Login);
|
||||||
router.delete("/auth/logout", sessionProtection, userController.Logout);
|
router.delete("/auth/logout", sessionProtection, userController.Logout);
|
||||||
router.get("/", sessionProtection, userController.GetUser);
|
router.get("/", sessionProtection, userController.GetUser);
|
||||||
|
router.post("/auth/check/accountname", userController.IsAccountNameAvailable);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -4,6 +4,8 @@ const router = express.Router();
|
||||||
import * as usersController from "../controllers/usersController";
|
import * as usersController from "../controllers/usersController";
|
||||||
|
|
||||||
router.post("/", usersController.AddEmployee);
|
router.post("/", usersController.AddEmployee);
|
||||||
router.get("/", usersController.GetEmployees);
|
router.get("/:storeId", usersController.GetEmployees);
|
||||||
|
router.post("/update", usersController.UpdateEmployee);
|
||||||
|
router.delete("/", usersController.DeleteEmployee);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export const DEFAULT_SESSION_EXPIRY = 365 * 24 * 60 * 60 * 1000; // 365 days
|
export const DEFAULT_SESSION_EXPIRY = 365 * 24 * 60 * 60 * 1000; // 365 days
|
||||||
|
export const USER_SESSION_LENGTH = 32;
|
||||||
|
|
||||||
export const USERNAME_MIN_LENGTH = 3;
|
export const USERNAME_MIN_LENGTH = 3;
|
||||||
export const USERNAME_MAX_LENGTH = 20;
|
export const USERNAME_MAX_LENGTH = 20;
|
||||||
|
@ -9,9 +10,36 @@ export const ACCOUNT_NAME_MAX_LENGTH = 20;
|
||||||
export const PASSWORD_MIN_LENGTH = 8;
|
export const PASSWORD_MIN_LENGTH = 8;
|
||||||
export const PASSWORD_MAX_LENGTH = 64;
|
export const PASSWORD_MAX_LENGTH = 64;
|
||||||
|
|
||||||
|
export const USER_ID_LENGTH = 36;
|
||||||
|
|
||||||
// Header name for the session ID
|
// Header name for the session ID
|
||||||
export const HEADER_X_AUTHORIZATION: string = "x-authorization";
|
export const HEADER_X_AUTHORIZATION: string = "x-authorization";
|
||||||
|
|
||||||
|
export const STORE_SERVICE_MIN_LENGTH = 3;
|
||||||
|
export const STORE_SERVICE_MAX_LENGTH = 32;
|
||||||
|
|
||||||
|
export const STORE_SERVICE_ACTIVITY_NAME_MIN_LENGTH = 3;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_NAME_MAX_LENGTH = 32;
|
||||||
|
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DESCRIPTION_MIN_LENGTH = 3;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DESCRIPTION_MAX_LENGTH = 1024;
|
||||||
|
|
||||||
|
export const STORE_SERVICE_ACTIVITY_PRICE_MIN = 0;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_PRICE_MAX = 10000000;
|
||||||
|
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DURATION_HOURS_MAX = 23;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DURATION_MINUTES_MAX = 60;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DURATION_MIN = 0;
|
||||||
|
export const STORE_SERVICE_ACTIVITY_DURATION_MAX =
|
||||||
|
STORE_SERVICE_ACTIVITY_DURATION_HOURS_MAX * 60 +
|
||||||
|
STORE_SERVICE_ACTIVITY_DURATION_MINUTES_MAX;
|
||||||
|
|
||||||
|
export const CALENDAR_MAX_FUTURE_BOOKING_DAYS = 14;
|
||||||
|
export const CALENDAR_MIN_EARLIEST_BOOKING_TIME = 1;
|
||||||
|
export const CALENDAR_PRIMARY_CALENDAR_ID = "";
|
||||||
|
export const CALENDAR_USING_PRIMARY_CALENDAR = false;
|
||||||
|
export const CALENDAR_MAX_SERVICE_DURATION = 1440; // 24 hours in minutes
|
||||||
|
|
||||||
export const Roles = {
|
export const Roles = {
|
||||||
// admin of the whole system independent of stores
|
// admin of the whole system independent of stores
|
||||||
Admin: "admin",
|
Admin: "admin",
|
||||||
|
|
|
@ -3,7 +3,11 @@ import bcrypt from "bcrypt";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import Session from "../models/session";
|
import Session from "../models/session";
|
||||||
import { DEFAULT_SESSION_EXPIRY, HEADER_X_AUTHORIZATION } from "./constants";
|
import {
|
||||||
|
DEFAULT_SESSION_EXPIRY,
|
||||||
|
HEADER_X_AUTHORIZATION,
|
||||||
|
USER_SESSION_LENGTH,
|
||||||
|
} from "./constants";
|
||||||
|
|
||||||
export async function matchPassword(decodedPassword: string, password: string) {
|
export async function matchPassword(decodedPassword: string, password: string) {
|
||||||
return await bcrypt.compare(decodedPassword, password);
|
return await bcrypt.compare(decodedPassword, password);
|
||||||
|
@ -21,8 +25,20 @@ export function newUserId() {
|
||||||
return uuidv4();
|
return uuidv4();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function newStoreId() {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function newStoreServiceId() {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function newStoreServiceActivityId() {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
||||||
|
|
||||||
export function newUserSession() {
|
export function newUserSession() {
|
||||||
return crypto.randomBytes(32).toString("hex");
|
return crypto.randomBytes(USER_SESSION_LENGTH).toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveSession(
|
export async function saveSession(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import logger from "../logger/logger";
|
||||||
import {
|
import {
|
||||||
USERNAME_MIN_LENGTH,
|
USERNAME_MIN_LENGTH,
|
||||||
USERNAME_MAX_LENGTH,
|
USERNAME_MAX_LENGTH,
|
||||||
|
@ -5,7 +6,19 @@ import {
|
||||||
PASSWORD_MAX_LENGTH,
|
PASSWORD_MAX_LENGTH,
|
||||||
ACCOUNT_NAME_MIN_LENGTH,
|
ACCOUNT_NAME_MIN_LENGTH,
|
||||||
ACCOUNT_NAME_MAX_LENGTH,
|
ACCOUNT_NAME_MAX_LENGTH,
|
||||||
|
USER_ID_LENGTH,
|
||||||
|
STORE_SERVICE_MIN_LENGTH,
|
||||||
|
STORE_SERVICE_MAX_LENGTH,
|
||||||
|
STORE_SERVICE_ACTIVITY_NAME_MAX_LENGTH,
|
||||||
|
STORE_SERVICE_ACTIVITY_NAME_MIN_LENGTH,
|
||||||
|
STORE_SERVICE_ACTIVITY_DESCRIPTION_MAX_LENGTH,
|
||||||
|
STORE_SERVICE_ACTIVITY_DESCRIPTION_MIN_LENGTH,
|
||||||
|
STORE_SERVICE_ACTIVITY_PRICE_MAX,
|
||||||
|
STORE_SERVICE_ACTIVITY_PRICE_MIN,
|
||||||
|
STORE_SERVICE_ACTIVITY_DURATION_MAX,
|
||||||
|
STORE_SERVICE_ACTIVITY_DURATION_MIN,
|
||||||
} from "../utils/constants";
|
} from "../utils/constants";
|
||||||
|
import User from "../models/user";
|
||||||
|
|
||||||
// TODO: regex for username
|
// TODO: regex for username
|
||||||
export function isUsernameValid(username: string) {
|
export function isUsernameValid(username: string) {
|
||||||
|
@ -16,11 +29,28 @@ export function isUsernameValid(username: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: regex for account name
|
// TODO: regex for account name
|
||||||
export function isAccountNameValid(accountName: string) {
|
export async function isAccountNameValid(accountName: string) {
|
||||||
return (
|
if (
|
||||||
accountName.length >= ACCOUNT_NAME_MIN_LENGTH &&
|
accountName.length < ACCOUNT_NAME_MIN_LENGTH ||
|
||||||
accountName.length <= ACCOUNT_NAME_MAX_LENGTH
|
accountName.length > ACCOUNT_NAME_MAX_LENGTH
|
||||||
);
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if account name is already taken in the database
|
||||||
|
|
||||||
|
const existingUser = await User.findOne({
|
||||||
|
where: {
|
||||||
|
account_name: accountName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
logger.debug("User already exists with this accountName: %s", accountName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: regex for password
|
// TODO: regex for password
|
||||||
|
@ -30,3 +60,52 @@ export function isPasswordValid(password: string) {
|
||||||
password.length <= PASSWORD_MAX_LENGTH
|
password.length <= PASSWORD_MAX_LENGTH
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isUserIdValid(userId: string) {
|
||||||
|
return userId.length === USER_ID_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStoreServiceNameValid(storeServiceName: string) {
|
||||||
|
return (
|
||||||
|
storeServiceName.length >= STORE_SERVICE_MIN_LENGTH &&
|
||||||
|
storeServiceName.length <= STORE_SERVICE_MAX_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStoreServiceActivityNameValid(
|
||||||
|
storeServiceActivityName: string
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
storeServiceActivityName.length >= STORE_SERVICE_ACTIVITY_NAME_MIN_LENGTH &&
|
||||||
|
storeServiceActivityName.length <= STORE_SERVICE_ACTIVITY_NAME_MAX_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStoreServiceActivityDescriptionValid(
|
||||||
|
storeServiceActivityDescription: string
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
storeServiceActivityDescription.length >=
|
||||||
|
STORE_SERVICE_ACTIVITY_DESCRIPTION_MIN_LENGTH &&
|
||||||
|
storeServiceActivityDescription.length <=
|
||||||
|
STORE_SERVICE_ACTIVITY_DESCRIPTION_MAX_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStoreServiceActivityPriceValid(
|
||||||
|
storeServiceActivityPrice: any
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
storeServiceActivityPrice >= STORE_SERVICE_ACTIVITY_PRICE_MIN &&
|
||||||
|
storeServiceActivityPrice <= STORE_SERVICE_ACTIVITY_PRICE_MAX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStoreServiceActivityDurationValid(
|
||||||
|
storeServiceActivityDuration: any
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
storeServiceActivityDuration >= STORE_SERVICE_ACTIVITY_DURATION_MIN &&
|
||||||
|
storeServiceActivityDuration <= STORE_SERVICE_ACTIVITY_DURATION_MAX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue