Browse Source

feat(importJob): Added updated and removed functionality and event handling

Owen Diffey 2 years ago
parent
commit
95c2c9e6eb

+ 2 - 1
backend/logic/actions/apis.js

@@ -198,7 +198,8 @@ export default {
 			page === "statistics" ||
 			page === "punishments" ||
 			page === "youtube" ||
-			page === "youtubeVideos"
+			page === "youtubeVideos" ||
+			page === "import"
 		) {
 			WSModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: session.socketId }).then(() => {
 				WSModule.runJob("SOCKET_JOIN_ROOM", {

+ 19 - 0
backend/logic/actions/media.js

@@ -867,5 +867,24 @@ export default {
 				});
 			}
 		);
+	}),
+
+	/**
+	 * Remove import jobs
+	 *
+	 * @returns {{status: string, data: object}}
+	 */
+	removeImportJobs: isAdminRequired(function removeImportJobs(session, jobIds, cb) {
+		MediaModule.runJob("REMOVE_IMPORT_JOBS", { jobIds }, this)
+			.then(() => {
+				this.log("SUCCESS", "MEDIA_REMOVE_IMPORT_JOBS", `Removing import jobs was successful.`);
+
+				return cb({ status: "success", message: "Successfully removed import jobs" });
+			})
+			.catch(async err => {
+				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+				this.log("ERROR", "MEDIA_REMOVE_IMPORT_JOBS", `Removing import jobs failed. "${err}"`);
+				return cb({ status: "error", message: err });
+			});
 	})
 };

+ 7 - 1
backend/logic/actions/youtube.js

@@ -10,6 +10,7 @@ const DBModule = moduleManager.modules.db;
 const CacheModule = moduleManager.modules.cache;
 const UtilsModule = moduleManager.modules.utils;
 const YouTubeModule = moduleManager.modules.youtube;
+const MediaModule = moduleManager.modules.media;
 
 export default {
 	/**
@@ -461,7 +462,11 @@ export default {
 							}
 						},
 						err => {
-							next(err, importJob, response);
+							if (err) next(err, importJob);
+							else
+								MediaModule.runJob("UPDATE_IMPORT_JOBS", { jobIds: importJob._id })
+									.then(() => next(null, importJob, response))
+									.catch(error => next(error, importJob));
 						}
 					);
 				}
@@ -475,6 +480,7 @@ export default {
 						`Importing a YouTube playlist to be requested failed for admin "${session.userId}". "${err}"`
 					);
 					importJobModel.updateOne({ _id: importJob._id }, { $set: { status: "error" } });
+					MediaModule.runJob("UPDATE_IMPORT_JOBS", { jobIds: importJob._id });
 					return cb({ status: "error", message: err });
 				}
 

+ 113 - 0
backend/logic/media.js

@@ -7,6 +7,7 @@ let DBModule;
 let UtilsModule;
 let YouTubeModule;
 let SongsModule;
+let WSModule;
 
 class _MediaModule extends CoreClass {
 	// eslint-disable-next-line require-jsdoc
@@ -29,13 +30,35 @@ class _MediaModule extends CoreClass {
 		UtilsModule = this.moduleManager.modules.utils;
 		YouTubeModule = this.moduleManager.modules.youtube;
 		SongsModule = this.moduleManager.modules.songs;
+		WSModule = this.moduleManager.modules.ws;
 
 		this.RatingsModel = await DBModule.runJob("GET_MODEL", { modelName: "ratings" });
 		this.RatingsSchemaCache = await CacheModule.runJob("GET_SCHEMA", { schemaName: "ratings" });
+		this.ImportJobModel = await DBModule.runJob("GET_MODEL", { modelName: "importJob" });
 
 		this.setStage(2);
 
 		return new Promise((resolve, reject) => {
+			CacheModule.runJob("SUB", {
+				channel: "importJob.updated",
+				cb: importJob => {
+					WSModule.runJob("EMIT_TO_ROOM", {
+						room: "admin.import",
+						args: ["event:admin.importJob.updated", { data: { importJob } }]
+					});
+				}
+			});
+
+			CacheModule.runJob("SUB", {
+				channel: "importJob.removed",
+				cb: jobId => {
+					WSModule.runJob("EMIT_TO_ROOM", {
+						room: "admin.import",
+						args: ["event:admin.importJob.removed", { data: { jobId } }]
+					});
+				}
+			});
+
 			async.waterfall(
 				[
 					next => {
@@ -380,6 +403,96 @@ class _MediaModule extends CoreClass {
 			);
 		});
 	}
+
+	/**
+	 * Remove import job by id from Mongo
+	 *
+	 * @param {object} payload - object containing the payload
+	 * @param {string} payload.jobIds - the job ids
+	 * @returns {Promise} - returns a promise (resolve, reject)
+	 */
+	UPDATE_IMPORT_JOBS(payload) {
+		return new Promise((resolve, reject) => {
+			let { jobIds } = payload;
+			if (!Array.isArray(jobIds)) jobIds = [jobIds];
+
+			async.waterfall(
+				[
+					next => {
+						MediaModule.ImportJobModel.find({ _id: { $in: jobIds } }, next);
+					},
+
+					(importJobs, next) => {
+						async.eachLimit(
+							importJobs,
+							1,
+							(importJob, next) => {
+								CacheModule.runJob("PUB", {
+									channel: "importJob.updated",
+									value: importJob
+								})
+									.then(() => next())
+									.catch(next);
+							},
+							err => {
+								if (err) next(err);
+								else next(null, importJobs);
+							}
+						);
+					}
+				],
+				(err, importJobs) => {
+					if (err && err !== true) return reject(new Error(err));
+					return resolve({ importJobs });
+				}
+			);
+		});
+	}
+
+	/**
+	 * Remove import job by id from Mongo
+	 *
+	 * @param {object} payload - object containing the payload
+	 * @param {string} payload.jobIds - the job ids
+	 * @returns {Promise} - returns a promise (resolve, reject)
+	 */
+	REMOVE_IMPORT_JOBS(payload) {
+		return new Promise((resolve, reject) => {
+			let { jobIds } = payload;
+			if (!Array.isArray(jobIds)) jobIds = [jobIds];
+
+			async.waterfall(
+				[
+					next => {
+						MediaModule.ImportJobModel.deleteMany({ _id: { $in: jobIds } }, err => {
+							if (err) next(err);
+							else next();
+						});
+					},
+
+					next => {
+						async.eachLimit(
+							jobIds,
+							1,
+							(jobId, next) => {
+								CacheModule.runJob("PUB", {
+									channel: "importJob.removed",
+									value: jobId
+								})
+									.then(() => next())
+									.catch(next);
+							},
+							next
+						);
+					}
+				],
+				err => {
+					if (err && err !== true) return reject(new Error(err));
+					return resolve();
+				}
+			);
+		});
+	}
 }
 
 export default new _MediaModule();

+ 37 - 22
frontend/src/pages/Admin/Songs/Import.vue

@@ -153,7 +153,7 @@
 											message:
 												'Note: Removing an import will not remove any videos or songs.',
 											action: 'removeImportJob',
-											params: slotProps.item
+											params: slotProps.item._id
 										})
 									"
 									:disabled="
@@ -453,7 +453,19 @@ export default {
 						["failed", "Failed"]
 					]
 				}
-			]
+			],
+			events: {
+				adminRoom: "import",
+				updated: {
+					event: "admin.importJob.updated",
+					id: "importJob._id",
+					item: "importJob"
+				},
+				removed: {
+					event: "admin.importJob.removed",
+					id: "jobId"
+				}
+			}
 		};
 	},
 	computed: {
@@ -529,19 +541,11 @@ export default {
 			if (stage === 2) this.createImport.stage = 1;
 		},
 		importFromYoutube() {
-			let isImportingPlaylist = true;
-
 			if (!this.createImport.youtubeUrl)
 				return new Toast("Please enter a YouTube URL.");
 
-			// don't give starting import message instantly in case of instant error
-			setTimeout(() => {
-				if (isImportingPlaylist) {
-					new Toast(
-						"Starting to import your playlist. This can take some time to do."
-					);
-				}
-			}, 750);
+			let id;
+			let title;
 
 			return this.socket.dispatch(
 				"youtube.requestSetAdmin",
@@ -549,15 +553,20 @@ export default {
 				this.createImport.isImportingOnlyMusic,
 				true,
 				{
-					cb: res => {
-						isImportingPlaylist = false;
-
-						return new Toast({
-							content: res.message,
-							timeout: 20000
-						});
-					},
-					onProgress: console.log
+					cb: () => {},
+					onProgress: res => {
+						if (res.status === "started") {
+							id = res.id;
+							title = res.title;
+						}
+
+						if (id)
+							this.setJob({
+								id,
+								name: title,
+								...res
+							});
+					}
 				}
 			);
 		},
@@ -576,6 +585,11 @@ export default {
 				this.openModal({ modal: "editSong", data: { song: songs[0] } });
 			else this.openModal({ modal: "editSongs", data: { songs } });
 		},
+		removeImportJob(jobId) {
+			this.socket.dispatch("media.removeImportJobs", jobId, res => {
+				new Toast(res.message);
+			});
+		},
 		confirmAction({ message, action, params }) {
 			this.openModal({
 				modal: "confirm",
@@ -593,7 +607,8 @@ export default {
 				else this[action]();
 			}
 		},
-		...mapActions("modalVisibility", ["openModal"])
+		...mapActions("modalVisibility", ["openModal"]),
+		...mapActions("longJobs", ["setJob"])
 	}
 };
 </script>