Browse Source

feat(AccountRemoval): data removal request to admins, email sent to admins

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 3 years ago
parent
commit
fb46afcab6

+ 22 - 10
backend/logic/actions/users.js

@@ -215,10 +215,13 @@ export default {
 	 */
 	remove: isLoginRequired(async function remove(session, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const dataRequestModel = await DBModule.runJob("GET_MODEL", { modelName: "dataRequest" }, this);
 		const stationModel = await DBModule.runJob("GET_MODEL", { modelName: "station" }, this);
 		const playlistModel = await DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
 		const activityModel = await DBModule.runJob("GET_MODEL", { modelName: "activity" }, this);
 
+		const dataRequestEmail = await MailModule.runJob("GET_SCHEMA", { schemaName: "dataRequest" }, this);
+
 		async.waterfall(
 			[
 				// activities related to the user
@@ -267,6 +270,23 @@ export default {
 				// user object
 				(res, next) => {
 					userModel.deleteMany({ _id: session.userId }, next);
+				},
+
+				// request data removal for user
+				(res, next) => {
+					dataRequestModel.create({ userId: session.userId, type: "remove" }, next);
+				},
+
+				(request, next) => userModel.find({ role: "admin" }, next),
+
+				// send email to all admins of a data removal request
+				(users, next) => {
+					if (users.length === 0) return next();
+
+					const to = [];
+					users.forEach(user => to.push(user.email.address));
+
+					return dataRequestEmail(to, session.userId, "remove", err => next(err));
 				}
 			],
 			async err => {
@@ -349,9 +369,7 @@ export default {
 						},
 						this
 					)
-						.then(() => {
-							next(null, sessionId);
-						})
+						.then(() => next(null, sessionId))
 						.catch(next);
 				}
 			],
@@ -392,13 +410,7 @@ export default {
 		const verificationToken = await UtilsModule.runJob("GENERATE_RANDOM_STRING", { length: 64 }, this);
 
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
-		const verifyEmailSchema = await MailModule.runJob(
-			"GET_SCHEMA",
-			{
-				schemaName: "verifyEmail"
-			},
-			this
-		);
+		const verifyEmailSchema = await MailModule.runJob("GET_SCHEMA", { schemaName: "verifyEmail" }, this);
 
 		async.waterfall(
 			[

+ 0 - 2
backend/logic/app.js

@@ -374,8 +374,6 @@ class _AppModule extends CoreClass {
 						}
 					],
 					async (err, userId) => {
-						console.log(err, userId);
-
 						if (err && err !== true) {
 							err = await UtilsModule.runJob("GET_ERROR", {
 								error: err

+ 3 - 0
backend/logic/db/index.js

@@ -65,6 +65,7 @@ class _DBModule extends CoreClass {
 						queueSong: {},
 						station: {},
 						user: {},
+						dataRequest: {},
 						activity: {},
 						playlist: {},
 						news: {},
@@ -84,6 +85,7 @@ class _DBModule extends CoreClass {
 					await importSchema("queueSong");
 					await importSchema("station");
 					await importSchema("user");
+					await importSchema("dataRequest");
 					await importSchema("activity");
 					await importSchema("playlist");
 					await importSchema("news");
@@ -95,6 +97,7 @@ class _DBModule extends CoreClass {
 						queueSong: mongoose.model("queueSong", this.schemas.queueSong),
 						station: mongoose.model("station", this.schemas.station),
 						user: mongoose.model("user", this.schemas.user),
+						dataRequest: mongoose.model("dataRequest", this.schemas.dataRequest),
 						activity: mongoose.model("activity", this.schemas.activity),
 						playlist: mongoose.model("playlist", this.schemas.playlist),
 						news: mongoose.model("news", this.schemas.news),

+ 7 - 0
backend/logic/db/schemas/dataRequest.js

@@ -0,0 +1,7 @@
+export default {
+	userId: { type: String, required: true },
+	createdAt: { type: Date, default: Date.now, required: true },
+	type: { type: String, required: true, enum: ["remove"] },
+	resolved: { type: Boolean, default: false },
+	documentVersion: { type: Number, default: 1, required: true }
+};

+ 3 - 1
backend/logic/mail/index.js

@@ -28,7 +28,8 @@ class _MailModule extends CoreClass {
 		this.schemas = {
 			verifyEmail: await importSchema("verifyEmail"),
 			resetPasswordRequest: await importSchema("resetPasswordRequest"),
-			passwordRequest: await importSchema("passwordRequest")
+			passwordRequest: await importSchema("passwordRequest"),
+			dataRequest: await importSchema("dataRequest")
 		};
 
 		this.enabled = config.get("smtp.enabled");
@@ -55,6 +56,7 @@ class _MailModule extends CoreClass {
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	SEND_MAIL(payload) {
+		// console.log(payload);
 		return new Promise((resolve, reject) => {
 			if (MailModule.enabled)
 				return MailModule.transporter

+ 34 - 0
backend/logic/mail/schemas/dataRequest.js

@@ -0,0 +1,34 @@
+import config from "config";
+
+import mail from "../index";
+
+/**
+ * Sends an email to all admins that a user has submitted a data request
+ *
+ * @param {string} to - an array of email addresses of admins
+ * @param {string} userId - the id of the user the data request is for
+ * @param {string} type - the type of data request e.g. remove
+ * @param {Function} cb - gets called when an error occurred or when the operation was successful
+ */
+export default (to, userId, type, cb) => {
+	const data = {
+		from: "Musare <noreply@musare.com>",
+		to,
+		subject: `Data Request - ${type}`,
+		html: `
+				Hello,
+				<br>
+				<br>
+				User ${userId} has requested to ${type} the data for their account on Musare.
+				<br>
+				<br>
+				This request can be viewed and resolved in the <a href="${config.get(
+					"domain"
+				)}/admin/users">Users tab of the admin page</a>. Note: All admins will be sent the same message.
+			`
+	};
+
+	mail.runJob("SEND_MAIL", { data })
+		.then(() => cb())
+		.catch(err => cb(err));
+};

+ 0 - 3
backend/logic/mail/schemas/verifyEmail.js

@@ -1,7 +1,4 @@
 import config from "config";
-
-// const moduleManager = require('../../../index');
-
 import mail from "../index";
 
 /**

+ 2 - 1
frontend/src/components/modals/RemoveAccount.vue

@@ -155,7 +155,8 @@
 			>
 				<h2 class="content-box-title">Remove your account</h2>
 				<p class="content-box-description">
-					There is no going back after confirming account removal.
+					Your account will be deactivated instantly and your data
+					will shortly be deleted by an admin.
 				</p>
 
 				<div class="content-box-inputs">