Browse Source

Made backend actions run in jobs when called from socket.io

Kristian Vos 4 years ago
parent
commit
6d70540a84

+ 11 - 1
backend/core.js

@@ -243,6 +243,16 @@ class Job {
 	setResponseType(responseType) {
 		this.responseType = responseType;
 	}
+
+	/**
+	 * Logs to the module of the job
+	 *
+	 * @param  {any} args
+	 */
+	log(...args) {
+		args.splice(1, 0, this.name); // Adds the name of the job as the first argument (after INFO/SUCCESS/ERROR).
+		this.module.log.apply(this.module, args);
+	}
 }
 
 class MovingAverageCalculator {
@@ -382,7 +392,7 @@ export default class CoreClass {
 		if (this.logRules.blacklistedTerms.some(blacklistedTerm => _arguments.join().indexOf(blacklistedTerm) !== -1))
 			return;
 
-		if (type === "INFO") {
+		if (type === "INFO" || type === "SUCCESS") {
 			_arguments[0] += "\x1b[36m";
 			_arguments.push("\x1b[0m");
 			console.log.apply(null, _arguments);

+ 39 - 13
backend/index.js

@@ -380,6 +380,34 @@ moduleManager.addModule("youtube");
 
 moduleManager.initialize();
 
+/**
+ * Prints a job
+ *
+ * @param {Job} job - the job
+ * @param {number} layer - the layer
+ */
+function printJob(job, layer) {
+	const tabs = Array(layer).join("\t");
+	console.log(`${tabs}${job.name} (${job.toString()}) ${job.status}`);
+	job.childJobs.forEach(childJob => {
+		printJob(childJob, layer + 1);
+	});
+}
+
+/**
+ * Prints a task
+ *
+ * @param {Task} task - the task
+ * @param {number} layer - the layer
+ */
+function printTask(task, layer) {
+	const tabs = Array(layer).join("\t");
+	console.log(`${tabs}${task.job.name} (${task.job.toString()}) ${task.job.status} (priority: ${task.priority})`);
+	task.job.childJobs.forEach(childJob => {
+		printJob(childJob, layer + 1);
+	});
+}
+
 process.stdin.on("data", data => {
 	const command = data.toString().replace(/\r?\n|\r/g, "");
 	if (command === "lockdown") {
@@ -405,33 +433,31 @@ process.stdin.on("data", data => {
 	if (command.startsWith("running")) {
 		const parts = command.split(" ");
 
-		console.log(moduleManager.modules[parts[1]].jobQueue.runningTasks);
+		moduleManager.modules[parts[1]].jobQueue.runningTasks.forEach(task => {
+			printTask(task, 1);
+		});
 	}
 	if (command.startsWith("queued")) {
 		const parts = command.split(" ");
 
-		console.log(moduleManager.modules[parts[1]].jobQueue.queue);
+		moduleManager.modules[parts[1]].jobQueue.queue.forEach(task => {
+			printTask(task, 1);
+		});
 	}
 	if (command.startsWith("paused")) {
 		const parts = command.split(" ");
 
-		console.log(moduleManager.modules[parts[1]].jobQueue.pausedTasks);
+		moduleManager.modules[parts[1]].jobQueue.pausedTasks.forEach(task => {
+			printTask(task, 1);
+		});
 	}
 	if (command.startsWith("stats")) {
 		const parts = command.split(" ");
 
 		console.log(moduleManager.modules[parts[1]].jobStatistics);
 	}
-	if (command.startsWith("debug")) {
-		moduleManager.modules.youtube
-			.runJob("GET_PLAYLIST", { url: "https://www.youtube.com/playlist?list=PLN-cFDG8y28Pz4dkAFwDNH0as0-prFfvR" })
-			.then(response => {
-				console.log(1111, response);
-			})
-			.catch(err => {
-				console.log(1112, err);
-			});
-	}
+	// if (command.startsWith("debug")) {
+	// }
 
 	if (command.startsWith("eval")) {
 		const evalCommand = command.replace("eval ", "");

+ 22 - 14
backend/logic/actions/activities.js

@@ -16,10 +16,14 @@ export default {
 	 * @param {number} set - the set number to return
 	 * @param {Function} cb - callback
 	 */
-	getSet: async (session, userId, set, cb) => {
-		const activityModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "activity"
-		});
+	async getSet(session, userId, set, cb) {
+		const activityModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "activity"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -33,12 +37,12 @@ export default {
 			],
 			async (err, activities) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "ACTIVITIES_GET_SET", `Failed to get set ${set} from activities. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "ACTIVITIES_GET_SET", `Failed to get set ${set} from activities. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log("SUCCESS", "ACTIVITIES_GET_SET", `Set ${set} from activities obtained successfully.`);
+				this.log("SUCCESS", "ACTIVITIES_GET_SET", `Set ${set} from activities obtained successfully.`);
 				return cb({ status: "success", data: activities });
 			}
 		);
@@ -51,10 +55,14 @@ export default {
 	 * @param {string} activityId - the activity which should be hidden
 	 * @param cb
 	 */
-	hideActivity: isLoginRequired(async (session, activityId, cb) => {
-		const activityModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "activity"
-		});
+	hideActivity: isLoginRequired(async function hideActivity(session, activityId, cb) {
+		const activityModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "activity"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -63,12 +71,12 @@ export default {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "ACTIVITIES_HIDE_ACTIVITY", `Failed to hide activity ${activityId}. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "ACTIVITIES_HIDE_ACTIVITY", `Failed to hide activity ${activityId}. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log("SUCCESS", "ACTIVITIES_HIDE_ACTIVITY", `Successfully hid activity ${activityId}.`);
+				this.log("SUCCESS", "ACTIVITIES_HIDE_ACTIVITY", `Successfully hid activity ${activityId}.`);
 				return cb({ status: "success" });
 			}
 		);

+ 11 - 11
backend/logic/actions/apis.js

@@ -18,7 +18,7 @@ export default {
 	 * @param {Function} cb - callback
 	 * @returns {{status: string, data: object}} - returns an object
 	 */
-	searchYoutube: (session, query, cb) => {
+	searchYoutube(session, query, cb) {
 		const params = [
 			"part=snippet",
 			`q=${encodeURIComponent(query)}`,
@@ -41,15 +41,15 @@ export default {
 				console.log(data.error);
 				if (err || data.error) {
 					if (!err) err = data.error.message;
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"APIS_SEARCH_YOUTUBE",
 						`Searching youtube failed with query "${query}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "APIS_SEARCH_YOUTUBE", `Searching YouTube successful with query "${query}".`);
+				this.log("SUCCESS", "APIS_SEARCH_YOUTUBE", `Searching YouTube successful with query "${query}".`);
 				return cb({ status: "success", data });
 			}
 		);
@@ -62,7 +62,7 @@ export default {
 	 * @param query - the query
 	 * @param {Function} cb
 	 */
-	searchDiscogs: isAdminRequired((session, query, page, cb) => {
+	searchDiscogs: isAdminRequired(function searchDiscogs(session, query, page, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -88,15 +88,15 @@ export default {
 			],
 			async (err, body) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"APIS_SEARCH_DISCOGS",
 						`Searching discogs failed with query "${query}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"APIS_SEARCH_DISCOGS",
 					`User "${session.userId}" searched Discogs succesfully for query "${query}".`
@@ -117,7 +117,7 @@ export default {
 	 * @param {string} page - the room to join
 	 * @param {Function} cb - callback
 	 */
-	joinRoom: (session, page, cb) => {
+	joinRoom(session, page, cb) {
 		if (page === "home") {
 			IOModule.runJob("SOCKET_JOIN_ROOM", {
 				socketId: session.socketId,
@@ -125,7 +125,7 @@ export default {
 			})
 				.then()
 				.catch(err => {
-					console.log("ERROR", `Joining room failed: ${err.message}`);
+					this.log("ERROR", `Joining room failed: ${err.message}`);
 				});
 		}
 		cb({});
@@ -163,7 +163,7 @@ export default {
 	 * @param {object} session - user session
 	 * @param {Function} cb - callback
 	 */
-	ping: (session, cb) => {
+	ping(session, cb) {
 		cb({ date: Date.now() });
 	}
 };

+ 40 - 35
backend/logic/actions/hooks/adminRequired.js

@@ -6,41 +6,46 @@ const DBModule = moduleManager.modules.db;
 const CacheModule = moduleManager.modules.cache;
 const UtilsModule = moduleManager.modules.utils;
 
-export default destination => async (session, ...args) => {
-	const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
+export default destination =>
+	async function adminRequired(session, ...args) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 
-	const cb = args[args.length - 1];
+		const cb = args[args.length - 1];
 
-	async.waterfall(
-		[
-			next => {
-				CacheModule.runJob("HGET", {
-					table: "sessions",
-					key: session.sessionId
-				})
-					.then(session => {
-						next(null, session);
-					})
-					.catch(next);
-			},
-			(session, next) => {
-				if (!session || !session.userId) return next("Login required.");
-				return userModel.findOne({ _id: session.userId }, next);
-			},
-			(user, next) => {
-				if (!user) return next("Login required.");
-				if (user.role !== "admin") return next("Insufficient permissions.");
-				return next();
+		async.waterfall(
+			[
+				next => {
+					CacheModule.runJob(
+						"HGET",
+						{
+							table: "sessions",
+							key: session.sessionId
+						},
+						this
+					)
+						.then(session => {
+							next(null, session);
+						})
+						.catch(next);
+				},
+				(session, next) => {
+					if (!session || !session.userId) return next("Login required.");
+					return userModel.findOne({ _id: session.userId }, next);
+				},
+				(user, next) => {
+					if (!user) return next("Login required.");
+					if (user.role !== "admin") return next("Insufficient permissions.");
+					return next();
+				}
+			],
+			async err => {
+				if (err) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("INFO", "ADMIN_REQUIRED", `User failed to pass admin required check. "${err}"`);
+					return cb({ status: "failure", message: err });
+				}
+				this.log("INFO", "ADMIN_REQUIRED", `User "${session.userId}" passed admin required check.`, false);
+				return destination.apply(this, [session].concat(args));
 			}
-		],
-		async err => {
-			if (err) {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err });
-				console.log("INFO", "ADMIN_REQUIRED", `User failed to pass admin required check. "${err}"`);
-				return cb({ status: "failure", message: err });
-			}
-			console.log("INFO", "ADMIN_REQUIRED", `User "${session.userId}" passed admin required check.`, false);
-			return destination(session, ...args);
-		}
-	);
-};
+		);
+	};

+ 32 - 27
backend/logic/actions/hooks/loginRequired.js

@@ -5,32 +5,37 @@ import moduleManager from "../../../index";
 const CacheModule = moduleManager.modules.cache;
 const UtilsModule = moduleManager.modules.utils;
 
-export default destination => (session, ...args) => {
-	const cb = args[args.length - 1];
+export default destination =>
+	function loginRequired(session, ...args) {
+		const cb = args[args.length - 1];
 
-	async.waterfall(
-		[
-			next => {
-				CacheModule.runJob("HGET", {
-					table: "sessions",
-					key: session.sessionId
-				})
-					.then(session => next(null, session))
-					.catch(next);
-			},
-			(session, next) => {
-				if (!session || !session.userId) return next("Login required.");
-				return next();
+		async.waterfall(
+			[
+				next => {
+					CacheModule.runJob(
+						"HGET",
+						{
+							table: "sessions",
+							key: session.sessionId
+						},
+						this
+					)
+						.then(session => next(null, session))
+						.catch(next);
+				},
+				(session, next) => {
+					if (!session || !session.userId) return next("Login required.");
+					return next();
+				}
+			],
+			async err => {
+				if (err) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("LOGIN_REQUIRED", `User failed to pass login required check.`);
+					return cb({ status: "failure", message: err });
+				}
+				this.log("LOGIN_REQUIRED", `User "${session.userId}" passed login required check.`);
+				return destination.apply(this, [session].concat(args));
 			}
-		],
-		async err => {
-			if (err) {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err });
-				console.log("LOGIN_REQUIRED", `User failed to pass login required check.`);
-				return cb({ status: "failure", message: err });
-			}
-			console.log("LOGIN_REQUIRED", `User "${session.userId}" passed login required check.`);
-			return destination(session, ...args);
-		}
-	);
-};
+		);
+	};

+ 56 - 51
backend/logic/actions/hooks/ownerRequired.js

@@ -7,60 +7,65 @@ const CacheModule = moduleManager.modules.cache;
 const UtilsModule = moduleManager.modules.utils;
 const StationsModule = moduleManager.modules.stations;
 
-export default destination => async (session, stationId, ...args) => {
-	const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
+export default destination =>
+	async function ownerRequired(session, stationId, ...args) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 
-	const cb = args[args.length - 1];
+		const cb = args[args.length - 1];
 
-	async.waterfall(
-		[
-			next => {
-				CacheModule.runJob("HGET", {
-					table: "sessions",
-					key: session.sessionId
-				})
-					.then(session => {
-						next(null, session);
-					})
-					.catch(next);
-			},
-			(session, next) => {
-				if (!session || !session.userId) return next("Login required.");
-				return userModel.findOne({ _id: session.userId }, next);
-			},
-			(user, next) => {
-				if (!user) return next("Login required.");
-				if (user.role === "admin") return next(true);
-				return StationsModule.runJob("GET_STATION", { stationId })
-					.then(station => {
-						next(null, station);
-					})
-					.catch(next);
-			},
-			(station, next) => {
-				if (!station) return next("Station not found.");
-				if (station.type === "community" && station.owner === session.userId) return next(true);
-				return next("Invalid permissions.");
-			}
-		],
-		async err => {
-			if (err !== true) {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err });
-				console.log(
+		async.waterfall(
+			[
+				next => {
+					CacheModule.runJob(
+						"HGET",
+						{
+							table: "sessions",
+							key: session.sessionId
+						},
+						this
+					)
+						.then(session => {
+							next(null, session);
+						})
+						.catch(next);
+				},
+				(session, next) => {
+					if (!session || !session.userId) return next("Login required.");
+					return userModel.findOne({ _id: session.userId }, next);
+				},
+				(user, next) => {
+					if (!user) return next("Login required.");
+					if (user.role === "admin") return next(true);
+					return StationsModule.runJob("GET_STATION", { stationId }, this)
+						.then(station => {
+							next(null, station);
+						})
+						.catch(next);
+				},
+				(station, next) => {
+					if (!station) return next("Station not found.");
+					if (station.type === "community" && station.owner === session.userId) return next(true);
+					return next("Invalid permissions.");
+				}
+			],
+			async err => {
+				if (err !== true) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
+						"INFO",
+						"OWNER_REQUIRED",
+						`User failed to pass owner required check for station "${stationId}". "${err}"`
+					);
+					return cb({ status: "failure", message: err });
+				}
+				this.log(
 					"INFO",
 					"OWNER_REQUIRED",
-					`User failed to pass owner required check for station "${stationId}". "${err}"`
+					`User "${session.userId}" passed owner required check for station "${stationId}"`,
+					false
 				);
-				return cb({ status: "failure", message: err });
-			}
-			console.log(
-				"INFO",
-				"OWNER_REQUIRED",
-				`User "${session.userId}" passed owner required check for station "${stationId}"`,
-				false
-			);
 
-			return destination(session, stationId, ...args);
-		}
-	);
-};
+				return destination.apply(this, [session, stationId].concat(args));
+			}
+		);
+	};

+ 25 - 29
backend/logic/actions/news.js

@@ -46,8 +46,8 @@ export default {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
 	 */
-	index: async (session, cb) => {
-		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" });
+	async index(session, cb) {
+		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -56,11 +56,11 @@ export default {
 			],
 			async (err, news) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "NEWS_INDEX", `Indexing news failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "NEWS_INDEX", `Indexing news failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "NEWS_INDEX", `Indexing news successful.`, false);
+				this.log("SUCCESS", "NEWS_INDEX", `Indexing news successful.`, false);
 				return cb({ status: "success", data: news });
 			}
 		);
@@ -73,8 +73,8 @@ export default {
 	 * @param {object} data - the object of the news data
 	 * @param {Function} cb - gets called with the result
 	 */
-	create: isAdminRequired(async (session, data, cb) => {
-		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" });
+	create: isAdminRequired(async function create(session, data, cb) {
+		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -85,12 +85,12 @@ export default {
 			],
 			async (err, news) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "NEWS_CREATE", `Creating news failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "NEWS_CREATE", `Creating news failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
 				CacheModule.runJob("PUB", { channel: "news.create", value: news });
-				console.log("SUCCESS", "NEWS_CREATE", `Creating news successful.`);
+				this.log("SUCCESS", "NEWS_CREATE", `Creating news successful.`);
 				return cb({
 					status: "success",
 					message: "Successfully created News"
@@ -105,8 +105,8 @@ export default {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
 	 */
-	newest: async (session, cb) => {
-		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" });
+	async newest(session, cb) {
+		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -115,11 +115,11 @@ export default {
 			],
 			async (err, news) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "NEWS_NEWEST", `Getting the latest news failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "NEWS_NEWEST", `Getting the latest news failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "NEWS_NEWEST", `Successfully got the latest news.`, false);
+				this.log("SUCCESS", "NEWS_NEWEST", `Successfully got the latest news.`, false);
 				return cb({ status: "success", data: news });
 			}
 		);
@@ -134,12 +134,12 @@ export default {
 	 */
 	// TODO Pass in an id, not an object
 	// TODO Fix this
-	remove: isAdminRequired(async (session, news, cb) => {
-		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" });
+	remove: isAdminRequired(async function remove(session, news, cb) {
+		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" }, this);
 		newsModel.deleteOne({ _id: news._id }, async err => {
 			if (err) {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err });
-				console.log(
+				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+				this.log(
 					"ERROR",
 					"NEWS_REMOVE",
 					`Removing news "${news._id}" failed for user "${session.userId}". "${err}"`
@@ -147,11 +147,7 @@ export default {
 				return cb({ status: "failure", message: err });
 			}
 			CacheModule.runJob("PUB", { channel: "news.remove", value: news });
-			console.log(
-				"SUCCESS",
-				"NEWS_REMOVE",
-				`Removing news "${news._id}" successful by user "${session.userId}".`
-			);
+			this.log("SUCCESS", "NEWS_REMOVE", `Removing news "${news._id}" successful by user "${session.userId}".`);
 			return cb({
 				status: "success",
 				message: "Successfully removed News"
@@ -168,12 +164,12 @@ export default {
 	 * @param {Function} cb - gets called with the result
 	 */
 	// TODO Fix this
-	update: isAdminRequired(async (session, _id, news, cb) => {
-		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" });
+	update: isAdminRequired(async function update(session, _id, news, cb) {
+		const newsModel = await DBModule.runJob("GET_MODEL", { modelName: "news" }, this);
 		newsModel.updateOne({ _id }, news, { upsert: true }, async err => {
 			if (err) {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err });
-				console.log(
+				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+				this.log(
 					"ERROR",
 					"NEWS_UPDATE",
 					`Updating news "${_id}" failed for user "${session.userId}". "${err}"`
@@ -181,7 +177,7 @@ export default {
 				return cb({ status: "failure", message: err });
 			}
 			CacheModule.runJob("PUB", { channel: "news.update", value: news });
-			console.log("SUCCESS", "NEWS_UPDATE", `Updating news "${_id}" successful for user "${session.userId}".`);
+			this.log("SUCCESS", "NEWS_UPDATE", `Updating news "${_id}" successful for user "${session.userId}".`);
 			return cb({
 				status: "success",
 				message: "Successfully updated News"

+ 167 - 119
backend/logic/actions/playlists.js

@@ -16,7 +16,7 @@ const ActivitiesModule = moduleManager.modules.activities;
 CacheModule.runJob("SUB", {
 	channel: "playlist.create",
 	cb: playlist => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: playlist.createdBy }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: playlist.createdBy }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.create", playlist);
 			});
@@ -27,7 +27,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.delete",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.delete", res.playlistId);
 			});
@@ -38,7 +38,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.moveSongToTop",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.moveSongToTop", {
 					playlistId: res.playlistId,
@@ -52,7 +52,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.moveSongToBottom",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.moveSongToBottom", {
 					playlistId: res.playlistId,
@@ -66,7 +66,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.addSong",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.addSong", {
 					playlistId: res.playlistId,
@@ -80,7 +80,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.removeSong",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.removeSong", {
 					playlistId: res.playlistId,
@@ -94,7 +94,7 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.updateDisplayName",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }).then(response => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
 			response.sockets.forEach(socket => {
 				socket.emit("event:playlist.updateDisplayName", {
 					playlistId: res.playlistId,
@@ -113,11 +113,11 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are getting the first song from
 	 * @param {Function} cb - gets called with the result
 	 */
-	getFirstSong: isLoginRequired((session, playlistId, cb) => {
+	getFirstSong: isLoginRequired(function getFirstSong(session, playlistId, cb) {
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -131,15 +131,15 @@ const lib = {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_GET_FIRST_SONG",
 						`Getting the first song of playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_GET_FIRST_SONG",
 					`Successfully got the first song of playlist "${playlistId}" for user "${session.userId}".`
@@ -158,10 +158,14 @@ const lib = {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
 	 */
-	indexForUser: isLoginRequired(async (session, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	indexForUser: isLoginRequired(async function indexForUser(session, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -170,15 +174,15 @@ const lib = {
 			],
 			async (err, playlists) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_INDEX_FOR_USER",
 						`Indexing playlists for user "${session.userId}" failed. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_INDEX_FOR_USER",
 					`Successfully indexed playlists for user "${session.userId}".`
@@ -198,10 +202,14 @@ const lib = {
 	 * @param {object} data - the data for the new private playlist
 	 * @param {Function} cb - gets called with the result
 	 */
-	create: isLoginRequired(async (session, data, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	create: isLoginRequired(async function create(session, data, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => (data ? next() : cb({ status: "failure", message: "Invalid data" })),
@@ -221,8 +229,8 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_CREATE",
 						`Creating private playlist failed for user "${session.userId}". "${err}"`
@@ -241,7 +249,7 @@ const lib = {
 					payload: [playlist._id]
 				});
 
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_CREATE",
 					`Successfully created private playlist for user "${session.userId}".`
@@ -265,11 +273,11 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are getting
 	 * @param {Function} cb - gets called with the result
 	 */
-	getPlaylist: isLoginRequired((session, playlistId, cb) => {
+	getPlaylist: isLoginRequired(function getPlaylist(session, playlistId, cb) {
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -283,15 +291,15 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_GET",
 						`Getting private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_GET",
 					`Successfully got private playlist "${playlistId}" for user "${session.userId}".`
@@ -311,11 +319,11 @@ const lib = {
 	 * @param {string} playlistId - the playlist id
 	 * @param {Function} cb - callback
 	 */
-	getPlaylistForActivity: (session, playlistId, cb) => {
+	getPlaylistForActivity(session, playlistId, cb) {
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -324,15 +332,15 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLISTS_GET_PLAYLIST_FOR_ACTIVITY",
 						`Failed to obtain metadata of playlist ${playlistId} for activity formatting. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLISTS_GET_PLAYLIST_FOR_ACTIVITY",
 					`Obtained metadata of playlist ${playlistId} for activity formatting successfully.`
@@ -356,10 +364,14 @@ const lib = {
 	 * @param {object} playlist - the new private playlist object
 	 * @param {Function} cb - gets called with the result
 	 */
-	update: isLoginRequired(async (session, playlistId, playlist, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	update: isLoginRequired(async function update(session, playlistId, playlist, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -372,7 +384,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -381,15 +393,15 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_UPDATE",
 						`Updating private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_UPDATE",
 					`Successfully updated private playlist "${playlistId}" for user "${session.userId}".`
@@ -409,10 +421,14 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are updating
 	 * @param {Function} cb - gets called with the result
 	 */
-	shuffle: isLoginRequired(async (session, playlistId, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	shuffle: isLoginRequired(async function shuffle(session, playlistId, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -421,7 +437,7 @@ const lib = {
 				},
 
 				(playlist, next) => {
-					UtilsModule.runJob("SHUFFLE", { array: playlist.songs })
+					UtilsModule.runJob("SHUFFLE", { array: playlist.songs }, this)
 						.then(result => {
 							next(null, result.array);
 						})
@@ -433,7 +449,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -442,15 +458,15 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_SHUFFLE",
 						`Updating private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_SHUFFLE",
 					`Successfully updated private playlist "${playlistId}" for user "${session.userId}".`
@@ -473,15 +489,19 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are adding the song to
 	 * @param {Function} cb - gets called with the result
 	 */
-	addSongToPlaylist: isLoginRequired(async (session, isSet, songId, playlistId, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	addSongToPlaylist: isLoginRequired(async function addSongToPlaylist(session, isSet, songId, playlistId, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							if (!playlist || playlist.createdBy !== session.userId)
 								return next("Something went wrong when trying to get the playlist");
@@ -498,7 +518,7 @@ const lib = {
 						.catch(next);
 				},
 				next => {
-					SongsModule.runJob("GET_SONG", { id: songId })
+					SongsModule.runJob("GET_SONG", { id: songId }, this)
 						.then(response => {
 							const { song } = response;
 							next(null, {
@@ -509,7 +529,7 @@ const lib = {
 							});
 						})
 						.catch(() => {
-							YouTubeModule.runJob("GET_SONG", { songId })
+							YouTubeModule.runJob("GET_SONG", { songId }, this)
 								.then(response => next(null, response.song))
 								.catch(next);
 						});
@@ -521,7 +541,7 @@ const lib = {
 						{ runValidators: true },
 						err => {
 							if (err) return next(err);
-							return PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+							return PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 								.then(playlist => next(null, playlist, newSong))
 								.catch(next);
 						}
@@ -530,15 +550,15 @@ const lib = {
 			],
 			async (err, playlist, newSong) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_ADD_SONG",
 						`Adding song "${songId}" to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_ADD_SONG",
 					`Successfully added song "${songId}" to private playlist "${playlistId}" for user "${session.userId}".`
@@ -576,7 +596,7 @@ const lib = {
 	 * @param {boolean} musicOnly - whether to only add music to the playlist
 	 * @param {Function} cb - gets called with the result
 	 */
-	addSetToPlaylist: isLoginRequired((session, url, playlistId, musicOnly, cb) => {
+	addSetToPlaylist: isLoginRequired(function addSetToPlaylist(session, url, playlistId, musicOnly, cb) {
 		let videosInPlaylistTotal = 0;
 		let songsInPlaylistTotal = 0;
 		let songsSuccess = 0;
@@ -587,10 +607,14 @@ const lib = {
 		async.waterfall(
 			[
 				next => {
-					YouTubeModule.runJob("GET_PLAYLIST", {
-						url,
-						musicOnly
-					}).then(response => {
+					YouTubeModule.runJob(
+						"GET_PLAYLIST",
+						{
+							url,
+							musicOnly
+						},
+						this
+					).then(response => {
 						if (response.filteredSongs) {
 							videosInPlaylistTotal = response.songs.length;
 							songsInPlaylistTotal = response.filteredSongs.length;
@@ -623,7 +647,7 @@ const lib = {
 				},
 
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -637,8 +661,8 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_IMPORT",
 						`Importing a YouTube playlist to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
@@ -650,7 +674,7 @@ const lib = {
 					activityType: "added_songs_to_playlist",
 					payload: addedSongs
 				});
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_IMPORT",
 					`Successfully imported a YouTube playlist to private playlist "${playlistId}" for user "${session.userId}". Videos in playlist: ${videosInPlaylistTotal}, songs in playlist: ${songsInPlaylistTotal}, songs successfully added: ${songsSuccess}, songs failed: ${songsFail}.`
@@ -678,10 +702,14 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are removing the song from
 	 * @param {Function} cb - gets called with the result
 	 */
-	removeSongFromPlaylist: isLoginRequired(async (session, songId, playlistId, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	removeSongFromPlaylist: isLoginRequired(async function removeSongFromPlaylist(session, songId, playlistId, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -691,7 +719,7 @@ const lib = {
 				},
 
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -704,7 +732,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -713,15 +741,15 @@ const lib = {
 			],
 			async (err, playlist) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_REMOVE_SONG",
 						`Removing song "${songId}" from private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_REMOVE_SONG",
 					`Successfully removed song "${songId}" from private playlist "${playlistId}" for user "${session.userId}".`
@@ -750,10 +778,14 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are updating the displayName for
 	 * @param {Function} cb - gets called with the result
 	 */
-	updateDisplayName: isLoginRequired(async (session, playlistId, displayName, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	updateDisplayName: isLoginRequired(async function updateDisplayName(session, playlistId, displayName, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -766,7 +798,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -775,15 +807,15 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_UPDATE_DISPLAY_NAME",
 						`Updating display name to "${displayName}" for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_UPDATE_DISPLAY_NAME",
 					`Successfully updated display name to "${displayName}" for private playlist "${playlistId}" for user "${session.userId}".`
@@ -812,14 +844,18 @@ const lib = {
 	 * @param {string} songId - the id of the song we are moving to the top of the list
 	 * @param {Function} cb - gets called with the result
 	 */
-	moveSongToTop: isLoginRequired(async (session, playlistId, songId, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	moveSongToTop: isLoginRequired(async function moveSongToTop(session, playlistId, songId, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -864,7 +900,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -873,8 +909,8 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_MOVE_SONG_TO_TOP",
 						`Moving song "${songId}" to the top for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
@@ -882,7 +918,7 @@ const lib = {
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_MOVE_SONG_TO_TOP",
 					`Successfully moved song "${songId}" to the top for private playlist "${playlistId}" for user "${session.userId}".`
@@ -913,14 +949,18 @@ const lib = {
 	 * @param {string} songId - the id of the song we are moving to the bottom of the list
 	 * @param {Function} cb - gets called with the result
 	 */
-	moveSongToBottom: isLoginRequired(async (session, playlistId, songId, cb) => {
-		const playlistModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "playlist"
-		});
+	moveSongToBottom: isLoginRequired(async function moveSongToBottom(session, playlistId, songId, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -962,7 +1002,7 @@ const lib = {
 				},
 
 				(res, next) => {
-					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId })
+					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
 							next(null, playlist);
 						})
@@ -971,8 +1011,8 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_MOVE_SONG_TO_BOTTOM",
 						`Moving song "${songId}" to the bottom for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
@@ -980,7 +1020,7 @@ const lib = {
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_MOVE_SONG_TO_BOTTOM",
 					`Successfully moved song "${songId}" to the bottom for private playlist "${playlistId}" for user "${session.userId}".`
@@ -1010,15 +1050,19 @@ const lib = {
 	 * @param {string} playlistId - the id of the playlist we are moving the song to the top from
 	 * @param {Function} cb - gets called with the result
 	 */
-	remove: isLoginRequired(async (session, playlistId, cb) => {
-		const stationModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "station"
-		});
+	remove: isLoginRequired(async function remove(session, playlistId, cb) {
+		const stationModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "station"
+			},
+			this
+		);
 
 		async.waterfall(
 			[
 				next => {
-					PlaylistsModule.runJob("DELETE_PLAYLIST", { playlistId }).then(next).catch(next);
+					PlaylistsModule.runJob("DELETE_PLAYLIST", { playlistId }, this).then(next).catch(next);
 				},
 
 				next => {
@@ -1045,9 +1089,13 @@ const lib = {
 									(res, next) => {
 										if (!station.partyMode) {
 											moduleManager.modules.stations
-												.runJob("UPDATE_STATION", {
-													stationId: station._id
-												})
+												.runJob(
+													"UPDATE_STATION",
+													{
+														stationId: station._id
+													},
+													this
+												)
 												.then(station => next(null, station))
 												.catch(next);
 											CacheModule.runJob("PUB", {
@@ -1074,8 +1122,8 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"PLAYLIST_REMOVE",
 						`Removing private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
@@ -1083,7 +1131,7 @@ const lib = {
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log(
+				this.log(
 					"SUCCESS",
 					"PLAYLIST_REMOVE",
 					`Successfully removed private playlist "${playlistId}" for user "${session.userId}".`

+ 27 - 19
backend/logic/actions/punishments.js

@@ -17,7 +17,7 @@ CacheModule.runJob("SUB", {
 			room: "admin.punishments",
 			args: ["event:admin.punishment.added", data.punishment]
 		});
-		IOModule.runJob("SOCKETS_FROM_IP", { ip: data.ip }).then(sockets => {
+		IOModule.runJob("SOCKETS_FROM_IP", { ip: data.ip }, this).then(sockets => {
 			sockets.forEach(socket => {
 				socket.disconnect(true);
 			});
@@ -32,10 +32,14 @@ export default {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
 	 */
-	index: isAdminRequired(async (session, cb) => {
-		const punishmentModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "punishment"
-		});
+	index: isAdminRequired(async function index(session, cb) {
+		const punishmentModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "punishment"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -44,11 +48,11 @@ export default {
 			],
 			async (err, punishments) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "PUNISHMENTS_INDEX", `Indexing punishments failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "PUNISHMENTS_INDEX", `Indexing punishments failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "PUNISHMENTS_INDEX", "Indexing punishments successful.");
+				this.log("SUCCESS", "PUNISHMENTS_INDEX", "Indexing punishments successful.");
 				return cb({ status: "success", data: punishments });
 			}
 		);
@@ -63,7 +67,7 @@ export default {
 	 * @param {string} expiresAt - the time the ban expires
 	 * @param {Function} cb - gets called with the result
 	 */
-	banIP: isAdminRequired((session, value, reason, expiresAt, cb) => {
+	banIP: isAdminRequired(function banIP(session, value, reason, expiresAt, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -111,13 +115,17 @@ export default {
 				},
 
 				next => {
-					PunishmentsModule.runJob("ADD_PUNISHMENT", {
-						type: "banUserIp",
-						value,
-						reason,
-						expiresAt,
-						punishedBy: session.userId
-					})
+					PunishmentsModule.runJob(
+						"ADD_PUNISHMENT",
+						{
+							type: "banUserIp",
+							value,
+							reason,
+							expiresAt,
+							punishedBy: session.userId
+						},
+						this
+					)
 						.then(punishment => {
 							next(null, punishment);
 						})
@@ -126,15 +134,15 @@ export default {
 			],
 			async (err, punishment) => {
 				if (err && err !== true) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"BAN_IP",
 						`User ${session.userId} failed to ban IP address ${value} with the reason ${reason}. '${err}'`
 					);
 					cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"BAN_IP",
 					`User ${session.userId} has successfully banned IP address ${value} with the reason ${reason}.`

+ 70 - 50
backend/logic/actions/queueSongs.js

@@ -59,10 +59,14 @@ const lib = {
 	 * @param session
 	 * @param cb
 	 */
-	length: isAdminRequired(async (session, cb) => {
-		const queueSongModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "queueSong"
-		});
+	length: isAdminRequired(async function length(session, cb) {
+		const queueSongModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "queueSong"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -71,11 +75,11 @@ const lib = {
 			],
 			async (err, count) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "QUEUE_SONGS_LENGTH", `Failed to get length from queue songs. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "QUEUE_SONGS_LENGTH", `Failed to get length from queue songs. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "QUEUE_SONGS_LENGTH", `Got length from queue songs successfully.`);
+				this.log("SUCCESS", "QUEUE_SONGS_LENGTH", `Got length from queue songs successfully.`);
 				return cb(count);
 			}
 		);
@@ -88,10 +92,14 @@ const lib = {
 	 * @param set - the set number to return
 	 * @param cb
 	 */
-	getSet: isAdminRequired(async (session, set, cb) => {
-		const queueSongModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "queueSong"
-		});
+	getSet: isAdminRequired(async function getSet(session, set, cb) {
+		const queueSongModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "queueSong"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -104,11 +112,11 @@ const lib = {
 			],
 			async (err, songs) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "QUEUE_SONGS_GET_SET", `Failed to get set from queue songs. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "QUEUE_SONGS_GET_SET", `Failed to get set from queue songs. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "QUEUE_SONGS_GET_SET", `Got set from queue songs successfully.`);
+				this.log("SUCCESS", "QUEUE_SONGS_GET_SET", `Got set from queue songs successfully.`);
 				return cb(songs);
 			}
 		);
@@ -122,10 +130,14 @@ const lib = {
 	 * @param {object} updatedSong - the object of the updated queueSong
 	 * @param {Function} cb - gets called with the result
 	 */
-	update: isAdminRequired(async (session, songId, updatedSong, cb) => {
-		const queueSongModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "queueSong"
-		});
+	update: isAdminRequired(async function update(session, songId, updatedSong, cb) {
+		const queueSongModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "queueSong"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -150,8 +162,8 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"QUEUE_UPDATE",
 						`Updating queuesong "${songId}" failed for user ${session.userId}. "${err}"`
@@ -159,7 +171,7 @@ const lib = {
 					return cb({ status: "failure", message: err });
 				}
 				CacheModule.runJob("PUB", { channel: "queue.update", value: songId });
-				console.log(
+				this.log(
 					"SUCCESS",
 					"QUEUE_UPDATE",
 					`User "${session.userId}" successfully update queuesong "${songId}".`
@@ -179,10 +191,14 @@ const lib = {
 	 * @param {string} songId - the id of the queuesong that gets removed
 	 * @param {Function} cb - gets called with the result
 	 */
-	remove: isAdminRequired(async (session, songId, cb) => {
-		const queueSongModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "queueSong"
-		});
+	remove: isAdminRequired(async function remove(session, songId, cb) {
+		const queueSongModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "queueSong"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -191,8 +207,8 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"QUEUE_REMOVE",
 						`Removing queuesong "${songId}" failed for user ${session.userId}. "${err}"`
@@ -203,7 +219,7 @@ const lib = {
 					channel: "queue.removedSong",
 					value: songId
 				});
-				console.log(
+				this.log(
 					"SUCCESS",
 					"QUEUE_REMOVE",
 					`User "${session.userId}" successfully removed queuesong "${songId}".`
@@ -223,13 +239,17 @@ const lib = {
 	 * @param {string} songId - the id of the song that gets added
 	 * @param {Function} cb - gets called with the result
 	 */
-	add: isLoginRequired(async (session, songId, cb) => {
+	add: isLoginRequired(async function add(session, songId, cb) {
 		const requestedAt = Date.now();
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const QueueSongModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "queueSong"
-		});
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const QueueSongModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "queueSong"
+			},
+			this
+		);
 
 		async.waterfall(
 			[
@@ -246,7 +266,7 @@ const lib = {
 				(song, next) => {
 					if (song) return next("This song has already been added.");
 					// TODO Add err object as first param of callback
-					return YouTubeModule.runJob("GET_SONG", { songId })
+					return YouTubeModule.runJob("GET_SONG", { songId }, this)
 						.then(response => {
 							const { song } = response;
 							song.duration = -1;
@@ -283,8 +303,8 @@ const lib = {
 			],
 			async (err, newSong) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"QUEUE_ADD",
 						`Adding queuesong "${songId}" failed for user ${session.userId}. "${err}"`
@@ -295,11 +315,7 @@ const lib = {
 					channel: "queue.newSong",
 					value: newSong._id
 				});
-				console.log(
-					"SUCCESS",
-					"QUEUE_ADD",
-					`User "${session.userId}" successfully added queuesong "${songId}".`
-				);
+				this.log("SUCCESS", "QUEUE_ADD", `User "${session.userId}" successfully added queuesong "${songId}".`);
 				return cb({
 					status: "success",
 					message: "Successfully added that song to the queue"
@@ -316,14 +332,18 @@ const lib = {
 	 * @param {boolean} musicOnly - whether to only get music from the playlist
 	 * @param {Function} cb - gets called with the result
 	 */
-	addSetToQueue: isLoginRequired((session, url, musicOnly, cb) => {
+	addSetToQueue: isLoginRequired(function addSetToQueue(session, url, musicOnly, cb) {
 		async.waterfall(
 			[
 				next => {
-					YouTubeModule.runJob("GET_PLAYLIST", {
-						url,
-						musicOnly
-					})
+					YouTubeModule.runJob(
+						"GET_PLAYLIST",
+						{
+							url,
+							musicOnly
+						},
+						this
+					)
 						.then(res => {
 							next(null, res.songs);
 						})
@@ -347,15 +367,15 @@ const lib = {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"QUEUE_IMPORT",
 						`Importing a YouTube playlist to the queue failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
-				console.log(
+				this.log(
 					"SUCCESS",
 					"QUEUE_IMPORT",
 					`Successfully imported a YouTube playlist to the queue for user "${session.userId}".`

+ 57 - 45
backend/logic/actions/reports.js

@@ -60,10 +60,14 @@ export default {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
 	 */
-	index: isAdminRequired(async (session, cb) => {
-		const reportModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "report"
-		});
+	index: isAdminRequired(async function index(session, cb) {
+		const reportModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "report"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -72,11 +76,11 @@ export default {
 			],
 			async (err, reports) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "REPORTS_INDEX", `Indexing reports failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "REPORTS_INDEX", `Indexing reports failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "REPORTS_INDEX", "Indexing reports successful.");
+				this.log("SUCCESS", "REPORTS_INDEX", "Indexing reports successful.");
 				return cb({ status: "success", data: reports });
 			}
 		);
@@ -89,10 +93,14 @@ export default {
 	 * @param {string} reportId - the id of the report to return
 	 * @param {Function} cb - gets called with the result
 	 */
-	findOne: isAdminRequired(async (session, reportId, cb) => {
-		const reportModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "report"
-		});
+	findOne: isAdminRequired(async function findOne(session, reportId, cb) {
+		const reportModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "report"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -101,11 +109,11 @@ export default {
 			],
 			async (err, report) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "REPORTS_FIND_ONE", `Finding report "${reportId}" failed. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "REPORTS_FIND_ONE", `Finding report "${reportId}" failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "REPORTS_FIND_ONE", `Finding report "${reportId}" successful.`);
+				this.log("SUCCESS", "REPORTS_FIND_ONE", `Finding report "${reportId}" successful.`);
 				return cb({ status: "success", data: report });
 			}
 		);
@@ -118,10 +126,14 @@ export default {
 	 * @param {string} songId - the id of the song to index reports for
 	 * @param {Function} cb - gets called with the result
 	 */
-	getReportsForSong: isAdminRequired(async (session, songId, cb) => {
-		const reportModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "report"
-		});
+	getReportsForSong: isAdminRequired(async function getReportsForSong(session, songId, cb) {
+		const reportModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "report"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -141,15 +153,11 @@ export default {
 			],
 			async (err, data) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
-						"ERROR",
-						"GET_REPORTS_FOR_SONG",
-						`Indexing reports for song "${songId}" failed. "${err}"`
-					);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" successful.`);
+				this.log("SUCCESS", "GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" successful.`);
 				return cb({ status: "success", data });
 			}
 		);
@@ -162,10 +170,14 @@ export default {
 	 * @param {string} reportId - the id of the report that is getting resolved
 	 * @param {Function} cb - gets called with the result
 	 */
-	resolve: isAdminRequired(async (session, reportId, cb) => {
-		const reportModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "report"
-		});
+	resolve: isAdminRequired(async function resolve(session, reportId, cb) {
+		const reportModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "report"
+			},
+			this
+		);
 		async.waterfall(
 			[
 				next => {
@@ -183,8 +195,8 @@ export default {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"REPORTS_RESOLVE",
 						`Resolving report "${reportId}" failed by user "${session.userId}". "${err}"`
@@ -195,7 +207,7 @@ export default {
 					channel: "report.resolve",
 					value: reportId
 				});
-				console.log("SUCCESS", "REPORTS_RESOLVE", `User "${session.userId}" resolved report "${reportId}".`);
+				this.log("SUCCESS", "REPORTS_RESOLVE", `User "${session.userId}" resolved report "${reportId}".`);
 				return cb({
 					status: "success",
 					message: "Successfully resolved Report"
@@ -211,11 +223,15 @@ export default {
 	 * @param {object} data - the object of the report data
 	 * @param {Function} cb - gets called with the result
 	 */
-	create: isLoginRequired(async (session, data, cb) => {
-		const reportModel = await DBModule.runJob("GET_MODEL", {
-			modelName: "report"
-		});
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	create: isLoginRequired(async function create(session, data, cb) {
+		const reportModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "report"
+			},
+			this
+		);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -224,7 +240,7 @@ export default {
 
 				(song, next) => {
 					if (!song) return next("Song not found.");
-					return SongsModule.runJob("GET_SONG", { id: song._id })
+					return SongsModule.runJob("GET_SONG", { id: song._id }, this)
 						.then(response => {
 							next(null, response.song);
 						})
@@ -284,8 +300,8 @@ export default {
 			],
 			async (err, report) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"REPORTS_CREATE",
 						`Creating report for "${data.song._id}" failed by user "${session.userId}". "${err}"`
@@ -296,11 +312,7 @@ export default {
 					channel: "report.create",
 					value: report
 				});
-				console.log(
-					"SUCCESS",
-					"REPORTS_CREATE",
-					`User "${session.userId}" created report for "${data.songId}".`
-				);
+				this.log("SUCCESS", "REPORTS_CREATE", `User "${session.userId}" created report for "${data.songId}".`);
 				return cb({
 					status: "success",
 					message: "Successfully created report"

+ 70 - 74
backend/logic/actions/songs.js

@@ -160,8 +160,8 @@ export default {
 	 * @param {object} session - the session object automatically added by socket.io
 	 * @param cb
 	 */
-	length: isAdminRequired(async (session, cb) => {
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	length: isAdminRequired(async function length(session, cb) {
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -170,11 +170,11 @@ export default {
 			],
 			async (err, count) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "SONGS_LENGTH", `Failed to get length from songs. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "SONGS_LENGTH", `Failed to get length from songs. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "SONGS_LENGTH", `Got length from songs successfully.`);
+				this.log("SUCCESS", "SONGS_LENGTH", `Got length from songs successfully.`);
 				return cb(count);
 			}
 		);
@@ -187,8 +187,8 @@ export default {
 	 * @param set - the set number to return
 	 * @param cb
 	 */
-	getSet: isAdminRequired(async (session, set, cb) => {
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	getSet: isAdminRequired(async function getSet(session, set, cb) {
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -201,11 +201,11 @@ export default {
 			],
 			async (err, songs) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "SONGS_GET_SET", `Failed to get set from songs. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "SONGS_GET_SET", `Failed to get set from songs. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "SONGS_GET_SET", `Got set from songs successfully.`);
+				this.log("SUCCESS", "SONGS_GET_SET", `Got set from songs successfully.`);
 				return cb(songs);
 			}
 		);
@@ -218,11 +218,11 @@ export default {
 	 * @param {string} songId - the song id
 	 * @param {Function} cb
 	 */
-	getSong: isAdminRequired((session, songId, cb) => {
+	getSong: isAdminRequired(function getSong(session, songId, cb) {
 		async.waterfall(
 			[
 				next => {
-					SongsModule.runJob("GET_SONG_FROM_ID", { songId })
+					SongsModule.runJob("GET_SONG_FROM_ID", { songId }, this)
 						.then(song => {
 							next(null, song);
 						})
@@ -233,11 +233,11 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "SONGS_GET_SONG", `Failed to get song ${songId}. "${err}"`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "SONGS_GET_SONG", `Failed to get song ${songId}. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				console.log("SUCCESS", "SONGS_GET_SONG", `Got song ${songId} successfully.`);
+				this.log("SUCCESS", "SONGS_GET_SONG", `Got song ${songId} successfully.`);
 				return cb({ status: "success", data: song });
 			}
 		);
@@ -250,20 +250,20 @@ export default {
 	 * @param {string} songId - the song id
 	 * @param {Function} cb - callback
 	 */
-	getSongForActivity: (session, songId, cb) => {
+	getSongForActivity(session, songId, cb) {
 		async.waterfall(
 			[
 				next => {
-					SongsModule.runJob("GET_SONG_FROM_ID", { songId })
+					SongsModule.runJob("GET_SONG_FROM_ID", { songId }, this)
 						.then(response => next(null, response.song))
 						.catch(next);
 				}
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 
-					console.log(
+					this.log(
 						"ERROR",
 						"SONGS_GET_SONG_FOR_ACTIVITY",
 						`Failed to obtain metadata of song ${songId} for activity formatting. "${err}"`
@@ -273,7 +273,7 @@ export default {
 				}
 
 				if (song) {
-					console.log(
+					this.log(
 						"SUCCESS",
 						"SONGS_GET_SONG_FOR_ACTIVITY",
 						`Obtained metadata of song ${songId} for activity formatting successfully.`
@@ -288,7 +288,7 @@ export default {
 					});
 				}
 
-				console.log(
+				this.log(
 					"ERROR",
 					"SONGS_GET_SONG_FOR_ACTIVITY",
 					`Song ${songId} does not exist so failed to obtain for activity formatting.`
@@ -307,8 +307,8 @@ export default {
 	 * @param {object} song - the updated song object
 	 * @param {Function} cb
 	 */
-	update: isAdminRequired(async (session, songId, song, cb) => {
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	update: isAdminRequired(async function update(session, songId, song, cb) {
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -316,7 +316,7 @@ export default {
 				},
 
 				(res, next) => {
-					SongsModule.runJob("UPDATE_SONG", { songId })
+					SongsModule.runJob("UPDATE_SONG", { songId }, this)
 						.then(song => {
 							next(null, song);
 						})
@@ -325,14 +325,14 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 
-					console.log("ERROR", "SONGS_UPDATE", `Failed to update song "${songId}". "${err}"`);
+					this.log("ERROR", "SONGS_UPDATE", `Failed to update song "${songId}". "${err}"`);
 
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log("SUCCESS", "SONGS_UPDATE", `Successfully updated song "${songId}".`);
+				this.log("SUCCESS", "SONGS_UPDATE", `Successfully updated song "${songId}".`);
 
 				CacheModule.runJob("PUB", {
 					channel: "song.updated",
@@ -355,8 +355,8 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	remove: isAdminRequired(async (session, songId, cb) => {
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	remove: isAdminRequired(async function remove(session, songId, cb) {
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -365,7 +365,7 @@ export default {
 
 				(res, next) => {
 					// TODO Check if res gets returned from above
-					CacheModule.runJob("HDEL", { table: "songs", key: songId })
+					CacheModule.runJob("HDEL", { table: "songs", key: songId }, this)
 						.then(() => {
 							next();
 						})
@@ -374,14 +374,14 @@ export default {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 
-					console.log("ERROR", "SONGS_UPDATE", `Failed to remove song "${songId}". "${err}"`);
+					this.log("ERROR", "SONGS_UPDATE", `Failed to remove song "${songId}". "${err}"`);
 
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log("SUCCESS", "SONGS_UPDATE", `Successfully remove song "${songId}".`);
+				this.log("SUCCESS", "SONGS_UPDATE", `Successfully remove song "${songId}".`);
 
 				CacheModule.runJob("PUB", { channel: "song.removed", value: songId });
 
@@ -400,8 +400,8 @@ export default {
 	 * @param song - the song object
 	 * @param cb
 	 */
-	add: isAdminRequired(async (session, song, cb) => {
-		const SongModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	add: isAdminRequired(async function add(session, song, cb) {
+		const SongModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -428,18 +428,14 @@ export default {
 			],
 			async err => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 
-					console.log("ERROR", "SONGS_ADD", `User "${session.userId}" failed to add song. "${err}"`);
+					this.log("ERROR", "SONGS_ADD", `User "${session.userId}" failed to add song. "${err}"`);
 
 					return cb({ status: "failure", message: err });
 				}
 
-				console.log(
-					"SUCCESS",
-					"SONGS_ADD",
-					`User "${session.userId}" successfully added song "${song.songId}".`
-				);
+				this.log("SUCCESS", "SONGS_ADD", `User "${session.userId}" successfully added song "${song.songId}".`);
 
 				CacheModule.runJob("PUB", {
 					channel: "song.added",
@@ -462,9 +458,9 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	like: isLoginRequired(async (session, songId, cb) => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	like: isLoginRequired(async function like(session, songId, cb) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -478,12 +474,8 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
-						"ERROR",
-						"SONGS_LIKE",
-						`User "${session.userId}" failed to like song ${songId}. "${err}"`
-					);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "SONGS_LIKE", `User "${session.userId}" failed to like song ${songId}. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
 
@@ -579,9 +571,9 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	dislike: isLoginRequired(async (session, songId, cb) => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	dislike: isLoginRequired(async function dislike(session, songId, cb) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -595,8 +587,8 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"SONGS_DISLIKE",
 						`User "${session.userId}" failed to like song ${songId}. "${err}"`
@@ -687,9 +679,9 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	undislike: isLoginRequired(async (session, songId, cb) => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	undislike: isLoginRequired(async function undislike(session, songId, cb) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -703,8 +695,8 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"SONGS_UNDISLIKE",
 						`User "${session.userId}" failed to like song ${songId}. "${err}"`
@@ -790,9 +782,9 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	unlike: isLoginRequired(async (session, songId, cb) => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	unlike: isLoginRequired(async function unlike(session, songId, cb) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -806,8 +798,8 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"SONGS_UNLIKE",
 						`User "${session.userId}" failed to like song ${songId}. "${err}"`
@@ -892,9 +884,9 @@ export default {
 	 * @param songId - the song id
 	 * @param cb
 	 */
-	getOwnSongRatings: isLoginRequired(async (session, songId, cb) => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" });
+	getOwnSongRatings: isLoginRequired(async function getOwnSongRatings(session, songId, cb) {
+		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
+		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
@@ -908,8 +900,8 @@ export default {
 			],
 			async (err, song) => {
 				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log(
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
 						"ERROR",
 						"SONGS_GET_OWN_RATINGS",
 						`User "${session.userId}" failed to get ratings for ${songId}. "${err}"`
@@ -928,9 +920,13 @@ export default {
 					}
 					return cb({
 						status: "failure",
-						message: await UtilsModule.runJob("GET_ERROR", {
-							error: err
-						})
+						message: await UtilsModule.runJob(
+							"GET_ERROR",
+							{
+								error: err
+							},
+							this
+						)
 					});
 				});
 			}

File diff suppressed because it is too large
+ 265 - 180
backend/logic/actions/stations.js


File diff suppressed because it is too large
+ 260 - 195
backend/logic/actions/users.js


+ 10 - 18
backend/logic/actions/utils.js

@@ -7,7 +7,7 @@ import moduleManager from "../../index";
 const UtilsModule = moduleManager.modules.utils;
 
 export default {
-	getModules: isAdminRequired((session, cb) => {
+	getModules: isAdminRequired(function getModules(session, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -15,7 +15,7 @@ export default {
 				},
 
 				(modules, next) => {
-					// console.log(modules, next);
+					// this.log(modules, next);
 					next(
 						null,
 						Object.keys(modules).map(moduleName => {
@@ -35,15 +35,11 @@ export default {
 			],
 			async (err, modules) => {
 				if (err && err !== true) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "GET_MODULES", `User ${session.userId} failed to get modules. '${err}'`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "GET_MODULES", `User ${session.userId} failed to get modules. '${err}'`);
 					cb({ status: "failure", message: err });
 				} else {
-					console.log(
-						"SUCCESS",
-						"GET_MODULES",
-						`User ${session.userId} has successfully got the modules info.`
-					);
+					this.log("SUCCESS", "GET_MODULES", `User ${session.userId} has successfully got the modules info.`);
 					cb({
 						status: "success",
 						message: "Successfully got modules.",
@@ -54,7 +50,7 @@ export default {
 		);
 	}),
 
-	getModule: isAdminRequired((session, moduleName, cb) => {
+	getModule: isAdminRequired(function getModule(session, moduleName, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -62,17 +58,13 @@ export default {
 				}
 			],
 			async (err, module) => {
-				// console.log(module.runningJobs);
+				// this.log(module.runningJobs);
 				if (err && err !== true) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err });
-					console.log("ERROR", "GET_MODULE", `User ${session.userId} failed to get module. '${err}'`);
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "GET_MODULE", `User ${session.userId} failed to get module. '${err}'`);
 					cb({ status: "failure", message: err });
 				} else {
-					console.log(
-						"SUCCESS",
-						"GET_MODULE",
-						`User ${session.userId} has successfully got the module info.`
-					);
+					this.log("SUCCESS", "GET_MODULE", `User ${session.userId} has successfully got the module info.`);
 					cb({
 						status: "success",
 						message: "Successfully got module info.",

+ 367 - 261
backend/logic/io.js

@@ -37,13 +37,13 @@ class _IOModule extends CoreClass {
 		DBModule = this.moduleManager.modules.db;
 		PunishmentsModule = this.moduleManager.modules.punishments;
 
-		const actions = (await import("./actions")).default;
+		this.actions = (await import("./actions")).default;
 
 		this.userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
 
 		this.setStage(2);
 
-		const SIDname = config.get("cookie.SIDname");
+		this.SIDname = config.get("cookie.SIDname");
 
 		// TODO: Check every 30s/, for all sockets, if they are still allowed to be in the rooms they are in, and on socket at all (permission changing/banning)
 		const server = await AppModule.runJob("SERVER");
@@ -53,270 +53,13 @@ class _IOModule extends CoreClass {
 			this.setStage(3);
 
 			this._io.use(async (socket, cb) => {
-				if (this.getStatus() !== "READY") {
-					this.log(
-						"INFO",
-						"IO_REJECTED_CONNECTION",
-						`A user tried to connect, but the IO module is currently not ready. IP: ${socket.ip}`
-					);
-					return socket.disconnect(true);
-				}
-
-				let SID;
-
-				socket.ip = socket.request.headers["x-forwarded-for"] || "0.0.0.0";
-
-				return async.waterfall(
-					[
-						next => {
-							UtilsModule.runJob("PARSE_COOKIES", {
-								cookieString: socket.request.headers.cookie
-							}).then(res => {
-								SID = res[SIDname];
-								next(null);
-							});
-						},
-
-						next => {
-							if (!SID) return next("No SID.");
-							return next();
-						},
-
-						next => {
-							CacheModule.runJob("HGET", { table: "sessions", key: SID })
-								.then(session => {
-									next(null, session);
-								})
-								.catch(next);
-						},
-
-						(session, next) => {
-							if (!session) return next("No session found.");
-
-							session.refreshDate = Date.now();
-
-							socket.session = session;
-
-							return CacheModule.runJob("HSET", {
-								table: "sessions",
-								key: SID,
-								value: session
-							}).then(session => {
-								next(null, session);
-							});
-						},
-
-						(res, next) => {
-							// check if a session's user / IP is banned
-							PunishmentsModule.runJob("GET_PUNISHMENTS", {})
-								.then(punishments => {
-									const isLoggedIn = !!(socket.session && socket.session.refreshDate);
-									const userId = isLoggedIn ? socket.session.userId : null;
-
-									const banishment = {
-										banned: false,
-										ban: 0
-									};
-
-									punishments.forEach(punishment => {
-										if (punishment.expiresAt > banishment.ban) banishment.ban = punishment;
-										if (
-											punishment.type === "banUserId" &&
-											isLoggedIn &&
-											punishment.value === userId
-										)
-											banishment.banned = true;
-										if (punishment.type === "banUserIp" && punishment.value === socket.ip)
-											banishment.banned = true;
-									});
-
-									socket.banishment = banishment;
-
-									next();
-								})
-								.catch(() => {
-									next();
-								});
-						}
-					],
-					() => {
-						if (!socket.session) socket.session = { socketId: socket.id };
-						else socket.session.socketId = socket.id;
-
-						cb();
-					}
-				);
+				IOModule.runJob("HANDLE_IO_USE", { socket, cb });
 			});
 
 			this.setStage(4);
 
 			this._io.on("connection", async socket => {
-				let sessionInfo = "";
-
-				if (this.getStatus() !== "READY") {
-					this.log(
-						"INFO",
-						"IO_REJECTED_CONNECTION",
-						`A user tried to connect, but the IO module is currently not ready. IP: ${socket.ip}.${sessionInfo}`
-					);
-					return socket.disconnect(true);
-				}
-
-				if (socket.session.sessionId) sessionInfo = ` UserID: ${socket.session.userId}.`;
-
-				// if session is banned
-				if (socket.banishment && socket.banishment.banned) {
-					this.log(
-						"INFO",
-						"IO_BANNED_CONNECTION",
-						`A user tried to connect, but is currently banned. IP: ${socket.ip}.${sessionInfo}`
-					);
-
-					socket.emit("keep.event:banned", socket.banishment.ban);
-
-					return socket.disconnect(true);
-				}
-
-				this.log("INFO", "IO_CONNECTION", `User connected. IP: ${socket.ip}.${sessionInfo}`);
-
-				// catch when the socket has been disconnected
-				socket.on("disconnect", () => {
-					if (socket.session.sessionId) sessionInfo = ` UserID: ${socket.session.userId}.`;
-					this.log("INFO", "IO_DISCONNECTION", `User disconnected. IP: ${socket.ip}.${sessionInfo}`);
-				});
-
-				socket.use((data, next) => {
-					if (data.length === 0) return next(new Error("Not enough arguments specified."));
-					if (typeof data[0] !== "string") return next(new Error("First argument must be a string."));
-
-					const namespaceAction = data[0];
-					if (
-						!namespaceAction ||
-						namespaceAction.indexOf(".") === -1 ||
-						namespaceAction.indexOf(".") !== namespaceAction.lastIndexOf(".")
-					)
-						return next(new Error("Invalid first argument"));
-					const namespace = data[0].split(".")[0];
-					const action = data[0].split(".")[1];
-
-					if (!namespace) return next(new Error("Invalid namespace."));
-					if (!action) return next(new Error("Invalid action."));
-					if (!actions[namespace]) return next(new Error("Namespace not found."));
-					if (!actions[namespace][action]) return next(new Error("Action not found."));
-
-					return next();
-				});
-
-				// catch errors on the socket (internal to socket.io)
-				socket.on("error", console.error);
-
-				if (socket.session.sessionId) {
-					CacheModule.runJob("HGET", {
-						table: "sessions",
-						key: socket.session.sessionId
-					})
-						.then(session => {
-							if (session && session.userId) {
-								IOModule.userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (err || !user) return socket.emit("ready", false);
-
-									let role = "";
-									let username = "";
-									let userId = "";
-									if (user) {
-										role = user.role;
-										username = user.username;
-										userId = session.userId;
-									}
-
-									return socket.emit("ready", true, role, username, userId);
-								});
-							} else socket.emit("ready", false);
-						})
-						.catch(() => {
-							socket.emit("ready", false);
-						});
-				} else socket.emit("ready", false);
-
-				// have the socket listen for each action
-				return Object.keys(actions).forEach(namespace => {
-					Object.keys(actions[namespace]).forEach(action => {
-						// the full name of the action
-						const name = `${namespace}.${action}`;
-
-						// listen for this action to be called
-						socket.on(name, async (...args) => {
-							let cb = args[args.length - 1];
-
-							if (typeof cb !== "function")
-								cb = () => {
-									this.this.log("INFO", "IO_MODULE", `There was no callback provided for ${name}.`);
-								};
-							else args.pop();
-
-							if (this.getStatus() !== "READY") {
-								this.log(
-									"INFO",
-									"IO_REJECTED_ACTION",
-									`A user tried to execute an action, but the IO module is currently not ready. Action: ${namespace}.${action}.`
-								);
-								return;
-							}
-							this.log("INFO", "IO_ACTION", `A user executed an action. Action: ${namespace}.${action}.`);
-
-							let failedGettingSession = false;
-							// load the session from the cache
-							if (socket.session.sessionId)
-								await CacheModule.runJob("HGET", {
-									table: "sessions",
-									key: socket.session.sessionId
-								})
-									.then(session => {
-										// make sure the sockets sessionId isn't set if there is no session
-										if (socket.session.sessionId && session === null)
-											delete socket.session.sessionId;
-									})
-									.catch(() => {
-										failedGettingSession = true;
-										if (typeof cb === "function")
-											cb({
-												status: "error",
-												message: "An error occurred while obtaining your session"
-											});
-									});
-							if (!failedGettingSession)
-								try {
-									// call the action, passing it the session, and the arguments socket.io passed us
-									actions[namespace][action].apply(
-										null,
-										[socket.session].concat(args).concat([
-											result => {
-												this.log(
-													"INFO",
-													"IO_ACTION",
-													`Response to action. Action: ${namespace}.${action}. Response status: ${result.status}`
-												);
-												// respond to the socket with our message
-												if (typeof cb === "function") cb(result);
-											}
-										])
-									);
-								} catch (err) {
-									if (typeof cb === "function")
-										cb({
-											status: "error",
-											message: "An error occurred while executing the specified action."
-										});
-
-									this.log(
-										"ERROR",
-										"IO_ACTION_ERROR",
-										`Some type of exception occurred in the action ${namespace}.${action}. Error message: ${err.message}`
-									);
-								}
-						});
-					});
-				});
+				IOModule.runJob("HANDLE_IO_CONNECTION", { socket });
 			});
 
 			this.setStage(5);
@@ -661,6 +404,369 @@ class _IOModule extends CoreClass {
 			return resolve(roomSockets);
 		});
 	}
+
+	/**
+	 * Handles io.use
+	 *
+	 * @param {object} payload - object that contains the payload
+	 * @returns {Promise} - returns promise (reject, resolve)
+	 */
+	async HANDLE_IO_USE(payload) {
+		return new Promise(resolve => {
+			const { socket, cb } = payload;
+
+			let SID;
+
+			socket.ip = socket.request.headers["x-forwarded-for"] || "0.0.0.0";
+
+			return async.waterfall(
+				[
+					next => {
+						UtilsModule.runJob(
+							"PARSE_COOKIES",
+							{
+								cookieString: socket.request.headers.cookie
+							},
+							this
+						).then(res => {
+							SID = res[IOModule.SIDname];
+							next(null);
+						});
+					},
+
+					next => {
+						if (!SID) return next("No SID.");
+						return next();
+					},
+
+					next => {
+						CacheModule.runJob("HGET", { table: "sessions", key: SID }, this)
+							.then(session => {
+								next(null, session);
+							})
+							.catch(next);
+					},
+
+					(session, next) => {
+						if (!session) return next("No session found.");
+
+						session.refreshDate = Date.now();
+
+						socket.session = session;
+
+						return CacheModule.runJob(
+							"HSET",
+							{
+								table: "sessions",
+								key: SID,
+								value: session
+							},
+							this
+						).then(session => {
+							next(null, session);
+						});
+					},
+
+					(res, next) => {
+						// check if a session's user / IP is banned
+						PunishmentsModule.runJob("GET_PUNISHMENTS", {}, this)
+							.then(punishments => {
+								const isLoggedIn = !!(socket.session && socket.session.refreshDate);
+								const userId = isLoggedIn ? socket.session.userId : null;
+
+								const banishment = {
+									banned: false,
+									ban: 0
+								};
+
+								punishments.forEach(punishment => {
+									if (punishment.expiresAt > banishment.ban) banishment.ban = punishment;
+									if (punishment.type === "banUserId" && isLoggedIn && punishment.value === userId)
+										banishment.banned = true;
+									if (punishment.type === "banUserIp" && punishment.value === socket.ip)
+										banishment.banned = true;
+								});
+
+								socket.banishment = banishment;
+
+								next();
+							})
+							.catch(() => {
+								next();
+							});
+					}
+				],
+				() => {
+					if (!socket.session) socket.session = { socketId: socket.id };
+					else socket.session.socketId = socket.id;
+
+					cb();
+					resolve();
+				}
+			);
+		});
+	}
+
+	/**
+	 * Handles io.connection
+	 *
+	 * @param {object} payload - object that contains the payload
+	 * @returns {Promise} - returns promise (reject, resolve)
+	 */
+	async HANDLE_IO_CONNECTION(payload) {
+		return new Promise(resolve => {
+			const { socket } = payload;
+
+			let sessionInfo = "";
+
+			if (socket.session.sessionId) sessionInfo = ` UserID: ${socket.session.userId}.`;
+
+			// if session is banned
+			if (socket.banishment && socket.banishment.banned) {
+				IOModule.log(
+					"INFO",
+					"IO_BANNED_CONNECTION",
+					`A user tried to connect, but is currently banned. IP: ${socket.ip}.${sessionInfo}`
+				);
+
+				socket.emit("keep.event:banned", socket.banishment.ban);
+
+				return socket.disconnect(true);
+			}
+
+			IOModule.log("INFO", "IO_CONNECTION", `User connected. IP: ${socket.ip}.${sessionInfo}`);
+
+			// catch when the socket has been disconnected
+			socket.on("disconnect", () => {
+				if (socket.session.sessionId) sessionInfo = ` UserID: ${socket.session.userId}.`;
+				IOModule.log("INFO", "IO_DISCONNECTION", `User disconnected. IP: ${socket.ip}.${sessionInfo}`);
+			});
+
+			socket.use((data, next) => {
+				if (data.length === 0) return next(new Error("Not enough arguments specified."));
+				if (typeof data[0] !== "string") return next(new Error("First argument must be a string."));
+
+				const namespaceAction = data[0];
+				if (
+					!namespaceAction ||
+					namespaceAction.indexOf(".") === -1 ||
+					namespaceAction.indexOf(".") !== namespaceAction.lastIndexOf(".")
+				)
+					return next(new Error("Invalid first argument"));
+				const namespace = data[0].split(".")[0];
+				const action = data[0].split(".")[1];
+
+				if (!namespace) return next(new Error("Invalid namespace."));
+				if (!action) return next(new Error("Invalid action."));
+				if (!IOModule.actions[namespace]) return next(new Error("Namespace not found."));
+				if (!IOModule.actions[namespace][action]) return next(new Error("Action not found."));
+
+				return next();
+			});
+
+			// catch errors on the socket (internal to socket.io)
+			socket.on("error", console.error);
+
+			if (socket.session.sessionId) {
+				CacheModule.runJob("HGET", {
+					table: "sessions",
+					key: socket.session.sessionId
+				})
+					.then(session => {
+						if (session && session.userId) {
+							IOModule.userModel.findOne({ _id: session.userId }, (err, user) => {
+								if (err || !user) return socket.emit("ready", false);
+
+								let role = "";
+								let username = "";
+								let userId = "";
+								if (user) {
+									role = user.role;
+									username = user.username;
+									userId = session.userId;
+								}
+
+								return socket.emit("ready", true, role, username, userId);
+							});
+						} else socket.emit("ready", false);
+					})
+					.catch(() => {
+						socket.emit("ready", false);
+					});
+			} else socket.emit("ready", false);
+
+			// have the socket listen for each action
+			Object.keys(IOModule.actions).forEach(namespace => {
+				Object.keys(IOModule.actions[namespace]).forEach(action => {
+					// the full name of the action
+					const name = `${namespace}.${action}`;
+
+					// listen for this action to be called
+					socket.on(name, async (...args) => {
+						IOModule.runJob("RUN_ACTION", { socket, namespace, action, args });
+
+						/* let cb = args[args.length - 1];
+
+						if (typeof cb !== "function")
+							cb = () => {
+								IOModule.log("INFO", "IO_MODULE", `There was no callback provided for ${name}.`);
+							};
+						else args.pop();
+
+						if (this.getStatus() !== "READY") {
+							IOModule.log(
+								"INFO",
+								"IO_REJECTED_ACTION",
+								`A user tried to execute an action, but the IO module is currently not ready. Action: ${namespace}.${action}.`
+							);
+							return;
+						}
+						IOModule.log("INFO", "IO_ACTION", `A user executed an action. Action: ${namespace}.${action}.`);
+
+						let failedGettingSession = false;
+						// load the session from the cache
+						if (socket.session.sessionId)
+							await CacheModule.runJob("HGET", {
+								table: "sessions",
+								key: socket.session.sessionId
+							})
+								.then(session => {
+									// make sure the sockets sessionId isn't set if there is no session
+									if (socket.session.sessionId && session === null) delete socket.session.sessionId;
+								})
+								.catch(() => {
+									failedGettingSession = true;
+									if (typeof cb === "function")
+										cb({
+											status: "error",
+											message: "An error occurred while obtaining your session"
+										});
+								});
+						if (!failedGettingSession)
+							try {
+								// call the action, passing it the session, and the arguments socket.io passed us
+								this.runJob("RUN_ACTION", { namespace, action, session: socket.session, args })
+									.then(response => {
+										if (typeof cb === "function") cb(response);
+									})
+									.catch(err => {
+										if (typeof cb === "function") cb(err);
+									});
+								// actions[namespace][action].apply(
+								// 	null,
+								// 	[socket.session].concat(args).concat([
+								// 		result => {
+								// 			IOModule.log(
+								// 				"INFO",
+								// 				"IO_ACTION",
+								// 				`Response to action. Action: ${namespace}.${action}. Response status: ${result.status}`
+								// 			);
+								// 			// respond to the socket with our message
+								// 			if (typeof cb === "function") cb(result);
+								// 		}
+								// 	])
+								// );
+							} catch (err) {
+								if (typeof cb === "function")
+									cb({
+										status: "error",
+										message: "An error occurred while executing the specified action."
+									});
+
+								IOModule.log(
+									"ERROR",
+									"IO_ACTION_ERROR",
+									`Some type of exception occurred in the action ${namespace}.${action}. Error message: ${err.message}`
+								);
+							} */
+					});
+				});
+			});
+
+			return resolve();
+		});
+	}
+
+	/**
+	 * Runs an action
+	 *
+	 * @param {object} payload - object that contains the payload
+	 * @returns {Promise} - returns promise (reject, resolve)
+	 */
+	async RUN_ACTION(payload) {
+		return new Promise((resolve, reject) => {
+			const { socket, namespace, action, args } = payload;
+
+			// the full name of the action
+			const name = `${namespace}.${action}`;
+
+			let cb = args[args.length - 1];
+			if (typeof cb !== "function")
+				cb = () => {
+					IOModule.log("INFO", "IO_MODULE", `There was no callback provided for ${name}.`);
+				};
+			else args.pop();
+
+			IOModule.log("INFO", "IO_ACTION", `A user executed an action. Action: ${namespace}.${action}.`);
+
+			// load the session from the cache
+			new Promise(resolve => {
+				if (socket.session.sessionId)
+					CacheModule.runJob("HGET", {
+						table: "sessions",
+						key: socket.session.sessionId
+					})
+						.then(session => {
+							// make sure the sockets sessionId isn't set if there is no session
+							if (socket.session.sessionId && session === null) delete socket.session.sessionId;
+							resolve();
+						})
+						.catch(() => {
+							if (typeof cb === "function")
+								cb({
+									status: "error",
+									message: "An error occurred while obtaining your session"
+								});
+							reject(new Error("An error occurred while obtaining the session"));
+						});
+			})
+				.then(() => {
+					try {
+						// call the action, passing it the session, and the arguments socket.io passed us
+
+						IOModule.actions[namespace][action].apply(
+							this,
+							[socket.session].concat(args).concat([
+								result => {
+									IOModule.log(
+										"INFO",
+										"RUN_ACTION",
+										`Response to action. Action: ${namespace}.${action}. Response status: ${result.status}`
+									);
+									// respond to the socket with our message
+									if (typeof cb === "function") cb(result);
+									resolve();
+								}
+							])
+						);
+					} catch (err) {
+						if (typeof cb === "function")
+							cb({
+								status: "error",
+								message: "An error occurred while executing the specified action."
+							});
+						reject(err);
+
+						IOModule.log(
+							"ERROR",
+							"IO_ACTION_ERROR",
+							`Some type of exception occurred in the action ${namespace}.${action}. Error message: ${err.message}`
+						);
+					}
+				})
+				.catch(reject);
+		});
+	}
 }
 
 export default new _IOModule();

+ 2 - 2
backend/logic/tasks.js

@@ -430,7 +430,7 @@ class _TasksModule extends CoreClass {
 					StationsModule.usersPerStation = usersPerStation;
 
 					stationsCountUpdated.forEach(stationId => {
-						console.log("INFO", "UPDATE_STATION_USER_COUNT", `Updating user count of ${stationId}.`);
+						this.log("INFO", "UPDATE_STATION_USER_COUNT", `Updating user count of ${stationId}.`);
 						CacheModule.runJob("PUB", {
 							table: "station.updateUserCount",
 							value: stationId
@@ -438,7 +438,7 @@ class _TasksModule extends CoreClass {
 					});
 
 					stationsUpdated.forEach(stationId => {
-						console.log("INFO", "UPDATE_STATION_USER_LIST", `Updating user list of ${stationId}.`);
+						this.log("INFO", "UPDATE_STATION_USER_LIST", `Updating user list of ${stationId}.`);
 						CacheModule.runJob("PUB", {
 							table: "station.updateUsers",
 							value: stationId

Some files were not shown because too many files changed in this diff