export account

main
alex 2024-02-03 22:36:30 +01:00
parent 76f2eddd40
commit 3128b50540
9 changed files with 298 additions and 2 deletions

View File

@ -20,4 +20,12 @@ 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
WEBSITE_BUILDER_TMP_CUSTOMER_WEBSITES_DIR=./customer-websites
RABBITMQ_HOST=
RABBITMQ_PORT=
RABBITMQ_USERNAME=
RABBITMQ_PASSWORD=
RABBITMQ_MAIL_QUEUE=
ACCOUNT_EXPORT_URL=

114
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"amqplib": "^0.10.3",
"axios": "^1.6.5",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2",
@ -32,6 +33,7 @@
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/amqplib": "^0.10.4",
"@types/bcrypt": "^5.0.2",
"@types/cookie-parser": "^1.4.6",
"@types/cors": "^2.8.17",
@ -46,6 +48,45 @@
"typescript": "^5.3.3"
}
},
"node_modules/@acuminous/bitsyntax": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz",
"integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==",
"dependencies": {
"buffer-more-ints": "~1.0.0",
"debug": "^4.3.4",
"safe-buffer": "~5.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/@acuminous/bitsyntax/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@acuminous/bitsyntax/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/@acuminous/bitsyntax/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/@apidevtools/json-schema-ref-parser": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
@ -121,6 +162,15 @@
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@types/amqplib": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.4.tgz",
"integrity": "sha512-Y5Sqquh/LqDxSgxYaAAFNM0M7GyONtSDCcFMJk+DQwYEjibPyW6y+Yu9H9omdkKc3epyXULmFN3GTaeBHhn2Hg==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/bcrypt": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
@ -431,6 +481,36 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/amqplib": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
"integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
"dependencies": {
"@acuminous/bitsyntax": "^0.1.2",
"buffer-more-ints": "~1.0.0",
"readable-stream": "1.x >=1.1.9",
"url-parse": "~1.5.10"
},
"engines": {
"node": ">=10"
}
},
"node_modules/amqplib/node_modules/readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/amqplib/node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@ -603,6 +683,11 @@
"ieee754": "^1.2.1"
}
},
"node_modules/buffer-more-ints": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -812,6 +897,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
@ -1509,6 +1599,11 @@
"node": ">=8"
}
},
"node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"node_modules/joycon": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
@ -2114,6 +2209,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"node_modules/quick-format-unescaped": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
@ -2188,6 +2288,11 @@
"node": ">=0.10.0"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
"node_modules/retry-as-promised": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
@ -2708,6 +2813,15 @@
"node": ">= 0.8"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@ -6,11 +6,12 @@
"scripts": {
"build": "npx tsc",
"start": "node build/server.js",
"dev": "concurrently \"npx tsc --watch\" \"nodemon --ignore ./tmp/ --ignore ./customer-websites/ -q build/server.js | pino-pretty\""
"dev": "concurrently \"npx tsc --watch\" \"nodemon --ignore ./tmp/ --ignore ./customer-websites/ --ignore ./user-profile-exports/ -q build/server.js | pino-pretty\""
},
"author": "",
"license": "ISC",
"dependencies": {
"amqplib": "^0.10.3",
"axios": "^1.6.5",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2",
@ -34,6 +35,7 @@
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/amqplib": "^0.10.4",
"@types/bcrypt": "^5.0.2",
"@types/cookie-parser": "^1.4.6",
"@types/cors": "^2.8.17",

View File

@ -7,6 +7,7 @@ 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";
@ -23,6 +24,7 @@ import logger from "./src/logger/logger";
import passport from "passport";
import fs from "fs-extra";
import { cloneWebsiteTemplate } from "./src/controllers/websiteController";
import { connect } from "amqplib";
const app: Express = express();
const host = process.env.HOST || "localhost";
const port = Number(process.env.PORT) || 3000;
@ -156,6 +158,13 @@ if (
// 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}`)
);

View File

@ -4,6 +4,7 @@ import User from "../models/user";
import {
isAccountNameValid,
isCompanyNameValid,
isEmailValid,
isLanguageCodeValid,
isPasswordValid,
isUsernameValid,
@ -29,6 +30,8 @@ import {
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";
export async function SignUp(req: Request, res: Response) {
try {
@ -644,3 +647,123 @@ export async function DeleteUserProfile(req: Request, res: Response) {
res.status(500).send({ err: "invalid request" });
}
}
export async function ExportUserAccount(req: Request, res: Response) {
try {
const { email, password } = req.body;
if (
!email ||
!password ||
!isEmailValid(email) ||
!isPasswordValid(password)
) {
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" });
}
const decodedPassword = decodeBase64(password);
const match = await matchPassword(decodedPassword, user.password);
if (!match) {
return res.status(400).send({ err: "invalid request" });
}
(async () => {
try {
// send email with user data
console.log("email");
// simulate delay
await new Promise((resolve) => setTimeout(resolve, 5000));
// create json file with user data
console.log("file");
const exportData = {
user: {
user_id: user.user_id,
username: user.username,
account_name: user.account_name,
calendar_max_future_booking_days:
user.calendar_max_future_booking_days,
calendar_min_earliest_booking_time:
user.calendar_min_earliest_booking_time,
calendar_using_primary_calendar:
user.calendar_using_primary_calendar,
language: user.language,
analytics_enabled: user.analytics_enabled,
},
};
fs.writeJson(`./user-profile-exports/${user.user_id}.json`, exportData);
// send email with file
channel.sendToQueue(
process.env.RABBITMQ_MAIL_QUEUE as string,
Buffer.from(
JSON.stringify({
m: "test@roese.dev", // UserMail
t: "userAccountExportFinish", // TemplateId
l: "de", // LanguageId
// BodyData
b: {
accountExportDownloadUrl: `${
process.env.ACCOUNT_EXPORT_URL as string
}${user.user_id}`,
},
})
)
);
} catch (error) {
logger.error(error);
}
})();
res.status(200).json({});
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}
export function GetExportedUserAccount(req: Request, res: Response) {
try {
const { userId } = req.params;
if (!userId) {
return res.status(400).send({ err: "invalid request" });
}
const file = `./user-profile-exports/${userId}.json`;
res.download(file, (err) => {
if (err) {
logger.error(err);
res.status(500).send({ err: "invalid request" });
}
});
} catch (error) {
logger.error(error);
res.status(500).send({ err: "invalid request" });
}
}

28
src/rabbitmq/rabbitmq.ts Normal file
View File

@ -0,0 +1,28 @@
import amqplib from "amqplib";
export let channel: amqplib.Channel;
async function connect(
RABBITMQ_USERNAME: string,
RABBITMQ_PASSWORD: string,
RABBITMQ_HOST: string,
RABBITMQ_PORT: string
) {
const open = await amqplib.connect(
`amqp://${RABBITMQ_USERNAME}:${RABBITMQ_PASSWORD}@${RABBITMQ_HOST}:${RABBITMQ_PORT}`
);
if (!open) {
console.log("RabbitMQ connection failed");
return;
}
channel = await open.createChannel();
if (!channel) {
console.log("RabbitMQ channel failed");
return;
}
}
export default connect;

View File

@ -39,5 +39,11 @@ router.delete(
sessionProtection,
userController.DeleteUserProfile
);
router.post(
"/profile/export",
sessionProtection,
userController.ExportUserAccount
);
router.get("/profile/export/:id", userController.GetExportedUserAccount);
export default router;

View File

@ -63,6 +63,11 @@ 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;
}

View File

@ -0,0 +1 @@
{"user":{"user_id":"4417984c-de81-4930-8ae7-9f178d98ddf7","username":"Alexander","account_name":"alex","calendar_max_future_booking_days":13,"calendar_min_earliest_booking_time":8,"calendar_using_primary_calendar":true,"language":"de","analytics_enabled":false}}