1
0
Эх сурвалжийг харах

Merge tag 'v3.4.0-rc2' into staging

Owen Diffey 3 жил өмнө
parent
commit
96858eb61a

+ 13 - 0
CHANGELOG.md

@@ -1,5 +1,18 @@
 # Changelog
 
+## [v3.4.0-rc2] - 2022-03-19
+
+### Added
+- feat: Re-added ability to hard stop player in Edit Song
+
+### Changed
+- refactor: Delete user sessions when account is deleted
+
+### Fixed
+- fix: Changing password in Settings does not create success toast
+- fix: Invalid user sessions could sometimes break actions
+- fix: Add To Playlist Dropdown create playlist button not full width
+
 ## [v3.4.0-rc1] - 2022-03-06
 
 ### **Breaking Changes**

+ 43 - 35
backend/logic/actions/playlists.js

@@ -526,25 +526,29 @@ export default {
 					userModel.findById(userId).select({ "preferences.orderOfPlaylists": -1 }).exec(next);
 				},
 
-				({ preferences }, next) => {
-					const { orderOfPlaylists } = preferences;
-
-					const match = {
-						createdBy: userId,
-						type: { $in: ["user", "user-liked", "user-disliked"] }
-					};
-
-					// if a playlist order exists
-					if (orderOfPlaylists > 0) match._id = { $in: orderOfPlaylists };
-
-					playlistModel
-						.aggregate()
-						.match(match)
-						.addFields({
-							weight: { $indexOfArray: [orderOfPlaylists, "$_id"] }
-						})
-						.sort({ weight: 1 })
-						.exec(next);
+				(user, next) => {
+					if (!user) next("User not found");
+					else {
+						const { preferences } = user;
+						const { orderOfPlaylists } = preferences;
+
+						const match = {
+							createdBy: userId,
+							type: { $in: ["user", "user-liked", "user-disliked"] }
+						};
+
+						// if a playlist order exists
+						if (orderOfPlaylists > 0) match._id = { $in: orderOfPlaylists };
+
+						playlistModel
+							.aggregate()
+							.match(match)
+							.addFields({
+								weight: { $indexOfArray: [orderOfPlaylists, "$_id"] }
+							})
+							.sort({ weight: 1 })
+							.exec(next);
+					}
 				},
 
 				(playlists, next) => {
@@ -599,25 +603,29 @@ export default {
 					userModel.findById(session.userId).select({ "preferences.orderOfPlaylists": -1 }).exec(next);
 				},
 
-				({ preferences }, next) => {
-					const { orderOfPlaylists } = preferences;
+				(user, next) => {
+					if (!user) next("User not found");
+					else {
+						const { preferences } = user;
+						const { orderOfPlaylists } = preferences;
 
-					const match = {
-						createdBy: session.userId,
-						type: { $in: ["user", "user-liked", "user-disliked"] }
-					};
+						const match = {
+							createdBy: session.userId,
+							type: { $in: ["user", "user-liked", "user-disliked"] }
+						};
 
-					// if a playlist order exists
-					if (orderOfPlaylists > 0) match._id = { $in: orderOfPlaylists };
+						// if a playlist order exists
+						if (orderOfPlaylists > 0) match._id = { $in: orderOfPlaylists };
 
-					playlistModel
-						.aggregate()
-						.match(match)
-						.addFields({
-							weight: { $indexOfArray: [orderOfPlaylists, "$_id"] }
-						})
-						.sort({ weight: 1 })
-						.exec(next);
+						playlistModel
+							.aggregate()
+							.match(match)
+							.addFields({
+								weight: { $indexOfArray: [orderOfPlaylists, "$_id"] }
+							})
+							.sort({ weight: 1 })
+							.exec(next);
+					}
 				}
 			],
 			async (err, playlists) => {

+ 10 - 5
backend/logic/actions/stations.js

@@ -66,11 +66,15 @@ CacheModule.runJob("SUB", {
 									this
 								).then(userModel =>
 									userModel.findOne({ _id: session.userId }, (err, user) => {
-										if (user.role === "admin")
+										if (user && user.role === "admin")
 											socket.dispatch("event:station.userCount.updated", {
 												data: { stationId, count }
 											});
-										else if (station.type === "community" && station.owner === session.userId)
+										else if (
+											user &&
+											station.type === "community" &&
+											station.owner === session.userId
+										)
 											socket.dispatch("event:station.userCount.updated", {
 												data: { stationId, count }
 											});
@@ -518,9 +522,9 @@ CacheModule.runJob("SUB", {
 						}).then(session => {
 							if (session) {
 								userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (user.role === "admin")
+									if (user && user.role === "admin")
 										socket.dispatch("event:station.created", { data: { station } });
-									else if (station.type === "community" && station.owner === session.userId)
+									else if (user && station.type === "community" && station.owner === session.userId)
 										socket.dispatch("event:station.created", { data: { station } });
 								});
 							}
@@ -571,7 +575,8 @@ export default {
 					return next(null, { favoriteStations: [] });
 				},
 
-				({ favoriteStations }, next) => {
+				(user, next) => {
+					const favoriteStations = user ? user.favoriteStations : [];
 					CacheModule.runJob("HGETALL", { table: "stations" }, this).then(stations =>
 						next(null, stations, favoriteStations)
 					);

+ 131 - 6
backend/logic/actions/users.js

@@ -387,8 +387,68 @@ export default {
 					userModel.deleteMany({ _id: session.userId }, next);
 				},
 
-				// request data removal for user
+				// session
 				(res, next) => {
+					CacheModule.runJob("PUB", {
+						channel: "user.removeSessions",
+						value: session.userId
+					});
+
+					async.waterfall(
+						[
+							next => {
+								CacheModule.runJob("HGETALL", { table: "sessions" }, this)
+									.then(sessions => {
+										next(null, sessions);
+									})
+									.catch(next);
+							},
+
+							(sessions, next) => {
+								if (!sessions) return next(null, [], {});
+
+								const keys = Object.keys(sessions);
+
+								return next(null, keys, sessions);
+							},
+
+							(keys, sessions, next) => {
+								// temp fix, need to wait properly for the SUB/PUB refactor (on wekan)
+								const { userId } = session;
+								setTimeout(
+									() =>
+										async.each(
+											keys,
+											(sessionId, callback) => {
+												const session = sessions[sessionId];
+
+												if (session && session.userId === userId) {
+													CacheModule.runJob(
+														"HDEL",
+														{
+															table: "sessions",
+															key: sessionId
+														},
+														this
+													)
+														.then(() => callback(null))
+														.catch(callback);
+												} else callback();
+											},
+											err => {
+												next(err);
+											}
+										),
+									50
+								);
+							}
+						],
+						next
+					);
+				},
+
+				// request data removal for user
+				next => {
 					dataRequestModel.create({ userId: session.userId, type: "remove" }, next);
 				},
 
@@ -555,8 +615,68 @@ export default {
 					userModel.deleteMany({ _id: userId }, next);
 				},
 
-				// request data removal for user
+				// session
 				(res, next) => {
+					CacheModule.runJob("PUB", {
+						channel: "user.removeSessions",
+						value: session.userId
+					});
+
+					async.waterfall(
+						[
+							next => {
+								CacheModule.runJob("HGETALL", { table: "sessions" }, this)
+									.then(sessions => {
+										next(null, sessions);
+									})
+									.catch(next);
+							},
+
+							(sessions, next) => {
+								if (!sessions) return next(null, [], {});
+
+								const keys = Object.keys(sessions);
+
+								return next(null, keys, sessions);
+							},
+
+							(keys, sessions, next) => {
+								// temp fix, need to wait properly for the SUB/PUB refactor (on wekan)
+								const { userId } = session;
+								setTimeout(
+									() =>
+										async.each(
+											keys,
+											(sessionId, callback) => {
+												const session = sessions[sessionId];
+
+												if (session && session.userId === userId) {
+													CacheModule.runJob(
+														"HDEL",
+														{
+															table: "sessions",
+															key: sessionId
+														},
+														this
+													)
+														.then(() => callback(null))
+														.catch(callback);
+												} else callback();
+											},
+											err => {
+												next(err);
+											}
+										),
+									50
+								);
+							}
+						],
+						next
+					);
+				},
+
+				// request data removal for user
+				next => {
 					dataRequestModel.create({ userId, type: "remove" }, next);
 				},
 
@@ -1132,7 +1252,7 @@ export default {
 								(sessionId, callback) => {
 									const session = sessions[sessionId];
 
-									if (session.userId === userId) {
+									if (session && session.userId === userId) {
 										// TODO Also maybe add this to this runJob
 										CacheModule.runJob("HDEL", {
 											table: "sessions",
@@ -1140,7 +1260,7 @@ export default {
 										})
 											.then(() => callback(null))
 											.catch(callback);
-									}
+									} else callback();
 								},
 								err => {
 									next(err);
@@ -1403,9 +1523,14 @@ export default {
 			[
 				next => {
 					userModel.findById(session.userId).select({ preferences: -1 }).exec(next);
+				},
+
+				(user, next) => {
+					if (!user) next("User not found");
+					else next(null, user);
 				}
 			],
-			async (err, { preferences }) => {
+			async (err, user) => {
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 
@@ -1427,7 +1552,7 @@ export default {
 				return cb({
 					status: "success",
 					message: "Preferences successfully retrieved",
-					data: { preferences }
+					data: { preferences: user.preferences }
 				});
 			}
 		);

+ 2 - 2
backend/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "musare-backend",
-  "version": "3.4.0-rc1",
+  "version": "3.4.0-rc2",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "musare-backend",
-      "version": "3.4.0-dev",
+      "version": "3.4.0-rc2",
       "license": "GPL-3.0",
       "dependencies": {
         "async": "^3.2.3",

+ 1 - 1
backend/package.json

@@ -1,7 +1,7 @@
 {
   "name": "musare-backend",
   "private": true,
-  "version": "3.4.0-rc1",
+  "version": "3.4.0-rc2",
   "type": "module",
   "description": "An open-source collaborative music listening and catalogue curation application. Currently supporting YouTube based content.",
   "main": "index.js",

+ 1 - 1
frontend/package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "musare-frontend",
-  "version": "3.4.0-rc1",
+  "version": "3.4.0-rc2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {

+ 1 - 1
frontend/package.json

@@ -5,7 +5,7 @@
     "*.vue"
   ],
   "private": true,
-  "version": "3.4.0-rc1",
+  "version": "3.4.0-rc2",
   "description": "An open-source collaborative music listening and catalogue curation application. Currently supporting YouTube based content.",
   "main": "main.js",
   "author": "Musare Team",

+ 1 - 1
frontend/src/App.vue

@@ -1206,7 +1206,7 @@ img {
 
 	#create-playlist {
 		margin: 10px 10px 10px 10px;
-		width: unset;
+		width: calc(100% - 20px);
 	}
 }
 

+ 23 - 2
frontend/src/components/modals/EditSong/index.vue

@@ -79,8 +79,12 @@
 									</button>
 									<button
 										class="button is-danger"
-										@click="settings('stop')"
-										@keyup.enter="settings('stop')"
+										@click.exact="settings('stop')"
+										@click.shift="settings('hardStop')"
+										@keyup.enter.exact="settings('stop')"
+										@keyup.shift.enter="
+											settings('hardStop')
+										"
 										content="Stop Playback"
 										v-tippy
 									>
@@ -837,6 +841,16 @@ export default {
 			}
 		});
 
+		keyboardShortcuts.registerShortcut("editSong.hardStopVideo", {
+			keyCode: 101,
+			ctrl: true,
+			shift: true,
+			preventDefault: true,
+			handler: () => {
+				this.settings("hardStop");
+			}
+		});
+
 		keyboardShortcuts.registerShortcut("editSong.skipToLast10Secs", {
 			keyCode: 102,
 			preventDefault: true,
@@ -951,6 +965,7 @@ export default {
 
 		editSong.pauseResume - Num 5 - Pause/resume song
 		editSong.stopVideo - Ctrl - Num 5 - Stop
+		editSong.hardStopVideo - Shift - Ctrl - Num 5 - Stop
 		editSong.skipToLast10Secs - Num 6 - Skip to last 10 seconds
 
 		editSong.lowerVolumeLarge - Num 2 - Volume down by 10
@@ -983,6 +998,7 @@ export default {
 		const shortcutNames = [
 			"editSong.pauseResume",
 			"editSong.stopVideo",
+			"editSong.hardStopVideo",
 			"editSong.skipToLast10Secs",
 			"editSong.lowerVolumeLarge",
 			"editSong.lowerVolumeSmall",
@@ -1539,6 +1555,10 @@ export default {
 					this.stopVideo();
 					this.pauseVideo(true);
 					break;
+				case "hardStop":
+					this.hardStopVideo();
+					this.pauseVideo(true);
+					break;
 				case "pause":
 					this.pauseVideo(true);
 					break;
@@ -1804,6 +1824,7 @@ export default {
 		}),
 		...mapActions("modals/editSong", [
 			"stopVideo",
+			"hardStopVideo",
 			"loadVideoById",
 			"pauseVideo",
 			"getCurrentTime",

+ 1 - 1
frontend/src/pages/Settings/Tabs/Security.vue

@@ -254,7 +254,7 @@ export default {
 				res => {
 					if (res.status !== "success") new Toast(res.message);
 					else {
-						this.validation.prevPassword.value = "";
+						this.validation.oldPassword.value = "";
 						this.validation.newPassword.value = "";
 
 						new Toast("Successfully changed password.");

+ 6 - 0
frontend/src/store/modules/modals/editSong.js

@@ -27,6 +27,7 @@ export default {
 			commit("updateOriginalSong", song),
 		resetSong: ({ commit }, songId) => commit("resetSong", songId),
 		stopVideo: ({ commit }) => commit("stopVideo"),
+		hardStopVideo: ({ commit }) => commit("hardStopVideo"),
 		loadVideoById: ({ commit }, id, skipDuration) =>
 			commit("loadVideoById", id, skipDuration),
 		pauseVideo: ({ commit }, status) => commit("pauseVideo", status),
@@ -80,6 +81,11 @@ export default {
 				state.video.player.seekTo(0);
 			}
 		},
+		hardStopVideo(state) {
+			if (state.video.player && state.video.player.stopVideo) {
+				state.video.player.stopVideo();
+			}
+		},
 		loadVideoById(state, id, skipDuration) {
 			state.song.duration = -1;
 			state.video.player.loadVideoById(id, skipDuration);