changed to email

main
alex 2024-02-10 13:52:13 +01:00
parent 7a78649010
commit bd1fedb397
15 changed files with 309 additions and 165 deletions

View File

@ -7,27 +7,22 @@ MARIADB_DATABASE=terminplanner
MARIADB_USER=terminplanner
MARIADB_PASSWORD=your_password
DASHBOARD_URL=
DASHBOARD_API_URL=
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_CALLBACK_URL=your_callback_url
PASSPORT_FAILURE_REDIRECT_URL=your_failure_redirect_url
PASSPORT_SUCCESS_REDIRECT_URL=your_success_redirect_url
TERMIN_PLANNER_AUTHORIZATION_PASSWORD=your_authorization_password
TERMIN_PLANNER_URL=your_termin_planner_url
WEBSITE_BUILDER_TEMPLATE_REPOSITORY_URL=https://your-git-repo.com/website-template.git
WEBSITE_BUILDER_TMP_DIR=./tmp
WEBSITE_BUILDER_TMP_DIR_WEBSITE_TEMPLATE=./tmp/website-template
WEBSITE_BUILDER_TMP_CUSTOMER_WEBSITES_DIR=./customer-websites
RABBITMQ_HOST=
RABBITMQ_PORT=
RABBITMQ_USERNAME=
RABBITMQ_PASSWORD=
RABBITMQ_MAIL_QUEUE=
ACCOUNT_EXPORT_URL=
RECAPTCHA_SECRET_KEY=
RECAPTCHA_SECRET_KEY=
CONSTANTS_ACCOUNT_DEMO_DAYS=

View File

@ -7,14 +7,13 @@ import GoogleStrategy from "passport-google-oauth20";
import cookieParser from "cookie-parser";
import session from "express-session";
import useragent from "express-useragent";
import rabbitmq from "./src/rabbitmq/rabbitmq";
import calendarRoutes from "./src/routes/calendarRoutes";
import storeRoutes from "./src/routes/storeRoutes";
import storeServicesRoutes from "./src/routes/storeServicesRoutes";
import userRoutes from "./src/routes/userRoutes";
import usersRoutes from "./src/routes/usersRoutes";
import websiteRoutes from "./src/routes/websiteRoutes";
//import websiteRoutes from "./src/routes/websiteRoutes";
dotenv.config();
@ -22,8 +21,9 @@ import swaggerJsDoc from "swagger-jsdoc";
import syncModels from "./src/models/index";
import logger from "./src/logger/logger";
import passport from "passport";
import fs from "fs-extra";
import { cloneWebsiteTemplate } from "./src/controllers/websiteController";
import rabbitmq from "./src/rabbitmq/rabbitmq";
import { GOOGLE_CALLBACK_URL } from "./src/utils/constants";
//import { cloneWebsiteTemplate } from "./src/controllers/websiteController";
const app: Express = express();
const host = process.env.HOST || "localhost";
const port = Number(process.env.PORT) || 3000;
@ -68,7 +68,7 @@ passport.use(
{
clientID: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
callbackURL: process.env.GOOGLE_CALLBACK_URL as string,
callbackURL: GOOGLE_CALLBACK_URL,
/*scope: [
"https://www.googleapis.com/auth/calendar.app.created",
"https://www.googleapis.com/auth/calendar.events.freebusy",
@ -117,7 +117,7 @@ app.use("/api/v1/store", storeRoutes);
app.use("/api/v1/store/services", storeServicesRoutes);
app.use("/api/v1/user", userRoutes);
app.use("/api/v1/users", usersRoutes);
app.use("/api/v1/website", websiteRoutes);
//app.use("/api/v1/website", websiteRoutes);
const specs = swaggerJsDoc(options);
app.use("/api-docs", swaggerUI.serve, swaggerUI.setup(specs));
@ -135,7 +135,7 @@ app.use((err: any, req: any, res: any, next: any) => {
syncModels();
// create tmp folder if not exists
/*
[
process.env.WEBSITE_BUILDER_TMP_DIR as string,
process.env.WEBSITE_BUILDER_TMP_CUSTOMER_WEBSITES_DIR as string,
@ -154,16 +154,21 @@ if (
) {
cloneWebsiteTemplate();
}
*/
// start server
rabbitmq(
process.env.RABBITMQ_USERNAME as string,
process.env.RABBITMQ_PASSWORD as string,
process.env.RABBITMQ_HOST as string,
process.env.RABBITMQ_PORT as string
);
app.listen(port, host, () =>
logger.info(`⚡️[server]: Server is running at http://${host}:${port}`)
);
rabbitmq
.connect(
process.env.RABBITMQ_USERNAME as string,
process.env.RABBITMQ_PASSWORD as string,
process.env.RABBITMQ_HOST as string,
process.env.RABBITMQ_PORT as string
)
.then(() => {
app.listen(port, host, () =>
logger.info(`⚡️[server]: Server is running at http://${host}:${port}`)
);
})
.catch((err) => {
logger.error(err);
});

View File

@ -2,7 +2,6 @@ import { Request, Response } from "express";
import logger from "../logger/logger";
import User from "../models/user";
import {
isAccountNameValid,
isCompanyNameValid,
isEmailValid,
isLanguageCodeValid,
@ -15,15 +14,19 @@ import {
CALENDAR_MAX_FUTURE_BOOKING_DAYS,
CALENDAR_MAX_SERVICE_DURATION,
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
DASHBOARD_URL,
EMAIL_VERIFICATION_STATE,
Roles,
USER_ANALYTICS_ENABLED_DEFAULT,
} from "../utils/constants";
import {
decodeBase64,
getEmailVerificationUrl,
getUserSession,
hashPassword,
matchPassword,
newAccountExportId,
newEmailVerificationId,
newFeedbackId,
newStoreId,
newUserId,
@ -33,15 +36,16 @@ import Store from "../models/store";
import Session from "../models/session";
import Feedback from "../models/feedback";
import fs from "fs-extra";
import { channel } from "../rabbitmq/rabbitmq";
import rabbitmq from "../rabbitmq/rabbitmq";
import verifyCaptcha from "../utils/recaptcha";
import EmailVerification from "../models/emailVerification";
export async function SignUp(req: Request, res: Response) {
try {
let {
companyName,
username,
accountName,
email,
password,
language,
rememberMe,
@ -53,12 +57,12 @@ export async function SignUp(req: Request, res: Response) {
if (
!companyName ||
!username ||
!accountName ||
!email ||
!password ||
!language ||
!isCompanyNameValid(companyName) ||
!isUsernameValid(username) ||
!isAccountNameValid(accountName) ||
!isEmailValid(email) ||
!isLanguageCodeValid(language) ||
rememberMe === undefined ||
!recaptcha
@ -77,13 +81,13 @@ export async function SignUp(req: Request, res: Response) {
return res.status(400).send({ err: "invalid request" });
}
accountName = accountName.toLowerCase();
email = email.toLowerCase();
// check if user already exists
const existingUser = await User.findOne({
where: {
account_name: accountName,
email: email,
},
});
@ -107,7 +111,7 @@ export async function SignUp(req: Request, res: Response) {
let userId = newUserId();
Store.create({
const store = await Store.create({
store_id: newStoreId(),
owner_user_id: userId,
name: companyName,
@ -115,34 +119,41 @@ export async function SignUp(req: Request, res: Response) {
calendar_min_earliest_booking_time: CALENDAR_MIN_EARLIEST_BOOKING_TIME,
calendar_max_service_duration: CALENDAR_MAX_SERVICE_DURATION,
address: "",
})
.then(async (store) => {
// create user
});
await User.create({
user_id: userId,
store_id: store.store_id,
role: Roles.Master,
account_name: accountName,
username: username,
password: hashedPassword,
language: language,
analytics_enabled: USER_ANALYTICS_ENABLED_DEFAULT,
state: ACCOUNT_STATE.ACTIVE,
})
.then((user) => {
// create session
saveSession(req, res, user.user_id, user.username, rememberMe);
})
.catch((err) => {
logger.error(err);
res.status(500).send({ err: "invalid request" });
});
})
.catch((err) => {
logger.error(err);
res.status(500).send({ err: "invalid request" });
});
// create email verification
const emailVerificationId = newEmailVerificationId();
const state = EMAIL_VERIFICATION_STATE.PENDING_EMAIL_VERIFICATION;
await EmailVerification.create({
email_verification_id: emailVerificationId,
user_id: userId,
state: state,
});
rabbitmq.sendEmail(email, "dashboardSignUpEmailVerification", language, {
emailVerificationUrl: getEmailVerificationUrl(
String(state),
emailVerificationId
),
});
// create user
const user = await User.create({
user_id: userId,
store_id: store.store_id,
role: Roles.Master,
email: email,
username: username,
password: hashedPassword,
language: language,
analytics_enabled: USER_ANALYTICS_ENABLED_DEFAULT,
state: ACCOUNT_STATE.PENDING_EMAIL_VERIFICATION,
});
saveSession(req, res, false, user.user_id, user.username, rememberMe);
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
@ -151,24 +162,24 @@ export async function SignUp(req: Request, res: Response) {
export async function Login(req: Request, res: Response) {
try {
let { accountName, password, rememberMe, recaptcha } = req.body;
let { email, password, rememberMe, recaptcha } = req.body;
// validate request
if (!accountName) {
if (!email) {
return res.status(400).send({ err: "invalid request" });
}
accountName = accountName.toLowerCase();
email = email.toLowerCase();
if (!isAccountNameValid(accountName)) {
if (!isEmailValid(email)) {
return res.status(400).send({ err: "invalid request" });
}
// check if user exists
const user = await User.findOne({
where: {
account_name: accountName,
email: email,
},
attributes: ["user_id", "password", "state"],
});
@ -179,7 +190,7 @@ export async function Login(req: Request, res: Response) {
// if password not provided, then send user state
// user is on the login page on the first step of the login process
// and only needs to enter their account name to get the user state to know what to do next
// and only needs to enter their email to get the user state to know what to do next
if (password === undefined) {
return res.status(200).send({ state: user.state });
@ -244,7 +255,7 @@ export async function Login(req: Request, res: Response) {
}
// create session
saveSession(req, res, user.user_id, user.username, rememberMe);
saveSession(req, res, true, user.user_id, user.username, rememberMe);
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
@ -385,19 +396,19 @@ export async function GetUser(req: Request, res: Response) {
}
}
export async function IsAccountNameAvailable(req: Request, res: Response) {
export async function IsEmailAvailable(req: Request, res: Response) {
try {
let { accountName } = req.body;
let { email } = req.body;
// validate request
if (!accountName) {
if (!email) {
return res.status(400).send({ err: "invalid request" });
}
accountName = accountName.toLowerCase();
email = email.toLowerCase();
if (!isAccountNameValid(accountName)) {
if (!isEmailValid(email)) {
return res.status(400).send({ err: "invalid request" });
}
@ -405,7 +416,7 @@ export async function IsAccountNameAvailable(req: Request, res: Response) {
const user = await User.findOne({
where: {
account_name: accountName,
email: email,
},
});
@ -413,7 +424,7 @@ export async function IsAccountNameAvailable(req: Request, res: Response) {
return res.status(400).send({ err: "invalid request" });
}
res.status(200).send({ msg: "account name available" });
res.status(200).send({ msg: "email available" });
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
@ -432,7 +443,7 @@ export async function GetUserProfileSettings(req: Request, res: Response) {
where: {
user_id: session.user_id,
},
attributes: ["language", "analytics_enabled", "username", "account_name"],
attributes: ["language", "analytics_enabled", "username", "email"],
});
res.status(200).json(user);
@ -444,14 +455,9 @@ export async function GetUserProfileSettings(req: Request, res: Response) {
export async function UpdateUserProfileSettings(req: Request, res: Response) {
try {
const { language, analyticsEnabled, username, accountName } = req.body;
const { language, analyticsEnabled, username, email } = req.body;
if (
!language &&
analyticsEnabled === undefined &&
!username &&
!accountName
) {
if (!language && analyticsEnabled === undefined && !username && !email) {
return res.status(400).send({ err: "invalid request" });
}
@ -487,12 +493,12 @@ export async function UpdateUserProfileSettings(req: Request, res: Response) {
user.username = username;
}
if (accountName) {
if (!isAccountNameValid(accountName)) {
if (email) {
if (!isEmailValid(email)) {
return res.status(400).send({ err: "invalid request" });
}
user.account_name = accountName;
user.email = email;
}
await user.save();
@ -757,7 +763,7 @@ export async function ExportUserAccount(req: Request, res: Response) {
user: {
user_id: user.user_id,
username: user.username,
account_name: user.account_name,
email: user.email,
calendar_max_future_booking_days:
user.calendar_max_future_booking_days,
calendar_min_earliest_booking_time:
@ -778,22 +784,11 @@ export async function ExportUserAccount(req: Request, res: Response) {
// send email with file
channel.sendToQueue(
process.env.RABBITMQ_MAIL_QUEUE as string,
Buffer.from(
JSON.stringify({
m: email, // UserMail
t: "dashboardUserAccountExportFinish", // TemplateId
l: "de", // LanguageId
// BodyData
b: {
accountExportDownloadUrl: `${
process.env.ACCOUNT_EXPORT_URL as string
}${accountExportId}`,
},
})
)
);
rabbitmq.sendEmail(email, "dashboardUserAccountExportFinish", "de", {
accountExportDownloadUrl: `${
process.env.ACCOUNT_EXPORT_URL as string
}${accountExportId}`,
});
} catch (error) {
logger.error(error);
}
@ -806,7 +801,7 @@ export async function ExportUserAccount(req: Request, res: Response) {
}
}
export function GetExportedUserAccount(req: Request, res: Response) {
export async function GetExportedUserAccount(req: Request, res: Response) {
try {
const { id } = req.params;
@ -830,3 +825,53 @@ export function GetExportedUserAccount(req: Request, res: Response) {
res.status(500).send({ err: "invalid request" });
}
}
export async function VerifyEmail(req: Request, res: Response) {
try {
const { state, emailVerificationId } = req.params;
if (state === undefined || !emailVerificationId) {
return res.status(400).send({ err: "invalid request" });
}
const emailVerification = await EmailVerification.findOne({
where: {
email_verification_id: emailVerificationId,
},
});
if (!emailVerification) {
return res.status(400).send({ err: "invalid request" });
}
if (
emailVerification.state ===
EMAIL_VERIFICATION_STATE.PENDING_EMAIL_VERIFICATION
) {
await User.update(
{
state: ACCOUNT_STATE.ACTIVE,
},
{
where: {
user_id: emailVerification.user_id,
},
}
);
await EmailVerification.destroy({
where: {
email_verification_id: emailVerificationId,
},
});
res.status(200).send({ msg: "email verified" });
return;
}
res.status(400).send({ err: "invalid request" });
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}

View File

@ -1,7 +1,7 @@
import { Request, Response } from "express";
import logger from "../logger/logger";
import {
isAccountNameValid,
isEmailValid,
isLanguageCodeValid,
isPasswordValid,
isUserIdValid,
@ -27,7 +27,7 @@ export async function AddEmployee(req: Request, res: Response) {
let {
storeId,
username,
accountName,
email,
password,
calendarMaxFutureBookingDays,
calendarMinEarliestBookingTime,
@ -40,18 +40,15 @@ export async function AddEmployee(req: Request, res: Response) {
if (
!storeId ||
!username ||
!accountName ||
!email ||
passwordSetOnInitLogging === undefined ||
(!password && passwordSetOnInitLogging === false) ||
!language ||
!isLanguageCodeValid(language)
) {
logger.debug("Invalid request");
return res.status(400).send({ err: "invalid request" });
}
logger.debug("Request is valid %s %s", passwordSetOnInitLogging, password);
// verify if requester is a store master
const requesterSession = await getUserSession(req);
@ -74,14 +71,11 @@ export async function AddEmployee(req: Request, res: Response) {
return res.status(401).send({ err: "unauthorized" });
}
// validate username and account name
// validate username and email
accountName = accountName.toLowerCase();
email = email.toLowerCase();
if (
!isUsernameValid(username) ||
!(await isAccountNameValid(accountName))
) {
if (!isUsernameValid(username) || !(await isEmailValid(email))) {
return res.status(400).send({ err: "invalid request" });
}
@ -89,7 +83,7 @@ export async function AddEmployee(req: Request, res: Response) {
const existingUser = await User.findOne({
where: {
account_name: accountName,
email: email,
},
});
@ -105,7 +99,7 @@ export async function AddEmployee(req: Request, res: Response) {
user_id: userId,
store_id: storeId,
role: Roles.Worker,
account_name: accountName,
email: email,
username: username,
calendar_max_future_booking_days: calendarMaxFutureBookingDays,
calendar_min_earliest_booking_time: calendarMinEarliestBookingTime,
@ -136,7 +130,7 @@ export async function AddEmployee(req: Request, res: Response) {
user_id: string;
store_id: any;
role: string;
account_name: any;
email: any;
username: any;
calendar_max_future_booking_days: any;
calendar_min_earliest_booking_time: any;
@ -193,7 +187,7 @@ export async function GetEmployees(req: Request, res: Response) {
return res.status(401).send({ err: "unauthorized" });
}
// find all employees of the requester and select only the username and account name
// find all employees of the requester
const employees = await User.findAll({
where: {
@ -202,7 +196,7 @@ export async function GetEmployees(req: Request, res: Response) {
attributes: [
"user_id",
"username",
"account_name",
"email",
"calendar_max_future_booking_days",
"calendar_min_earliest_booking_time",
],
@ -234,13 +228,11 @@ export async function UpdateEmployee(req: Request, res: Response) {
let {
userId,
username,
accountName,
email,
calendarMaxFutureBookingDays,
calendarMinEarliestBookingTime,
} = req.body;
// validate username and account name
if (!isUserIdValid(userId)) {
return res.status(400).send({ err: "invalid request" });
}
@ -282,17 +274,17 @@ export async function UpdateEmployee(req: Request, res: Response) {
let update = {};
if (accountName) {
accountName = accountName.toLowerCase();
if (email) {
email = email.toLowerCase();
if (!(await isAccountNameValid(accountName))) {
if (!(await isEmailValid(email))) {
res.status(400).send({ err: "invalid request" });
return;
}
update = {
...update,
account_name: accountName,
email: email,
};
}

View File

@ -1,4 +1,4 @@
import { Request, Response } from "express";
/*import { Request, Response } from "express";
import logger from "../logger/logger";
import util from "util";
import { exec } from "child_process";
@ -159,3 +159,4 @@ export async function GetWebsite(req: Request, res: Response) {
res.status(500).send({ error: "invalid request" });
}
}
*/

View File

@ -0,0 +1,44 @@
import { DataTypes, Model } from "sequelize";
import sequelize from "../database/database";
interface EmailVerificationAttributes {
email_verification_id: string; // code that is sent to the user's email
user_id: string;
state: number; // to know for what the code is used for (like password reset, email verification, etc)
}
class EmailVerification
extends Model<EmailVerificationAttributes>
implements EmailVerificationAttributes
{
declare email_verification_id: string;
declare user_id: string;
declare state: number;
}
EmailVerification.init(
{
// Model attributes are defined here
email_verification_id: {
primaryKey: true,
type: DataTypes.STRING,
allowNull: false,
},
user_id: {
type: DataTypes.STRING,
allowNull: false,
},
state: {
type: DataTypes.TINYINT,
allowNull: false,
},
},
{
tableName: "email_verification",
sequelize, // passing the `sequelize` instance is required
createdAt: "created_at",
updatedAt: "updated_at",
}
);
export default EmailVerification;

View File

@ -1,4 +1,5 @@
import Feedback from "./feedback";
import EmailVerification from "./emailVerification";
import Session from "./session";
import Store from "./store";
import StoreService from "./storeService";
@ -8,6 +9,7 @@ import User from "./user";
import Website from "./website";
function syncModels() {
EmailVerification.sync();
User.sync();
Session.sync();
Store.sync();

View File

@ -6,7 +6,7 @@ interface UserAttributes {
store_id: string;
// TODO: change to role_id
role: string;
account_name: string;
email: string;
username: string;
password?: string; // can be null if user is created by store owner - password is set by user when they first login
calendar_max_future_booking_days?: number;
@ -21,7 +21,7 @@ class User extends Model<UserAttributes> implements UserAttributes {
declare user_id: string;
declare store_id: string;
declare role: string;
declare account_name: string;
declare email: string;
declare username: string;
declare password: string;
declare calendar_max_future_booking_days: number;
@ -49,7 +49,7 @@ User.init(
type: DataTypes.STRING,
allowNull: false,
},
account_name: {
email: {
type: DataTypes.STRING,
unique: true,
},

View File

@ -1,6 +1,6 @@
import amqplib from "amqplib";
export let channel: amqplib.Channel;
let channel: amqplib.Channel;
async function connect(
RABBITMQ_USERNAME: string,
@ -13,16 +13,45 @@ async function connect(
);
if (!open) {
console.log("RabbitMQ connection failed");
console.log("⚡️[RabbitMQ]: connection failed");
return;
}
channel = await open.createChannel();
if (!channel) {
console.log("RabbitMQ channel failed");
console.log("⚡️[RabbitMQ]: channel failed");
return;
}
}
export default connect;
async function sendEmail(
email: string,
templateId: string,
languageId: string,
bodyData: any
) {
if (!channel) {
console.log("⚡️[RabbitMQ]: channel not available");
return;
}
channel.sendToQueue(
process.env.RABBITMQ_MAIL_QUEUE as string,
Buffer.from(
JSON.stringify({
m: email,
t: templateId,
l: languageId,
b: bodyData,
})
)
);
}
const rabbitmq = {
connect,
sendEmail,
};
export default rabbitmq;

View File

@ -6,6 +6,10 @@ import logger from "../logger/logger";
import Session from "../models/session";
import * as calendarController from "../controllers/calendarController";
import {
PASSPORT_FAILURE_REDIRECT_URL,
PASSPORT_SUCCESS_REDIRECT_URL,
} from "../utils/constants";
router.get(
"/auth/google",
@ -24,7 +28,7 @@ router.get(
router.get(
"/auth/google/callback",
passport.authenticate("google", {
failureRedirect: process.env.PASSPORT_FAILURE_REDIRECT_URL as string,
failureRedirect: PASSPORT_FAILURE_REDIRECT_URL,
}),
function (req, res) {
// Successful authentication, redirect home.
@ -38,7 +42,7 @@ router.get(
if (!sessionId) {
logger.error("session cookie not found");
res.redirect(process.env.PASSPORT_FAILURE_REDIRECT_URL as string);
res.redirect(PASSPORT_FAILURE_REDIRECT_URL);
return;
}
@ -50,7 +54,7 @@ router.get(
.then((userSession) => {
if (!userSession) {
logger.error("user session not found");
res.redirect(process.env.PASSPORT_FAILURE_REDIRECT_URL as string);
res.redirect(PASSPORT_FAILURE_REDIRECT_URL);
return;
}
@ -70,11 +74,11 @@ router.get(
logger.info("err %s", err);
});
res.redirect(process.env.PASSPORT_SUCCESS_REDIRECT_URL as string);
res.redirect(PASSPORT_SUCCESS_REDIRECT_URL);
})
.catch((err) => {
logger.error(err);
res.redirect(process.env.PASSPORT_FAILURE_REDIRECT_URL as string);
res.redirect(PASSPORT_FAILURE_REDIRECT_URL);
});
// /api/v1/addGoogleAccount

View File

@ -8,7 +8,7 @@ router.post("/auth/signup", userController.SignUp);
router.post("/auth/login", userController.Login);
router.delete("/auth/logout", sessionProtection, userController.Logout);
router.get("/", sessionProtection, userController.GetUser);
router.post("/auth/check/accountname", userController.IsAccountNameAvailable);
router.post("/auth/check/email", userController.IsEmailAvailable);
router.get(
"/profile/settings",
sessionProtection,
@ -45,5 +45,6 @@ router.post(
userController.ExportUserAccount
);
router.get("/profile/export/:id", userController.GetExportedUserAccount);
router.get("/verify/:state/:emailVerificationId", userController.VerifyEmail);
export default router;

View File

@ -1,4 +1,4 @@
import express from "express";
/*import express from "express";
const router = express.Router();
import * as websiteController from "../controllers/websiteController";
@ -11,3 +11,4 @@ router.post("/", websiteController.CreateWebsite);
router.get("/:storeId", websiteController.GetWebsite);
export default router;
*/

View File

@ -5,8 +5,9 @@ export const USER_SESSION_LENGTH = 32;
export const USERNAME_MIN_LENGTH = 3;
export const USERNAME_MAX_LENGTH = 20;
export const ACCOUNT_NAME_MIN_LENGTH = 3;
export const ACCOUNT_NAME_MAX_LENGTH = 20;
export const EMAIL_MIN_LENGTH = 3;
export const EMAIL_MAX_LENGTH = 64;
export const EMAIL_REGEX = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
export const PASSWORD_MIN_LENGTH = 8;
export const PASSWORD_MAX_LENGTH = 64;
@ -51,6 +52,7 @@ export enum ACCOUNT_STATE {
PENDING_DELETION = 1, // account still exists but is marked as deleted, can be restored or will be deleted after a certain time
INIT_LOGIN = 2, // account is created but password is not set yet
BANNED = 3, // account is banned, cannot login
PENDING_EMAIL_VERIFICATION = 4, // account is created but email is not verified yet
}
export const FEEDBACK_MIN_LENGTH = 3;
@ -69,3 +71,13 @@ export const Roles = {
export const ACCOUNT_DEMO_DAYS = Number(
process.env.CONSTANTS_ACCOUNT_DEMO_DAYS
); // how many days a demo account is valid until payment is required or account will be deleted
export enum EMAIL_VERIFICATION_STATE {
PENDING_EMAIL_VERIFICATION = 0, // account is created but email is not verified yet
}
export const DASHBOARD_URL = process.env.DASHBOARD_URL as string;
export const GOOGLE_CALLBACK_URL = `${process.env.GOOGLE_CALLBACK_URL}/v1/calendar/auth/google/callback`;
export const PASSPORT_FAILURE_REDIRECT_URL = `${process.env.DASHBOARD_URL}/store/calendar/auth/failed`;
export const PASSPORT_SUCCESS_REDIRECT_URL = `${process.env.DASHBOARD_URL}/store/calendar/auth/finish`;
export const ACCOUNT_EXPORT_URL = `${process.env.DASHBOARD_API_URL}/v1/user/profile/export/`;

View File

@ -4,6 +4,7 @@ import { v4 as uuidv4 } from "uuid";
import { Request, Response } from "express";
import Session from "../models/session";
import {
DASHBOARD_URL,
DEFAULT_SESSION_EXPIRY,
HEADER_X_AUTHORIZATION,
SESSION_EXPIRY_NOT_REMEMBER_ME,
@ -42,6 +43,10 @@ export function newUserSession() {
return crypto.randomBytes(USER_SESSION_LENGTH).toString("hex");
}
export function newEmailVerificationId() {
return crypto.randomBytes(64).toString("hex");
}
export function newSessionId() {
return uuidv4();
}
@ -57,6 +62,7 @@ export function newAccountExportId() {
export async function saveSession(
req: Request,
res: Response,
sendResponseData: boolean,
userId: string,
username: string,
rememberMe: boolean
@ -77,12 +83,15 @@ export async function saveSession(
),
});
res.status(200).json({
XAuthorization: userSession,
Username: username,
});
if (sendResponseData) {
res.status(200).json({
XAuthorization: userSession,
Username: username,
});
} else {
res.status(200).send({ msg: "success" });
}
} catch (err) {
console.log(err);
res.status(500).send({ err: "invalid request" });
}
}
@ -100,3 +109,10 @@ export async function getUserSession(req: Request) {
},
});
}
export function getEmailVerificationUrl(
state: string,
emailVerificationId: string
) {
return `${DASHBOARD_URL}/verify/${state}/${emailVerificationId}`;
}

View File

@ -3,8 +3,6 @@ import {
USERNAME_MAX_LENGTH,
PASSWORD_MIN_LENGTH,
PASSWORD_MAX_LENGTH,
ACCOUNT_NAME_MIN_LENGTH,
ACCOUNT_NAME_MAX_LENGTH,
USER_ID_LENGTH,
STORE_SERVICE_MIN_LENGTH,
STORE_SERVICE_MAX_LENGTH,
@ -20,6 +18,9 @@ import {
FEEDBACK_MIN_LENGTH,
COMPANY_NAME_MIN_LENGTH,
COMPANY_NAME_MAX_LENGTH,
EMAIL_MIN_LENGTH,
EMAIL_MAX_LENGTH,
EMAIL_REGEX,
} from "../utils/constants";
import User from "../models/user";
@ -31,20 +32,21 @@ export function isUsernameValid(username: string) {
);
}
// TODO: regex for account name
export async function isAccountNameValid(accountName: string) {
// TODO: regex for email
export async function isEmailValid(email: string) {
if (
accountName.length < ACCOUNT_NAME_MIN_LENGTH ||
accountName.length > ACCOUNT_NAME_MAX_LENGTH
email.length < EMAIL_MIN_LENGTH ||
email.length > EMAIL_MAX_LENGTH ||
!EMAIL_REGEX.test(email)
) {
return false;
}
// check if account name is already taken in the database
// check if email is already taken in the database
const existingUser = await User.findOne({
where: {
account_name: accountName,
email: email,
},
});
@ -63,11 +65,6 @@ export function isPasswordValid(password: string) {
);
}
// TODO: regex for email
export function isEmailValid(email: string) {
return true;
}
export function isUserIdValid(userId: string) {
return userId.length === USER_ID_LENGTH;
}