Browse Source

Added preference to request songs anonymously

Kristian Vos 3 years ago
parent
commit
2246c3001a

+ 20 - 3
backend/logic/actions/playlists.js

@@ -870,13 +870,30 @@ export default {
 									if (song.songId === songId) return next("That song is already in the playlist");
 									return nextSong();
 								},
-								err => next(err, playlist.songs.length + 1)
+								err => next(err)
 							);
 						})
 						.catch(next);
 				},
-				(position, next) => {
-					SongsModule.runJob("ENSURE_SONG_EXISTS_BY_SONG_ID", { songId, userId: session.userId }, this)
+
+				next => {
+					DBModule.runJob("GET_MODEL", { modelName: "user" }, this)
+						.then(UserModel => {
+							UserModel.findOne(
+								{ _id: session.userId },
+								{ "preferences.anonymousSongRequests": 1 },
+								next
+							);
+						})
+						.catch(next);
+				},
+
+				(user, next) => {
+					SongsModule.runJob(
+						"ENSURE_SONG_EXISTS_BY_SONG_ID",
+						{ songId, userId: user.preferences.anonymousSongRequests ? null : session.userId },
+						this
+					)
 						.then(response => {
 							const { song } = response;
 							const { _id, title, thumbnail, duration, status } = song;

+ 17 - 1
backend/logic/actions/stations.js

@@ -2821,7 +2821,23 @@ export default {
 				},
 
 				(station, next) => {
-					SongsModule.runJob("ENSURE_SONG_EXISTS_BY_SONG_ID", { songId, userId: session.userId }, this)
+					DBModule.runJob("GET_MODEL", { modelName: "user" }, this)
+						.then(UserModel => {
+							UserModel.findOne(
+								{ _id: session.userId },
+								{ "preferences.anonymousSongRequests": 1 },
+								(err, user) => next(err, station, user)
+							);
+						})
+						.catch(next);
+				},
+
+				(station, user, next) => {
+					SongsModule.runJob(
+						"ENSURE_SONG_EXISTS_BY_SONG_ID",
+						{ songId, userId: user.preferences.anonymousSongRequests ? null : session.userId },
+						this
+					)
 						.then(response => {
 							const { song } = response;
 							const { _id, title, thumbnail, duration, status } = song;

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

@@ -739,6 +739,7 @@ export default {
 	 * @param {boolean} preferences.nightmode - whether or not the user is using the night mode theme
 	 * @param {boolean} preferences.autoSkipDisliked - whether to automatically skip disliked songs
 	 * @param {boolean} preferences.activityLogPublic - whether or not a user's activity log can be publicly viewed
+	 * @param {boolean} preferences.anonymousSongRequests - whether or not a user's requested songs will be anonymous
 	 * @param {boolean} preferences.activityWatch - whether or not a user is using the ActivityWatch integration
 	 * @param {Function} cb - gets called with the result
 	 */
@@ -756,6 +757,7 @@ export default {
 									nightmode: preferences.nightmode,
 									autoSkipDisliked: preferences.autoSkipDisliked,
 									activityLogPublic: preferences.activityLogPublic,
+									anonymousSongRequests: preferences.anonymousSongRequests,
 									activityWatch: preferences.activityWatch
 								}
 							}

+ 1 - 1
backend/logic/db/index.js

@@ -14,7 +14,7 @@ const REQUIRED_DOCUMENT_VERSIONS = {
 	report: 1,
 	song: 3,
 	station: 4,
-	user: 2
+	user: 3
 };
 
 const regex = {

+ 2 - 1
backend/logic/db/schemas/user.js

@@ -45,7 +45,8 @@ export default {
 		nightmode: { type: Boolean, default: false, required: true },
 		autoSkipDisliked: { type: Boolean, default: true, required: true },
 		activityLogPublic: { type: Boolean, default: false, required: true },
+		anonymousSongRequests: { type: Boolean, default: false, required: true },
 		activityWatch: { type: Boolean, default: false, required: true }
 	},
-	documentVersion: { type: Number, default: 2, required: true }
+	documentVersion: { type: Number, default: 3, required: true }
 };

+ 45 - 0
backend/logic/migration/migrations/migration7.js

@@ -0,0 +1,45 @@
+import async from "async";
+
+/**
+ * Migration 7
+ *
+ * Migration for adding anonymous song requests preference to user object
+ *
+ * @param {object} MigrationModule - the MigrationModule
+ * @returns {Promise} - returns promise
+ */
+export default async function migrate(MigrationModule) {
+	const userModel = await MigrationModule.runJob("GET_MODEL", { modelName: "user" }, this);
+
+	return new Promise((resolve, reject) => {
+		async.waterfall(
+			[
+				next => {
+					this.log("INFO", `Migration 7. Finding users with document version 2.`);
+					userModel.updateMany(
+						{ documentVersion: 2 },
+						{ $set: { documentVersion: 3, "preferences.anonymousSongRequests": false } },
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 7. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+								);
+
+								next();
+							}
+						}
+					);
+				}
+			],
+			err => {
+				if (err) {
+					reject(new Error(err));
+				} else {
+					resolve();
+				}
+			}
+		);
+	});
+}

+ 13 - 4
backend/logic/songs.js

@@ -158,6 +158,7 @@ class _SongsModule extends CoreClass {
 	 *
 	 * @param {object} payload - an object containing the payload
 	 * @param {string} payload.songId - the youtube song id of the song we are trying to ensure is in the songs db
+	 * @param {string} payload.userId - the youtube song id of the song we are trying to ensure is in the songs db
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
 	ENSURE_SONG_EXISTS_BY_SONG_ID(payload) {
@@ -571,11 +572,19 @@ class _SongsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						SongsModule.SongModel.findOne({ songId }, next);
+						DBModule.runJob("GET_MODEL", { modelName: "user" }, this)
+							.then(UserModel => {
+								UserModel.findOne({ _id: userId }, { "preferences.anonymousSongRequests": 1 }, next);
+							})
+							.catch(next);
+					},
+
+					(user, next) => {
+						SongsModule.SongModel.findOne({ songId }, (err, song) => next(err, user, song));
 					},
 
 					// Get YouTube data from id
-					(song, next) => {
+					(user, song, next) => {
 						if (song) return next("This song is already in the database.");
 						// TODO Add err object as first param of callback
 						return YouTubeModule.runJob("GET_SONG", { songId }, this)
@@ -585,7 +594,7 @@ class _SongsModule extends CoreClass {
 								song.genres = [];
 								song.skipDuration = 0;
 								song.explicit = false;
-								song.requestedBy = userId;
+								song.requestedBy = user.preferences.anonymousSongRequests ? null : userId;
 								song.requestedAt = requestedAt;
 								song.status = "unverified";
 								next(null, song);
@@ -620,7 +629,7 @@ class _SongsModule extends CoreClass {
 				async (err, song) => {
 					if (err) reject(err);
 
-					SongsModule.runJob("UPDATE_SONG", { songId });
+					SongsModule.runJob("UPDATE_SONG", { songId: song._id });
 
 					CacheModule.runJob("PUB", {
 						channel: "song.newUnverifiedSong",

+ 4 - 0
frontend/src/App.vue

@@ -140,6 +140,9 @@ export default {
 				this.changeAutoSkipDisliked(res.data.autoSkipDisliked);
 				this.changeNightmode(res.data.nightmode);
 				this.changeActivityLogPublic(res.data.activityLogPublic);
+				this.changeAnonymousSongRequests(
+					res.data.anonymousSongRequests
+				);
 				this.changeActivityWatch(res.data.activityWatch);
 
 				if (this.nightmode) this.enableNightMode();
@@ -170,6 +173,7 @@ export default {
 			"changeNightmode",
 			"changeAutoSkipDisliked",
 			"changeActivityLogPublic",
+			"changeAnonymousSongRequests",
 			"changeActivityWatch"
 		])
 	}

+ 5 - 0
frontend/src/main.js

@@ -216,6 +216,11 @@ lofig.folder = "../config/default.json";
 			preferences.activityLogPublic
 		);
 
+		store.dispatch(
+			"user/preferences/changeAnonymousSongRequests",
+			preferences.anonymousSongRequests
+		);
+
 		store.dispatch(
 			"user/preferences/changeActivityWatch",
 			preferences.activityWatch

+ 21 - 0
frontend/src/pages/Settings/tabs/Preferences.vue

@@ -35,6 +35,17 @@
 				<p>Allow my activity log to be viewed publicly</p>
 			</label>
 		</p>
+		<p class="control is-expanded checkbox-control">
+			<input
+				type="checkbox"
+				id="anonymousSongRequests"
+				v-model="localAnonymousSongRequests"
+			/>
+			<label for="anonymousSongRequests">
+				<span></span>
+				<p>Request songs anonymously</p>
+			</label>
+		</p>
 		<p class="control is-expanded checkbox-control">
 			<input
 				type="checkbox"
@@ -64,6 +75,7 @@ export default {
 			localNightmode: false,
 			localAutoSkipDisliked: false,
 			localActivityLogPublic: false,
+			localAnonymousSongRequests: false,
 			localActivityWatch: false
 		};
 	},
@@ -73,6 +85,8 @@ export default {
 			autoSkipDisliked: state => state.user.preferences.autoSkipDisliked,
 			activityLogPublic: state =>
 				state.user.preferences.activityLogPublic,
+			anonymousSongRequests: state =>
+				state.user.preferences.anonymousSongRequests,
 			activityWatch: state => state.user.preferences.activityWatch
 		}),
 		...mapGetters({
@@ -85,6 +99,8 @@ export default {
 				this.localNightmode = res.data.nightmode;
 				this.localAutoSkipDisliked = res.data.autoSkipDisliked;
 				this.localActivityLogPublic = res.data.activityLogPublic;
+				this.localAnonymousSongRequests =
+					res.data.anonymousSongRequests;
 				this.localActivityWatch = res.data.activityWatch;
 			}
 		});
@@ -93,6 +109,7 @@ export default {
 			this.localNightmode = preferences.nightmode;
 			this.localAutoSkipDisliked = preferences.autoSkipDisliked;
 			this.localActivityLogPublic = preferences.activityLogPublic;
+			this.localAnonymousSongRequests = preferences.anonymousSongRequests;
 			this.localActivityWatch = preferences.activityWatch;
 		});
 	},
@@ -102,6 +119,8 @@ export default {
 				this.localNightmode === this.nightmode &&
 				this.localAutoSkipDisliked === this.autoSkipDisliked &&
 				this.localActivityLogPublic === this.activityLogPublic &&
+				this.localAnonymousSongRequests ===
+					this.anonymousSongRequests &&
 				this.localActivityWatch === this.activityWatch
 			) {
 				new Toast("Please make a change before saving.");
@@ -117,6 +136,7 @@ export default {
 					nightmode: this.localNightmode,
 					autoSkipDisliked: this.localAutoSkipDisliked,
 					activityLogPublic: this.localActivityLogPublic,
+					anonymousSongRequests: this.localAnonymousSongRequests,
 					activityWatch: this.localActivityWatch
 				},
 				res => {
@@ -136,6 +156,7 @@ export default {
 			"changeNightmode",
 			"changeAutoSkipDisliked",
 			"changeActivityLogPublic",
+			"changeAnonymousSongRequests",
 			"changeActivityWatch"
 		])
 	}

+ 10 - 0
frontend/src/store/modules/user.js

@@ -221,6 +221,7 @@ const modules = {
 			nightmode: false,
 			autoSkipDisliked: true,
 			activityLogPublic: false,
+			anonymousSongRequests: false,
 			activityWatch: false
 		},
 		actions: {
@@ -233,6 +234,12 @@ const modules = {
 			changeActivityLogPublic: ({ commit }, activityLogPublic) => {
 				commit("changeActivityLogPublic", activityLogPublic);
 			},
+			changeAnonymousSongRequests: (
+				{ commit },
+				anonymousSongRequests
+			) => {
+				commit("changeAnonymousSongRequests", anonymousSongRequests);
+			},
 			changeActivityWatch: ({ commit }, activityWatch) => {
 				commit("changeActivityWatch", activityWatch);
 			}
@@ -247,6 +254,9 @@ const modules = {
 			changeActivityLogPublic(state, activityLogPublic) {
 				state.activityLogPublic = activityLogPublic;
 			},
+			changeAnonymousSongRequests(state, anonymousSongRequests) {
+				state.anonymousSongRequests = anonymousSongRequests;
+			},
 			changeActivityWatch(state, activityWatch) {
 				state.activityWatch = activityWatch;
 			}