Sfoglia il codice sorgente

refactor: Verified parameter as a boolean and hidden song as a tag migration

Owen Diffey 2 anni fa
parent
commit
79eeeb40e0

+ 0 - 2
.wiki/Configuration.md

@@ -12,8 +12,6 @@ Location: `backend/config/default.json`
 | `serverDomain` | Should be the url where the backend will be accessible from, usually `http://localhost/backend` for docker or `http://localhost:8080` for non-Docker. |
 | `serverPort` | Should be the port where the backend will listen on, should always be `8080` for Docker, and is recommended for non-Docker. |
 | `registrationDisabled` | If set to true, users can't register accounts. |
-| `hideAutomaticallyRequestedSongs` | If `true` any automatically requested songs will be hidden. |
-| `hideAnonymousSongs` | If `true` any anonymously requested songs will be hidden. |
 | `sendDataRequestEmails` | If `true` all admin users will be sent an email if a data request is received. |
 | `apis.youtube.key` | YouTube Data API v3 key, obtained from [here](https://developers.google.com/youtube/v3/getting-started). |
 | `apis.youtube.rateLimit` | Minimum interval between YouTube API requests in milliseconds. |

+ 1 - 3
backend/config/template.json

@@ -7,8 +7,6 @@
 	"serverDomain": "http://localhost/backend",
 	"serverPort": 8080,
 	"registrationDisabled": true,
-	"hideAutomaticallyRequestedSongs": false,
-	"hideAnonymousSongs": false,
 	"sendDataRequestEmails": true,
 	"apis": {
 		"youtube": {
@@ -95,5 +93,5 @@
 			]
 		}
 	},
-	"configVersion": 8
+	"configVersion": 9
 }

+ 1 - 1
backend/index.js

@@ -6,7 +6,7 @@ import fs from "fs";
 
 import package_json from "./package.json";
 
-const REQUIRED_CONFIG_VERSION = 8;
+const REQUIRED_CONFIG_VERSION = 9;
 
 // eslint-disable-next-line
 Array.prototype.remove = function (item) {

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

@@ -184,9 +184,7 @@ export default {
 	 */
 	joinAdminRoom: isAdminRequired((session, page, cb) => {
 		if (
-			page === "unverifiedSongs" ||
 			page === "songs" ||
-			page === "hiddenSongs" ||
 			page === "stations" ||
 			page === "reports" ||
 			page === "news" ||

+ 6 - 56
backend/logic/actions/songs.js

@@ -684,56 +684,6 @@ export default {
 			});
 	}),
 
-	/**
-	 * Hides a song
-	 *
-	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the song id of the song that gets hidden
-	 * @param {Function} cb - gets called with the result
-	 */
-	hide: isLoginRequired(async function add(session, songId, cb) {
-		SongsModule.runJob("HIDE_SONG", { songId }, this)
-			.then(() => {
-				this.log("SUCCESS", "SONGS_HIDE", `User "${session.userId}" successfully hid song "${songId}".`);
-				return cb({
-					status: "success",
-					message: "Successfully hid that song"
-				});
-			})
-			.catch(async err => {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
-				this.log("ERROR", "SONGS_HIDE", `Hiding song "${songId}" failed for user ${session.userId}. "${err}"`);
-				return cb({ status: "error", message: err });
-			});
-	}),
-
-	/**
-	 * Unhides a song
-	 *
-	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the song id of the song that gets hidden
-	 * @param {Function} cb - gets called with the result
-	 */
-	unhide: isLoginRequired(async function add(session, songId, cb) {
-		SongsModule.runJob("UNHIDE_SONG", { songId }, this)
-			.then(() => {
-				this.log("SUCCESS", "SONGS_UNHIDE", `User "${session.userId}" successfully unhid song "${songId}".`);
-				return cb({
-					status: "success",
-					message: "Successfully unhid that song"
-				});
-			})
-			.catch(async err => {
-				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
-				this.log(
-					"ERROR",
-					"SONGS_UNHIDE",
-					`Unhiding song "${songId}" failed for user ${session.userId}. "${err}"`
-				);
-				return cb({ status: "error", message: err });
-			});
-	}),
-
 	/**
 	 * Verifies a song
 	 *
@@ -755,11 +705,11 @@ export default {
 				},
 
 				(song, next) => {
-					const oldStatus = song.status;
+					const oldStatus = false;
 
 					song.verifiedBy = session.userId;
 					song.verifiedAt = Date.now();
-					song.status = "verified";
+					song.verified = true;
 
 					song.save(err => next(err, song, oldStatus));
 				},
@@ -886,7 +836,7 @@ export default {
 				},
 
 				(song, next) => {
-					song.status = "unverified";
+					song.verified = false;
 					song.save(err => {
 						next(err, song);
 					});
@@ -899,7 +849,7 @@ export default {
 							.catch(() => {});
 					});
 
-					SongsModule.runJob("UPDATE_SONG", { songId, oldStatus: "verified" });
+					SongsModule.runJob("UPDATE_SONG", { songId, oldStatus: true });
 
 					next(null);
 				}
@@ -1778,7 +1728,7 @@ export default {
 	 * @param session
 	 * @param cb
 	 */
-	 getTags: isAdminRequired(function getModule(session, cb) {
+	getTags: isAdminRequired(function getModule(session, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -1806,5 +1756,5 @@ export default {
 				}
 			}
 		);
-	}),
+	})
 };

+ 7 - 9
backend/logic/db/index.js

@@ -8,12 +8,12 @@ import CoreClass from "../../core";
 const REQUIRED_DOCUMENT_VERSIONS = {
 	activity: 2,
 	news: 2,
-	playlist: 5,
+	playlist: 6,
 	punishment: 1,
 	queueSong: 1,
 	report: 5,
-	song: 6,
-	station: 6,
+	song: 7,
+	station: 7,
 	user: 3
 };
 
@@ -199,12 +199,10 @@ class _DBModule extends CoreClass {
 					};
 					this.schemas.song.path("genres").validate(songGenres, "Invalid genres.");
 
-					const songTags = tags => {
-						return (
-							tags.filter(tag => (new RegExp(/^[a-zA-Z0-9_]{1,64}$|^[a-zA-Z0-9_]{1,64}\[[a-zA-Z0-9_]{1,64}\]$/)).test(tag)).length ===
-							tags.length
-						);
-					};
+					const songTags = tags =>
+						tags.filter(tag =>
+							new RegExp(/^[a-zA-Z0-9_]{1,64}$|^[a-zA-Z0-9_]{1,64}\[[a-zA-Z0-9_]{1,64}\]$/).test(tag)
+						).length === tags.length;
 					this.schemas.song.path("tags").validate(songTags, "Invalid tags.");
 
 					const songThumbnail = thumbnail => {

+ 1 - 1
backend/logic/db/schemas/playlist.js

@@ -18,5 +18,5 @@ export default {
 	createdFor: { type: String },
 	privacy: { type: String, enum: ["public", "private"], default: "private" },
 	type: { type: String, enum: ["user", "user-liked", "user-disliked", "genre", "station"], required: true },
-	documentVersion: { type: Number, default: 5, required: true }
+	documentVersion: { type: Number, default: 6, required: true }
 };

+ 2 - 2
backend/logic/db/schemas/song.js

@@ -12,9 +12,9 @@ export default {
 	explicit: { type: Boolean },
 	requestedBy: { type: String },
 	requestedAt: { type: Date },
+	verified: { type: Boolean, default: false },
 	verifiedBy: { type: String },
 	verifiedAt: { type: Date },
 	discogs: { type: Object },
-	status: { type: String, required: true, default: "hidden", enum: ["hidden", "unverified", "verified"] },
-	documentVersion: { type: Number, default: 6, required: true }
+	documentVersion: { type: Number, default: 7, required: true }
 };

+ 3 - 3
backend/logic/db/schemas/station.js

@@ -17,7 +17,7 @@ export default {
 		skipVotes: [{ type: String }],
 		requestedBy: { type: String },
 		requestedAt: { type: Date },
-		status: { type: String }
+		verified: { type: Boolean }
 	},
 	currentSongIndex: { type: Number, default: 0, required: true },
 	timePaused: { type: Number, default: 0, required: true },
@@ -36,7 +36,7 @@ export default {
 			thumbnail: { type: String },
 			requestedBy: { type: String },
 			requestedAt: { type: Date },
-			status: { type: String }
+			verified: { type: Boolean }
 		}
 	],
 	owner: { type: String },
@@ -45,5 +45,5 @@ export default {
 	theme: { type: String, enum: ["blue", "purple", "teal", "orange", "red"], default: "blue" },
 	includedPlaylists: [{ type: String }],
 	excludedPlaylists: [{ type: String }],
-	documentVersion: { type: Number, default: 6, required: true }
+	documentVersion: { type: Number, default: 7, required: true }
 };

+ 1 - 1
backend/logic/migration/migrations/migration17.js

@@ -18,7 +18,7 @@ export default async function migrate(MigrationModule) {
 					this.log("INFO", `Migration 17. Finding songs with document version 5.`);
 					songModel.updateMany(
 						{ documentVersion: 5 },
-						{ $set: { documentVersion: 6, "tags": [] } },
+						{ $set: { documentVersion: 6, tags: [] } },
 						(err, res) => {
 							if (err) next(err);
 							else {

+ 185 - 0
backend/logic/migration/migrations/migration18.js

@@ -0,0 +1,185 @@
+import async from "async";
+
+/**
+ * Migration 18
+ *
+ * Migration for song status property.
+ *
+ * @param {object} MigrationModule - the MigrationModule
+ * @returns {Promise} - returns promise
+ */
+export default async function migrate(MigrationModule) {
+	const songModel = await MigrationModule.runJob("GET_MODEL", { modelName: "song" }, this);
+	const playlistModel = await MigrationModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
+	const stationModel = await MigrationModule.runJob("GET_MODEL", { modelName: "station" }, this);
+
+	return new Promise((resolve, reject) => {
+		async.waterfall(
+			[
+				next => {
+					this.log("INFO", `Migration 18. Finding hidden songs with document version 6.`);
+					songModel.updateMany(
+						{ documentVersion: 6, status: { $in: ["hidden"] } },
+						{
+							$push: { tags: "hidden" },
+							$set: { documentVersion: 7, verified: false },
+							$unset: { status: "" }
+						},
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 18 (hidden songs). Matched: ${res.matchedCount}, modified: ${res.modifiedCount}, ok: ${res.ok}.`
+								);
+
+								next();
+							}
+						}
+					);
+				},
+
+				next => {
+					this.log("INFO", `Migration 18. Finding unverified songs with document version 6.`);
+					songModel.updateMany(
+						{ documentVersion: 6, status: { $in: ["unverified"] } },
+						{ $set: { documentVersion: 7, verified: false }, $unset: { status: "" } },
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 18 (unverified songs). Matched: ${res.matchedCount}, modified: ${res.modifiedCount}, ok: ${res.ok}.`
+								);
+
+								next();
+							}
+						}
+					);
+				},
+
+				next => {
+					this.log("INFO", `Migration 18. Finding verified songs with document version 6.`);
+					songModel.updateMany(
+						{ documentVersion: 6, status: "verified" },
+						{ $set: { documentVersion: 7, verified: true }, $unset: { status: "" } },
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 18 (verified songs). Matched: ${res.matchedCount}, modified: ${res.modifiedCount}, ok: ${res.ok}.`
+								);
+
+								next();
+							}
+						}
+					);
+				},
+
+				next => {
+					this.log("INFO", `Migration 18. Updating playlist songs and queue songs.`);
+					songModel.find({ documentVersion: 6 }, (err, songs) => {
+						if (err) next(err);
+						else {
+							async.eachLimit(
+								songs.map(song => song._doc),
+								1,
+								(song, next) => {
+									const {
+										_id,
+										youtubeId,
+										title,
+										artists,
+										thumbnail,
+										duration,
+										skipDuration,
+										verified
+									} = song;
+									const trimmedSong = {
+										_id,
+										youtubeId,
+										title,
+										artists,
+										thumbnail,
+										duration,
+										skipDuration,
+										verified
+									};
+									async.waterfall(
+										[
+											next => {
+												playlistModel.updateMany(
+													{ "songs._id": song._id, documentVersion: 5 },
+													{ $set: { "songs.$": trimmedSong } },
+													next
+												);
+											},
+
+											(res, next) => {
+												stationModel.updateMany(
+													{ "queue._id": song._id, documentVersion: 6 },
+													{ $set: { "queue.$": trimmedSong } },
+													next
+												);
+											},
+
+											(res, next) => {
+												stationModel.updateMany(
+													{ "currentSong._id": song._id, documentVersion: 6 },
+													{ $set: { currentSong: null } },
+													next
+												);
+											}
+										],
+										err => {
+											next(err);
+										}
+									);
+								},
+								err => {
+									next(err);
+								}
+							);
+						}
+					});
+				},
+
+				next => {
+					playlistModel.updateMany({ documentVersion: 5 }, { $set: { documentVersion: 6 } }, (err, res) => {
+						if (err) next(err);
+						else {
+							this.log(
+								"INFO",
+								`Migration 18 (playlist). Matched: ${res.matchedCount}, modified: ${res.modifiedCount}, ok: ${res.ok}.`
+							);
+
+							next();
+						}
+					});
+				},
+
+				next => {
+					stationModel.updateMany({ documentVersion: 6 }, { $set: { documentVersion: 7 } }, (err, res) => {
+						if (err) next(err);
+						else {
+							this.log(
+								"INFO",
+								`Migration 18 (station). Matched: ${res.matchedCount}, modified: ${res.modifiedCount}, ok: ${res.ok}.`
+							);
+
+							next();
+						}
+					});
+				}
+			],
+			err => {
+				if (err) {
+					reject(new Error(err));
+				} else {
+					resolve();
+				}
+			}
+		);
+	});
+}

+ 4 - 4
backend/logic/playlists.js

@@ -356,7 +356,7 @@ class _PlaylistsModule extends CoreClass {
 	 */
 	ADD_SONG_TO_PLAYLIST(payload) {
 		return new Promise((resolve, reject) => {
-			const { _id, youtubeId, title, artists, thumbnail, duration, status } = payload.song;
+			const { _id, youtubeId, title, artists, thumbnail, duration, verified } = payload.song;
 			const trimmedSong = {
 				_id,
 				youtubeId,
@@ -364,7 +364,7 @@ class _PlaylistsModule extends CoreClass {
 				artists,
 				thumbnail,
 				duration,
-				status
+				verified
 			};
 
 			PlaylistsModule.playlistModel.updateOne(
@@ -458,7 +458,7 @@ class _PlaylistsModule extends CoreClass {
 
 					(playlistId, _songs, next) => {
 						const songs = _songs.map(song => {
-							const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
+							const { _id, youtubeId, title, artists, thumbnail, duration, verified } = song;
 							return {
 								_id,
 								youtubeId,
@@ -466,7 +466,7 @@ class _PlaylistsModule extends CoreClass {
 								artists,
 								thumbnail,
 								duration,
-								status
+								verified
 							};
 						});
 

+ 20 - 119
backend/logic/songs.js

@@ -1,5 +1,4 @@
 import async from "async";
-import config from "config";
 import mongoose from "mongoose";
 import CoreClass from "../core";
 
@@ -512,15 +511,8 @@ class _SongsModule extends CoreClass {
 								return next(null, song);
 							});
 						} else {
-							const status =
-								(!payload.userId && config.get("hideAnonymousSongs")) ||
-								(payload.automaticallyRequested && config.get("hideAutomaticallyRequestedSongs"))
-									? "hidden"
-									: "unverified";
-
 							const song = new SongsModule.SongModel({
 								...youtubeSong,
-								status,
 								requestedBy: payload.userId,
 								requestedAt: Date.now()
 							});
@@ -603,7 +595,7 @@ class _SongsModule extends CoreClass {
 					},
 
 					(song, next) => {
-						const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
+						const { _id, youtubeId, title, artists, thumbnail, duration, verified } = song;
 						const trimmedSong = {
 							_id,
 							youtubeId,
@@ -611,7 +603,7 @@ class _SongsModule extends CoreClass {
 							artists,
 							thumbnail,
 							duration,
-							status
+							verified
 						};
 						this.log("INFO", `Going to update playlists now for song ${_id}`);
 						DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this)
@@ -659,7 +651,7 @@ class _SongsModule extends CoreClass {
 					},
 
 					(song, next) => {
-						const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
+						const { _id, youtubeId, title, artists, thumbnail, duration, verified } = song;
 						this.log("INFO", `Going to update stations now for song ${_id}`);
 						DBModule.runJob("GET_MODEL", { modelName: "station" }, this)
 							.then(stationModel => {
@@ -672,7 +664,7 @@ class _SongsModule extends CoreClass {
 											"queue.$.artists": artists,
 											"queue.$.thumbnail": thumbnail,
 											"queue.$.duration": duration,
-											"queue.$.status": status
+											"queue.$.verified": verified
 										}
 									},
 									err => {
@@ -874,7 +866,6 @@ class _SongsModule extends CoreClass {
 	 *
 	 * @param {object} payload - object that contains the payload
 	 * @param {string} payload.query - the query
-	 * @param {string} payload.includeHidden - include hidden songs
 	 * @param {string} payload.includeUnverified - include unverified songs
 	 * @param {string} payload.includeVerified - include verified songs
 	 * @param {string} payload.trimmed - include trimmed songs
@@ -886,11 +877,10 @@ class _SongsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						const statuses = [];
-						if (payload.includeHidden) statuses.push("hidden");
-						if (payload.includeUnverified) statuses.push("unverified");
-						if (payload.includeVerified) statuses.push("verified");
-						if (statuses.length === 0) return next("No statuses have been included.");
+						const isVerified = [];
+						if (payload.includeUnverified) isVerified.push(false);
+						if (payload.includeVerified) isVerified.push(true);
+						if (isVerified.length === 0) return next("No verified status has been included.");
 
 						let { query } = payload;
 
@@ -902,11 +892,11 @@ class _SongsModule extends CoreClass {
 						const filterArray = [
 							{
 								title: new RegExp(`${query}`, "i"),
-								status: { $in: statuses }
+								verified: { $in: isVerified }
 							},
 							{
 								artists: new RegExp(`${query}`, "i"),
-								status: { $in: statuses }
+								verified: { $in: isVerified }
 							}
 						];
 
@@ -945,7 +935,7 @@ class _SongsModule extends CoreClass {
 						else if (payload.trimmed) {
 							next(null, {
 								songs: data.songs.map(song => {
-									const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
+									const { _id, youtubeId, title, artists, thumbnail, duration, verified } = song;
 									return {
 										_id,
 										youtubeId,
@@ -953,7 +943,7 @@ class _SongsModule extends CoreClass {
 										artists,
 										thumbnail,
 										duration,
-										status
+										verified
 									};
 								}),
 								...data
@@ -1074,7 +1064,7 @@ class _SongsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						SongsModule.SongModel.find({ status: "verified" }, { genres: 1, _id: false }, next);
+						SongsModule.SongModel.find({ verified: true }, { genres: 1, _id: false }, next);
 					},
 
 					(songs, next) => {
@@ -1113,7 +1103,7 @@ class _SongsModule extends CoreClass {
 					next => {
 						SongsModule.SongModel.find(
 							{
-								status: "verified",
+								verified: true,
 								genres: { $regex: new RegExp(`^${payload.genre.toLowerCase()}$`, "i") }
 							},
 							next
@@ -1204,9 +1194,6 @@ class _SongsModule extends CoreClass {
 						if (song) return next("This song is already in the database.", song);
 						// TODO Add err object as first param of callback
 
-						const requestedBy = user.preferences.anonymousSongRequests ? null : userId;
-						const status = !requestedBy && config.get("hideAnonymousSongs") ? "hidden" : "unverified";
-
 						return YouTubeModule.runJob("GET_SONG", { youtubeId }, this)
 							.then(response => {
 								const { song } = response;
@@ -1216,7 +1203,7 @@ class _SongsModule extends CoreClass {
 								song.explicit = false;
 								song.requestedBy = user.preferences.anonymousSongRequests ? null : userId;
 								song.requestedAt = requestedAt;
-								song.status = status;
+								song.verified = false;
 								next(null, song);
 							})
 							.catch(next);
@@ -1249,7 +1236,7 @@ class _SongsModule extends CoreClass {
 				async (err, song) => {
 					if (err && err !== "This song is already in the database.") return reject(err);
 
-					const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
+					const { _id, youtubeId, title, artists, thumbnail, duration, verified } = song;
 					const trimmedSong = {
 						_id,
 						youtubeId,
@@ -1257,7 +1244,7 @@ class _SongsModule extends CoreClass {
 						artists,
 						thumbnail,
 						duration,
-						status
+						verified
 					};
 
 					if (err && err === "This song is already in the database.")
@@ -1271,92 +1258,6 @@ class _SongsModule extends CoreClass {
 		});
 	}
 
-	/**
-	 * Hides a song
-	 *
-	 * @param {object} payload - The payload
-	 * @param {string} payload.songId - The song id of the song
-	 * @returns {Promise} - returns promise (reject, resolve)
-	 */
-	HIDE_SONG(payload) {
-		return new Promise((resolve, reject) => {
-			const { songId } = payload;
-
-			async.waterfall(
-				[
-					next => {
-						SongsModule.SongModel.findOne({ _id: songId }, next);
-					},
-
-					// Get YouTube data from id
-					(song, next) => {
-						if (!song) return next("This song does not exist.");
-						if (song.status === "hidden") return next("This song is already hidden.");
-						// TODO Add err object as first param of callback
-						return next(null, song.status);
-					},
-
-					(oldStatus, next) => {
-						SongsModule.SongModel.updateOne({ _id: songId }, { status: "hidden" }, res =>
-							next(null, res, oldStatus)
-						);
-					},
-
-					(res, oldStatus, next) => {
-						SongsModule.runJob("UPDATE_SONG", { songId, oldStatus });
-						next();
-					}
-				],
-				async err => {
-					if (err) reject(err);
-					resolve();
-				}
-			);
-		});
-	}
-
-	/**
-	 * Unhides a song
-	 *
-	 * @param {object} payload - The payload
-	 * @param {string} payload.songId - The song id of the song
-	 * @returns {Promise} - returns promise (reject, resolve)
-	 */
-	UNHIDE_SONG(payload) {
-		return new Promise((resolve, reject) => {
-			const { songId } = payload;
-
-			async.waterfall(
-				[
-					next => {
-						SongsModule.SongModel.findOne({ _id: songId }, next);
-					},
-
-					// Get YouTube data from id
-					(song, next) => {
-						if (!song) return next("This song does not exist.");
-						if (song.status !== "hidden") return next("This song is not hidden.");
-						// TODO Add err object as first param of callback
-						return next();
-					},
-
-					next => {
-						SongsModule.SongModel.updateOne({ _id: songId }, { status: "unverified" }, next);
-					},
-
-					(res, next) => {
-						SongsModule.runJob("UPDATE_SONG", { songId, oldStatus: "hidden" });
-						next();
-					}
-				],
-				async err => {
-					if (err) reject(err);
-					resolve();
-				}
-			);
-		});
-	}
-
 	// runjob songs REQUEST_ORPHANED_PLAYLIST_SONGS {}
 
 	/**
@@ -1403,7 +1304,7 @@ class _SongsModule extends CoreClass {
 										},
 
 										(song, next) => {
-											const { _id, title, artists, thumbnail, duration, status } = song;
+											const { _id, title, artists, thumbnail, duration, verified } = song;
 											const trimmedSong = {
 												_id,
 												youtubeId,
@@ -1411,7 +1312,7 @@ class _SongsModule extends CoreClass {
 												artists,
 												thumbnail,
 												duration,
-												status
+												verified
 											};
 											playlistModel.updateMany(
 												{ "songs.youtubeId": song.youtubeId },
@@ -1517,7 +1418,7 @@ class _SongsModule extends CoreClass {
 	 *
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
-	 GET_TAGS() {
+	GET_TAGS() {
 		return new Promise((resolve, reject) => {
 			async.waterfall(
 				[

+ 3 - 3
backend/logic/stations.js

@@ -736,7 +736,7 @@ class _StationsModule extends CoreClass {
 								"skipDuration",
 								"artists",
 								"thumbnail",
-								"status"
+								"verified"
 							]
 						})
 							.then(response => {
@@ -835,7 +835,7 @@ class _StationsModule extends CoreClass {
 											requestedBy: queueSong.requestedBy,
 											likes: song.likes,
 											dislikes: song.dislikes,
-											status: song.status
+											verified: song.verified
 										};
 
 										return next(null, newSong);
@@ -1035,7 +1035,7 @@ class _StationsModule extends CoreClass {
 								thumbnail: song.thumbnail,
 								requestedAt: song.requestedAt,
 								requestedBy: song.requestedBy,
-								status: song.status
+								verified: song.verified
 							};
 						}
 

+ 1 - 1
frontend/src/components/SongItem.vue

@@ -21,7 +21,7 @@
 						{{ song.title }}
 					</h4>
 					<i
-						v-if="song.status === 'verified'"
+						v-if="song.verified"
 						class="material-icons verified-song"
 						content="Verified Song"
 						v-tippy="{ theme: 'info' }"

+ 3 - 25
frontend/src/components/modals/EditSong/index.vue

@@ -497,7 +497,7 @@
 
 					<div class="right">
 						<button
-							v-if="song.status !== 'verified'"
+							v-if="!song.verified"
 							class="button is-success"
 							@click="verify(song._id)"
 							content="Verify Song"
@@ -506,7 +506,7 @@
 							<i class="material-icons">check_circle</i>
 						</button>
 						<quick-confirm
-							v-if="song.status === 'verified'"
+							v-if="song.verified"
 							placement="left"
 							@confirm="unverify(song._id)"
 						>
@@ -518,28 +518,6 @@
 								<i class="material-icons">cancel</i>
 							</button>
 						</quick-confirm>
-						<quick-confirm
-							v-if="song.status !== 'hidden'"
-							placement="left"
-							@confirm="hide(song._id)"
-						>
-							<button
-								class="button is-danger"
-								content="Hide Song"
-								v-tippy
-							>
-								<i class="material-icons">visibility_off</i>
-							</button>
-						</quick-confirm>
-						<button
-							v-if="song.status === 'hidden'"
-							class="button is-success"
-							@click="unhide(song._id)"
-							content="Unhide Song"
-							v-tippy
-						>
-							<i class="material-icons">visibility</i>
-						</button>
 						<button
 							class="
 								button
@@ -737,7 +715,7 @@ export default {
 			"event:admin.song.updated",
 			res => {
 				if (res.data.song._id === this.song._id)
-					this.song.status = res.data.song.status;
+					this.song.verified = res.data.song.verified;
 			},
 			{ modal: "editSong" }
 		);

+ 1 - 3
frontend/src/components/modals/ImportAlbum.vue

@@ -508,9 +508,7 @@ export default {
 				true,
 				res => {
 					this.isImportingPlaylist = false;
-					const songs = res.songs.filter(
-						song => song.status !== "verified"
-					);
+					const songs = res.songs.filter(song => !song.verified);
 					const songsAlreadyVerified =
 						res.songs.length - songs.length;
 					this.setPlaylistSongs(songs);

+ 14 - 18
frontend/src/pages/Admin/tabs/Songs.vue

@@ -42,7 +42,7 @@
 							edit
 						</button>
 						<quick-confirm
-							v-if="slotProps.item.status === 'verified'"
+							v-if="slotProps.item.verified"
 							@confirm="unverifyOne(slotProps.item._id)"
 						>
 							<button
@@ -156,9 +156,9 @@
 						{{ slotProps.item.youtubeId }}
 					</a>
 				</template>
-				<template #column-status="slotProps">
-					<span :title="slotProps.item.status">{{
-						slotProps.item.status
+				<template #column-verified="slotProps">
+					<span :title="slotProps.item.verified">{{
+						slotProps.item.verified
 					}}</span>
 				</template>
 				<template #column-duration="slotProps">
@@ -329,7 +329,7 @@ export default {
 				{
 					name: "options",
 					displayName: "Options",
-					properties: ["_id", "status"],
+					properties: ["_id", "verified"],
 					sortable: false,
 					hidable: false,
 					resizable: false,
@@ -405,10 +405,10 @@ export default {
 					defaultWidth: 120
 				},
 				{
-					name: "status",
-					displayName: "Status",
-					properties: ["status"],
-					sortProperty: "status",
+					name: "verified",
+					displayName: "Verified",
+					properties: ["verified"],
+					sortProperty: "verified",
 					minWidth: 120,
 					defaultWidth: 120
 				},
@@ -553,15 +553,11 @@ export default {
 					defaultFilterType: "datetimeBefore"
 				},
 				{
-					name: "status",
-					displayName: "Status",
-					property: "status",
-					filterTypes: ["exact"],
-					defaultFilterType: "exact",
-					dropdown: [
-						["verified", "Verified"],
-						["unverified", "Unverified"]
-					]
+					name: "verified",
+					displayName: "Verified",
+					property: "verified",
+					filterTypes: ["boolean"],
+					defaultFilterType: "boolean"
 				},
 				{
 					name: "likes",