Kaynağa Gözat

Merge branch 'polishing' into owen-manage-station

Owen Diffey 3 yıl önce
ebeveyn
işleme
db32a2c428
32 değiştirilmiş dosya ile 808 ekleme ve 530 silme
  1. 6 4
      backend/logic/actions/activities.js
  2. 3 3
      backend/logic/actions/news.js
  3. 51 21
      backend/logic/actions/playlists.js
  4. 1 1
      backend/logic/actions/punishments.js
  5. 2 2
      backend/logic/actions/reports.js
  6. 38 37
      backend/logic/actions/songs.js
  7. 48 38
      backend/logic/actions/stations.js
  8. 57 42
      backend/logic/actions/users.js
  9. 12 6
      backend/logic/activities.js
  10. 23 16
      backend/logic/stations.js
  11. 6 6
      backend/logic/ws.js
  12. 2 2
      frontend/src/App.vue
  13. 7 7
      frontend/src/components/AddToPlaylistDropdown.vue
  14. 21 7
      frontend/src/components/Confirm.vue
  15. 4 0
      frontend/src/components/ProfilePicture.vue
  16. 13 13
      frontend/src/components/modals/EditPlaylist.vue
  17. 12 8
      frontend/src/main.js
  18. 6 6
      frontend/src/pages/Admin/tabs/HiddenSongs.vue
  19. 7 5
      frontend/src/pages/Admin/tabs/News.vue
  20. 2 2
      frontend/src/pages/Admin/tabs/Punishments.vue
  21. 4 4
      frontend/src/pages/Admin/tabs/Reports.vue
  22. 4 4
      frontend/src/pages/Admin/tabs/Stations.vue
  23. 6 6
      frontend/src/pages/Admin/tabs/UnverifiedSongs.vue
  24. 6 6
      frontend/src/pages/Admin/tabs/VerifiedSongs.vue
  25. 28 22
      frontend/src/pages/Home.vue
  26. 9 7
      frontend/src/pages/News.vue
  27. 26 29
      frontend/src/pages/Profile/tabs/Playlists.vue
  28. 4 4
      frontend/src/pages/Profile/tabs/RecentActivity.vue
  29. 3 1
      frontend/src/pages/Settings/tabs/Preferences.vue
  30. 16 16
      frontend/src/pages/Station/Sidebar/Playlists.vue
  31. 59 54
      frontend/src/pages/Station/index.vue
  32. 322 151
      frontend/src/pages/Team.vue

+ 6 - 4
backend/logic/actions/activities.js

@@ -26,13 +26,15 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "activity.hide",
 	cb: res => {
-		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets =>
-			sockets.forEach(socket => socket.dispatch("event:activity.hide", res.activityId))
+		const { activityId, userId } = res;
+
+		WSModule.runJob("SOCKETS_FROM_USER", { userId }, this).then(sockets =>
+			sockets.forEach(socket => socket.dispatch("event:activity.hide", { data: { activityId } }))
 		);
 
 		WSModule.runJob("EMIT_TO_ROOM", {
-			room: `profile-${res.userId}-activities`,
-			args: ["event:activity.hide", res.activityId]
+			room: `profile-${userId}-activities`,
+			args: ["event:activity.hide", { data: { activityId } }]
 		});
 	}
 });

+ 3 - 3
backend/logic/actions/news.js

@@ -14,7 +14,7 @@ CacheModule.runJob("SUB", {
 	cb: news => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.news",
-			args: ["event:admin.news.created", news]
+			args: ["event:admin.news.created", { data: { news } }]
 		});
 	}
 });
@@ -24,7 +24,7 @@ CacheModule.runJob("SUB", {
 	cb: news => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.news",
-			args: ["event:admin.news.removed", news]
+			args: ["event:admin.news.removed", { data: { news } }]
 		});
 	}
 });
@@ -34,7 +34,7 @@ CacheModule.runJob("SUB", {
 	cb: news => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.news",
-			args: ["event:admin.news.updated", news]
+			args: ["event:admin.news.updated", { data: { news } }]
 		});
 	}
 });

+ 51 - 21
backend/logic/actions/playlists.js

@@ -18,13 +18,13 @@ CacheModule.runJob("SUB", {
 	channel: "playlist.create",
 	cb: playlist => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: playlist.createdBy }, this).then(sockets => {
-			sockets.forEach(socket => socket.dispatch("event:playlist.create", playlist));
+			sockets.forEach(socket => socket.dispatch("event:playlist.create", { data: { playlist } }));
 		});
 
 		if (playlist.privacy === "public")
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: `profile-${playlist.createdBy}-playlists`,
-				args: ["event:playlist.create", playlist]
+				args: ["event:playlist.create", { data: { playlist } }]
 			});
 	}
 });
@@ -34,13 +34,13 @@ CacheModule.runJob("SUB", {
 	cb: res => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:playlist.delete", res.playlistId);
+				socket.dispatch("event:playlist.delete", { data: { playlistId: res.playlistId } });
 			});
 		});
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `profile-${res.userId}-playlists`,
-			args: ["event:playlist.delete", res.playlistId]
+			args: ["event:playlist.delete", { data: { playlistId: res.playlistId } }]
 		});
 	}
 });
@@ -51,8 +51,10 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets =>
 			sockets.forEach(socket =>
 				socket.dispatch("event:playlist.repositionSongs", {
-					playlistId: res.playlistId,
-					songsBeingChanged: res.songsBeingChanged
+					data: {
+						playlistId: res.playlistId,
+						songsBeingChanged: res.songsBeingChanged
+					}
 				})
 			)
 		);
@@ -65,8 +67,10 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:playlist.addSong", {
-					playlistId: res.playlistId,
-					song: res.song
+					data: {
+						playlistId: res.playlistId,
+						song: res.song
+					}
 				});
 			});
 		});
@@ -77,8 +81,10 @@ CacheModule.runJob("SUB", {
 				args: [
 					"event:playlist.addSong",
 					{
-						playlistId: res.playlistId,
-						song: res.song
+						data: {
+							playlistId: res.playlistId,
+							song: res.song
+						}
 					}
 				]
 			});
@@ -91,8 +97,10 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:playlist.removeSong", {
-					playlistId: res.playlistId,
-					youtubeId: res.youtubeId
+					data: {
+						playlistId: res.playlistId,
+						youtubeId: res.youtubeId
+					}
 				});
 			});
 		});
@@ -103,8 +111,10 @@ CacheModule.runJob("SUB", {
 				args: [
 					"event:playlist.removeSong",
 					{
-						playlistId: res.playlistId,
-						youtubeId: res.youtubeId
+						data: {
+							playlistId: res.playlistId,
+							youtubeId: res.youtubeId
+						}
 					}
 				]
 			});
@@ -117,8 +127,10 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:playlist.updateDisplayName", {
-					playlistId: res.playlistId,
-					displayName: res.displayName
+					data: {
+						playlistId: res.playlistId,
+						displayName: res.displayName
+					}
 				});
 			});
 		});
@@ -129,8 +141,10 @@ CacheModule.runJob("SUB", {
 				args: [
 					"event:playlist.updateDisplayName",
 					{
-						playlistId: res.playlistId,
-						displayName: res.displayName
+						data: {
+							playlistId: res.playlistId,
+							displayName: res.displayName
+						}
 					}
 				]
 			});
@@ -143,7 +157,9 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:playlist.updatePrivacy", {
-					playlist: res.playlist
+					data: {
+						playlist: res.playlist
+					}
 				});
 			});
 		});
@@ -151,12 +167,26 @@ CacheModule.runJob("SUB", {
 		if (res.playlist.privacy === "public")
 			return WSModule.runJob("EMIT_TO_ROOM", {
 				room: `profile-${res.userId}-playlists`,
-				args: ["event:playlist.create", res.playlist]
+				args: [
+					"event:playlist.create",
+					{
+						data: {
+							playlist: res.playlist
+						}
+					}
+				]
 			});
 
 		return WSModule.runJob("EMIT_TO_ROOM", {
 			room: `profile-${res.userId}-playlists`,
-			args: ["event:playlist.delete", res.playlist._id]
+			args: [
+				"event:playlist.delete",
+				{
+					data: {
+						playlistId: res.playlist._id
+					}
+				}
+			]
 		});
 	}
 });

+ 1 - 1
backend/logic/actions/punishments.js

@@ -15,7 +15,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.punishments",
-			args: ["event:admin.punishment.added", data.punishment]
+			args: ["event:admin.punishment.added", { data: { punishment: data.punishment } }]
 		});
 
 		WSModule.runJob("SOCKETS_FROM_IP", { ip: data.ip }, this).then(sockets => {

+ 2 - 2
backend/logic/actions/reports.js

@@ -39,7 +39,7 @@ CacheModule.runJob("SUB", {
 	cb: reportId => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.reports",
-			args: ["event:admin.report.resolved", reportId]
+			args: ["event:admin.report.resolved", { data: { reportId } }]
 		});
 	}
 });
@@ -49,7 +49,7 @@ CacheModule.runJob("SUB", {
 	cb: report => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.reports",
-			args: ["event:admin.report.created", report]
+			args: ["event:admin.report.created", { data: { report } }]
 		});
 	}
 });

+ 38 - 37
backend/logic/actions/songs.js

@@ -19,10 +19,11 @@ CacheModule.runJob("SUB", {
 		const songModel = await DBModule.runJob("GET_MODEL", {
 			modelName: "song"
 		});
+
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.unverifiedSongs",
-				args: ["event:admin.unverifiedSong.added", song]
+				args: ["event:admin.unverifiedSong.added", { data: { song } }]
 			});
 		});
 	}
@@ -33,7 +34,7 @@ CacheModule.runJob("SUB", {
 	cb: songId => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.unverifiedSongs",
-			args: ["event:admin.unverifiedSong.removed", songId]
+			args: ["event:admin.unverifiedSong.removed", { data: { songId } }]
 		});
 	}
 });
@@ -48,7 +49,7 @@ CacheModule.runJob("SUB", {
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.unverifiedSongs",
-				args: ["event:admin.unverifiedSong.updated", song]
+				args: ["event:admin.unverifiedSong.updated", { data: { song } }]
 			});
 		});
 	}
@@ -61,7 +62,7 @@ CacheModule.runJob("SUB", {
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.songs",
-				args: ["event:admin.verifiedSong.added", song]
+				args: ["event:admin.verifiedSong.added", { data: { song } }]
 			});
 		});
 	}
@@ -72,7 +73,7 @@ CacheModule.runJob("SUB", {
 	cb: songId => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.songs",
-			args: ["event:admin.verifiedSong.removed", songId]
+			args: ["event:admin.verifiedSong.removed", { data: { songId } }]
 		});
 	}
 });
@@ -84,7 +85,7 @@ CacheModule.runJob("SUB", {
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.songs",
-				args: ["event:admin.verifiedSong.updated", song]
+				args: ["event:admin.verifiedSong.updated", { data: { song } }]
 			});
 		});
 	}
@@ -99,7 +100,7 @@ CacheModule.runJob("SUB", {
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.hiddenSongs",
-				args: ["event:admin.hiddenSong.added", song]
+				args: ["event:admin.hiddenSong.added", { data: { song } }]
 			});
 		});
 	}
@@ -110,7 +111,7 @@ CacheModule.runJob("SUB", {
 	cb: songId => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.hiddenSongs",
-			args: ["event:admin.hiddenSong.removed", songId]
+			args: ["event:admin.hiddenSong.removed", { data: { songId } }]
 		});
 	}
 });
@@ -125,7 +126,7 @@ CacheModule.runJob("SUB", {
 		songModel.findOne({ _id: songId }, (err, song) => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.hiddenSongs",
-				args: ["event:admin.hiddenSong.updated", song]
+				args: ["event:admin.hiddenSong.updated", { data: { song } }]
 			});
 		});
 	}
@@ -135,13 +136,11 @@ CacheModule.runJob("SUB", {
 	channel: "song.like",
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
-			room: `song.${data.songId}`,
+			room: `song.${data.youtubeId}`,
 			args: [
 				"event:song.like",
 				{
-					songId: data.songId,
-					likes: data.likes,
-					dislikes: data.dislikes
+					data: { youtubeId: data.youtubeId, likes: data.likes, dislikes: data.dislikes }
 				}
 			]
 		});
@@ -149,9 +148,11 @@ CacheModule.runJob("SUB", {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:song.newRatings", {
-					songId: data.songId,
-					liked: true,
-					disliked: false
+					data: {
+						youtubeId: data.youtubeId,
+						liked: true,
+						disliked: false
+					}
 				});
 			});
 		});
@@ -162,22 +163,22 @@ CacheModule.runJob("SUB", {
 	channel: "song.dislike",
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
-			room: `song.${data.songId}`,
+			room: `song.${data.youtubeId}`,
 			args: [
 				"event:song.dislike",
 				{
-					songId: data.songId,
-					likes: data.likes,
-					dislikes: data.dislikes
+					data: { youtubeId: data.youtubeId, likes: data.likes, dislikes: data.dislikes }
 				}
 			]
 		});
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:song.newRatings", {
-					songId: data.songId,
-					liked: false,
-					disliked: true
+					data: {
+						youtubeId: data.youtubeId,
+						liked: false,
+						disliked: true
+					}
 				});
 			});
 		});
@@ -188,22 +189,22 @@ CacheModule.runJob("SUB", {
 	channel: "song.unlike",
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
-			room: `song.${data.songId}`,
+			room: `song.${data.youtubeId}`,
 			args: [
 				"event:song.unlike",
 				{
-					songId: data.songId,
-					likes: data.likes,
-					dislikes: data.dislikes
+					data: { youtubeId: data.youtubeId, likes: data.likes, dislikes: data.dislikes }
 				}
 			]
 		});
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:song.newRatings", {
-					songId: data.songId,
-					liked: false,
-					disliked: false
+					data: {
+						youtubeId: data.youtubeId,
+						liked: false,
+						disliked: false
+					}
 				});
 			});
 		});
@@ -214,22 +215,22 @@ CacheModule.runJob("SUB", {
 	channel: "song.undislike",
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
-			room: `song.${data.songId}`,
+			room: `song.${data.youtubeId}`,
 			args: [
 				"event:song.undislike",
 				{
-					songId: data.songId,
-					likes: data.likes,
-					dislikes: data.dislikes
+					data: { youtubeId: data.youtubeId, likes: data.likes, dislikes: data.dislikes }
 				}
 			]
 		});
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
 				socket.dispatch("event:song.newRatings", {
-					songId: data.songId,
-					liked: false,
-					disliked: false
+					data: {
+						youtubeId: data.youtubeId,
+						liked: false,
+						disliked: false
+					}
 				});
 			});
 		});

+ 48 - 38
backend/logic/actions/stations.js

@@ -20,7 +20,7 @@ CacheModule.runJob("SUB", {
 	cb: ({ stationId, usersPerStation }) => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${stationId}`,
-			args: ["event:users.updated", usersPerStation]
+			args: ["event:users.updated", { data: { users: usersPerStation } }]
 		});
 	}
 });
@@ -32,14 +32,14 @@ CacheModule.runJob("SUB", {
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${stationId}`,
-			args: ["event:userCount.updated", count]
+			args: ["event:userCount.updated", { data: { userCount: count } }]
 		});
 
 		StationsModule.runJob("GET_STATION", { stationId }).then(async station => {
 			if (station.privacy === "public")
 				WSModule.runJob("EMIT_TO_ROOM", {
 					room: "home",
-					args: ["event:userCount.updated", stationId, count]
+					args: ["event:userCount.updated", { data: { stationId, userCount: count } }]
 				});
 			else {
 				const sockets = await WSModule.runJob("GET_SOCKETS_FOR_ROOM", {
@@ -65,9 +65,9 @@ CacheModule.runJob("SUB", {
 								).then(userModel =>
 									userModel.findOne({ _id: session.userId }, (err, user) => {
 										if (user.role === "admin")
-											socket.dispatch("event:userCount.updated", stationId, count);
+											socket.dispatch("event:userCount.updated", { data: { stationId, count } });
 										else if (station.type === "community" && station.owner === session.userId)
-											socket.dispatch("event:userCount.updated", stationId, count);
+											socket.dispatch("event:userCount.updated", { data: { stationId, count } });
 									})
 								);
 						});
@@ -83,7 +83,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${data.stationId}`,
-			args: ["event:theme.updated", data.theme]
+			args: ["event:theme.updated", { data: { theme: data.theme } }]
 		});
 	}
 });
@@ -93,7 +93,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${data.stationId}`,
-			args: ["event:queueLockToggled", data.locked]
+			args: ["event:queueLockToggled", { data: { locked: data.locked } }]
 		});
 	}
 });
@@ -103,7 +103,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${data.stationId}`,
-			args: ["event:partyMode.updated", data.partyMode]
+			args: ["event:partyMode.updated", { data: { partyMode: data.partyMode } }]
 		});
 	}
 });
@@ -113,7 +113,7 @@ CacheModule.runJob("SUB", {
 // 	cb: data => {
 // 		WSModule.runJob("EMIT_TO_ROOM", {
 // 			room: `station.${data.stationId}`,
-// 			args: ["event:privatePlaylist.selected", data.playlistId]
+// 			args: ["event:privatePlaylist.selected", {data: {playlistId: data.playlistId}}]
 // 		});
 // 	}
 // });
@@ -134,7 +134,7 @@ CacheModule.runJob("SUB", {
 		StationsModule.runJob("GET_STATION", { stationId }).then(station => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: `station.${stationId}`,
-				args: ["event:stations.pause", { pausedAt: station.pausedAt }]
+				args: ["event:stations.pause", { data: { pausedAt: station.pausedAt } }]
 			});
 
 			StationsModule.runJob("GET_SOCKETS_THAT_CAN_KNOW_ABOUT_STATION", {
@@ -143,7 +143,7 @@ CacheModule.runJob("SUB", {
 			}).then(response => {
 				const { socketsThatCan } = response;
 				socketsThatCan.forEach(socket => {
-					socket.dispatch("event:station.pause", { stationId });
+					socket.dispatch("event:station.pause", { data: { stationId } });
 				});
 			});
 		});
@@ -156,7 +156,7 @@ CacheModule.runJob("SUB", {
 		StationsModule.runJob("GET_STATION", { stationId }).then(station => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: `station.${stationId}`,
-				args: ["event:stations.resume", { timePaused: station.timePaused }]
+				args: ["event:stations.resume", { data: { timePaused: station.timePaused } }]
 			});
 
 			StationsModule.runJob("GET_SOCKETS_THAT_CAN_KNOW_ABOUT_STATION", {
@@ -166,7 +166,7 @@ CacheModule.runJob("SUB", {
 				.then(response => {
 					const { socketsThatCan } = response;
 					socketsThatCan.forEach(socket => {
-						socket.dispatch("event:station.resume", { stationId });
+						socket.dispatch("event:station.resume", { data: { stationId } });
 					});
 				})
 				.catch(console.log);
@@ -185,7 +185,7 @@ CacheModule.runJob("SUB", {
 
 					WSModule.runJob("EMIT_TO_ROOM", {
 						room: "home",
-						args: ["event:stations.created", station]
+						args: ["event:stations.created", { data: { station } }]
 					});
 				} else if (previousPrivacy === "public") {
 					// Station became hidden
@@ -196,10 +196,12 @@ CacheModule.runJob("SUB", {
 					}).then(response => {
 						const { socketsThatCan, socketsThatCannot } = response;
 						socketsThatCan.forEach(socket => {
-							socket.dispatch("event:station.updatePrivacy", { stationId, privacy: station.privacy });
+							socket.dispatch("event:station.updatePrivacy", {
+								data: { stationId, privacy: station.privacy }
+							});
 						});
 						socketsThatCannot.forEach(socket => {
-							socket.dispatch("event:station.removed", { stationId });
+							socket.dispatch("event:station.removed", { data: { stationId } });
 						});
 					});
 				} else {
@@ -211,7 +213,9 @@ CacheModule.runJob("SUB", {
 					}).then(response => {
 						const { socketsThatCan } = response;
 						socketsThatCan.forEach(socket => {
-							socket.dispatch("event:station.updatePrivacy", { stationId, privacy: station.privacy });
+							socket.dispatch("event:station.updatePrivacy", {
+								data: { stationId, privacy: station.privacy }
+							});
 						});
 					});
 				}
@@ -231,13 +235,15 @@ CacheModule.runJob("SUB", {
 				station
 			}).then(response => {
 				const { socketsThatCan } = response;
-				socketsThatCan.forEach(socket => socket.dispatch("event:station.updateName", { stationId, name }));
+				socketsThatCan.forEach(socket =>
+					socket.dispatch("event:station.updateName", { data: { stationId, name } })
+				);
 			})
 		);
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${stationId}`,
-			args: ["event:station.updateName", { stationId, name }]
+			args: ["event:station.updateName", { data: { stationId, name } }]
 		});
 	}
 });
@@ -254,14 +260,14 @@ CacheModule.runJob("SUB", {
 			}).then(response => {
 				const { socketsThatCan } = response;
 				socketsThatCan.forEach(socket =>
-					socket.dispatch("event:station.updateDisplayName", { stationId, displayName })
+					socket.dispatch("event:station.updateDisplayName", { data: { stationId, displayName } })
 				);
 			})
 		);
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${stationId}`,
-			args: ["event:station.updateDisplayName", { stationId, displayName }]
+			args: ["event:station.updateDisplayName", { data: { stationId, displayName } }]
 		});
 	}
 });
@@ -278,34 +284,36 @@ CacheModule.runJob("SUB", {
 			}).then(response => {
 				const { socketsThatCan } = response;
 				socketsThatCan.forEach(socket =>
-					socket.dispatch("event:station.updateDescription", { stationId, description })
+					socket.dispatch("event:station.updateDescription", { data: { stationId, description } })
 				);
 			})
 		);
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${stationId}`,
-			args: ["event:station.updateDescription", { stationId, description }]
+			args: ["event:station.updateDescription", { data: { stationId, description } }]
 		});
 	}
 });
 
 CacheModule.runJob("SUB", {
 	channel: "station.themeUpdate",
-	cb: response => {
-		const { stationId } = response;
+	cb: res => {
+		const { stationId } = res;
+
 		StationsModule.runJob("GET_STATION", { stationId }).then(station => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: `station.${stationId}`,
-				args: ["event:station.themeUpdated", station.theme]
+				args: ["event:station.themeUpdated", { data: { theme: station.theme } }]
 			});
+
 			StationsModule.runJob("GET_SOCKETS_THAT_CAN_KNOW_ABOUT_STATION", {
 				room: `home`,
 				station
-			}).then(response => {
-				const { socketsThatCan } = response;
+			}).then(res => {
+				const { socketsThatCan } = res;
 				socketsThatCan.forEach(socket => {
-					socket.dispatch("event:station.themeUpdated", { stationId, theme: station.theme });
+					socket.dispatch("event:station.themeUpdated", { data: { theme: station.theme } });
 				});
 			});
 		});
@@ -318,7 +326,7 @@ CacheModule.runJob("SUB", {
 		StationsModule.runJob("GET_STATION", { stationId }).then(station => {
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: `station.${stationId}`,
-				args: ["event:queue.update", station.queue]
+				args: ["event:queue.update", { data: { queue: station.queue } }]
 			});
 		});
 	}
@@ -329,7 +337,7 @@ CacheModule.runJob("SUB", {
 	cb: res => {
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `station.${res.stationId}`,
-			args: ["event:queue.repositionSong", res.song]
+			args: ["event:queue.repositionSong", { data: { song: res.song } }]
 		});
 	}
 });
@@ -351,14 +359,15 @@ CacheModule.runJob("SUB", {
 			room: `station.${stationId}`,
 			args: ["event:stations.remove"]
 		});
-		console.log(111, "REMOVED");
+
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `home`,
-			args: ["event:station.removed", { stationId }]
+			args: ["event:station.removed", { data: { stationId } }]
 		});
+
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: "admin.stations",
-			args: ["event:admin.station.removed", stationId]
+			args: ["event:admin.station.removed", { data: { stationId } }]
 		});
 	}
 });
@@ -374,14 +383,14 @@ CacheModule.runJob("SUB", {
 
 			WSModule.runJob("EMIT_TO_ROOM", {
 				room: "admin.stations",
-				args: ["event:admin.station.added", station]
+				args: ["event:admin.station.added", { data: { station } }]
 			}).then(() => {});
 
 			// TODO If community, check if on whitelist
 			if (station.privacy === "public")
 				WSModule.runJob("EMIT_TO_ROOM", {
 					room: "home",
-					args: ["event:stations.created", station]
+					args: ["event:stations.created", { data: { station } }]
 				}).then(() => {});
 			else {
 				const sockets = await WSModule.runJob("GET_SOCKETS_FOR_ROOM", {
@@ -399,9 +408,10 @@ CacheModule.runJob("SUB", {
 						}).then(session => {
 							if (session) {
 								userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (user.role === "admin") socket.dispatch("event:stations.created", station);
+									if (user.role === "admin")
+										socket.dispatch("event:stations.created", { data: { station } });
 									else if (station.type === "community" && station.owner === session.userId)
-										socket.dispatch("event:stations.created", station);
+										socket.dispatch("event:stations.created", { data: { station } });
 								});
 							}
 						});

+ 57 - 42
backend/logic/actions/users.js

@@ -23,7 +23,7 @@ CacheModule.runJob("SUB", {
 	cb: res => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("keep.event:user.preferences.changed", res.preferences);
+				socket.dispatch("keep.event:user.preferences.changed", { data: { preferences: res.preferences } });
 			});
 		});
 	}
@@ -34,7 +34,9 @@ CacheModule.runJob("SUB", {
 	cb: res => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:user.orderOfFavoriteStations.changed", res.favoriteStations);
+				socket.dispatch("event:user.orderOfFavoriteStations.changed", {
+					data: { order: res.favoriteStations }
+				});
 			});
 		});
 	}
@@ -45,13 +47,13 @@ CacheModule.runJob("SUB", {
 	cb: res => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:user.orderOfPlaylists.changed", res.orderOfPlaylists);
+				socket.dispatch("event:user.orderOfPlaylists.changed", { data: { order: res.orderOfPlaylists } });
 			});
 		});
 
 		WSModule.runJob("EMIT_TO_ROOM", {
 			room: `profile-${res.userId}-playlists`,
-			args: ["event:user.orderOfPlaylists.changed", res.orderOfPlaylists]
+			args: ["event:user.orderOfPlaylists.changed", { data: { order: res.orderOfPlaylists } }]
 		});
 	}
 });
@@ -61,7 +63,7 @@ CacheModule.runJob("SUB", {
 	cb: user => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: user._id }).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:user.username.changed", user.username);
+				socket.dispatch("event:user.username.changed", { data: { username: user.username } });
 			});
 		});
 	}
@@ -70,11 +72,9 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.removeSessions",
 	cb: userId => {
-		WSModule.runJob("SOCKETS_FROM_USER_WITHOUT_CACHE", { userId }).then(sockets => {
-			sockets.forEach(socket => {
-				socket.dispatch("keep.event:user.session.removed");
-			});
-		});
+		WSModule.runJob("SOCKETS_FROM_USER", { userId }).then(sockets =>
+			sockets.forEach(socket => socket.dispatch("keep.event:user.session.removed"))
+		);
 	}
 });
 
@@ -127,7 +127,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("keep.event:banned", data.punishment);
+				socket.dispatch("keep.event:banned", { data: { ban: data.punishment } });
 				socket.disconnect(true);
 			});
 		});
@@ -139,7 +139,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:user.favoritedStation", data.stationId);
+				socket.dispatch("event:user.favoritedStation", { data: { stationId: data.stationId } });
 			});
 		});
 	}
@@ -150,7 +150,7 @@ CacheModule.runJob("SUB", {
 	cb: data => {
 		WSModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
 			sockets.forEach(socket => {
-				socket.dispatch("event:user.unfavoritedStation", data.stationId);
+				socket.dispatch("event:user.unfavoritedStation", { data: { stationId: data.stationId } });
 			});
 		});
 	}
@@ -581,23 +581,32 @@ export default {
 				},
 
 				(session, next) => {
-					CacheModule.runJob("HDEL", { table: "sessions", key: session.sessionId }, this)
-						.then(() => next())
-						.catch(next);
+					CacheModule.runJob("PUB", {
+						channel: "user.removeSessions",
+						value: session.userId
+					});
+
+					// temp fix, need to wait properly for the SUB/PUB refactor (on wekan)
+					setTimeout(() => {
+						CacheModule.runJob("HDEL", { table: "sessions", key: session.sessionId }, this)
+							.then(() => next())
+							.catch(next);
+					}, 50);
 				}
 			],
 			async err => {
 				if (err && err !== true) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 					this.log("ERROR", "USER_LOGOUT", `Logout failed. "${err}" `);
-					cb({ status: "error", message: err });
-				} else {
-					this.log("SUCCESS", "USER_LOGOUT", `Logout successful.`);
-					cb({
-						status: "success",
-						message: "Successfully logged out."
-					});
+					return cb({ status: "error", message: err });
 				}
+
+				this.log("SUCCESS", "USER_LOGOUT", `Logout successful.`);
+
+				return cb({
+					status: "success",
+					message: "Successfully logged out."
+				});
 			}
 		);
 	},
@@ -645,25 +654,29 @@ export default {
 						value: userId
 					});
 
-					async.each(
-						keys,
-						(sessionId, callback) => {
-							const session = sessions[sessionId];
-							if (session.userId === userId) {
-								// TODO Also maybe add this to this runJob
-								CacheModule.runJob("HDEL", {
-									channel: "sessions",
-									key: sessionId
-								})
-									.then(() => {
-										callback(null);
-									})
-									.catch(next);
-							}
-						},
-						err => {
-							next(err);
-						}
+					// temp fix, need to wait properly for the SUB/PUB refactor (on wekan)
+					setTimeout(
+						() =>
+							async.each(
+								keys,
+								(sessionId, callback) => {
+									const session = sessions[sessionId];
+
+									if (session.userId === userId) {
+										// TODO Also maybe add this to this runJob
+										CacheModule.runJob("HDEL", {
+											table: "sessions",
+											key: sessionId
+										})
+											.then(() => callback(null))
+											.catch(callback);
+									}
+								},
+								err => {
+									next(err);
+								}
+							),
+						50
 					);
 				}
 			],
@@ -677,7 +690,9 @@ export default {
 					);
 					return cb({ status: "error", message: err });
 				}
+
 				this.log("SUCCESS", "REMOVE_SESSIONS_FOR_USER", `Removed all sessions for user "${userId}".`);
+
 				return cb({
 					status: "success",
 					message: "Successfully removed all sessions."

+ 12 - 6
backend/logic/activities.js

@@ -74,7 +74,9 @@ class _ActivitiesModule extends CoreClass {
 					(activity, next) => {
 						WSModule.runJob("SOCKETS_FROM_USER", { userId: activity.userId }, this)
 							.then(sockets => {
-								sockets.forEach(socket => socket.dispatch("event:activity.create", activity));
+								sockets.forEach(socket =>
+									socket.dispatch("event:activity.create", { data: { activity } })
+								);
 								next(null, activity);
 							})
 							.catch(next);
@@ -83,7 +85,7 @@ class _ActivitiesModule extends CoreClass {
 					(activity, next) => {
 						WSModule.runJob("EMIT_TO_ROOM", {
 							room: `profile-${activity.userId}-activities`,
-							args: ["event:activity.create", activity]
+							args: ["event:activity.create", { data: { activity } }]
 						});
 
 						return next(null, activity);
@@ -228,13 +230,15 @@ class _ActivitiesModule extends CoreClass {
 
 							WSModule.runJob("SOCKETS_FROM_USER", { userId: payload.userId }, this)
 								.then(sockets =>
-									sockets.forEach(socket => socket.dispatch("event:activity.hide", activity._id))
+									sockets.forEach(socket =>
+										socket.dispatch("event:activity.hide", { data: { activityId: activity._id } })
+									)
 								)
 								.catch(next);
 
 							WSModule.runJob("EMIT_TO_ROOM", {
 								room: `profile-${payload.userId}-activities`,
-								args: ["event:activity.hide", activity._id]
+								args: ["event:activity.hide", { data: { activityId: activity._id } }]
 							});
 
 							if (activity.type === payload.type) howManySongs += 1;
@@ -333,13 +337,15 @@ class _ActivitiesModule extends CoreClass {
 
 							WSModule.runJob("SOCKETS_FROM_USER", { userId: payload.userId }, this)
 								.then(sockets =>
-									sockets.forEach(socket => socket.dispatch("event:activity.hide", activity._id))
+									sockets.forEach(socket =>
+										socket.dispatch("event:activity.hide", { data: { activityId: activity._id } })
+									)
 								)
 								.catch(next);
 
 							WSModule.runJob("EMIT_TO_ROOM", {
 								room: `profile-${payload.userId}-activities`,
-								args: ["event:activity.hide", activity._id]
+								args: ["event:activity.hide", { data: { activityId: activity._id } }]
 							});
 						});
 

+ 23 - 16
backend/logic/stations.js

@@ -89,7 +89,7 @@ class _StationsModule extends CoreClass {
 					if (playlistObj) {
 						WSModule.runJob("EMIT_TO_ROOM", {
 							room: `station.${stationId}`,
-							args: ["event:newOfficialPlaylist", playlistObj.songs]
+							args: ["event:newOfficialPlaylist", { data: { playlist: playlistObj.songs } }]
 						});
 					}
 				});
@@ -951,10 +951,12 @@ class _StationsModule extends CoreClass {
 							args: [
 								"event:songs.next",
 								{
-									currentSong: station.currentSong,
-									startedAt: station.startedAt,
-									paused: station.paused,
-									timePaused: 0
+									data: {
+										currentSong: station.currentSong,
+										startedAt: station.startedAt,
+										paused: station.paused,
+										timePaused: 0
+									}
 								}
 							]
 						})
@@ -964,7 +966,10 @@ class _StationsModule extends CoreClass {
 						if (station.privacy === "public") {
 							WSModule.runJob("EMIT_TO_ROOM", {
 								room: "home",
-								args: ["event:station.nextSong", station._id, station.currentSong]
+								args: [
+									"event:station.nextSong",
+									{ data: { stationId: station._id, song: station.currentSong } }
+								]
 							})
 								.then()
 								.catch();
@@ -992,20 +997,22 @@ class _StationsModule extends CoreClass {
 														(err, user) => {
 															if (!err && user) {
 																if (user.role === "admin")
-																	socket.dispatch(
-																		"event:station.nextSong",
-																		station._id,
-																		station.currentSong
-																	);
+																	socket.dispatch("event:station.nextSong", {
+																		data: {
+																			stationId: station._id,
+																			song: station.currentSong
+																		}
+																	});
 																else if (
 																	station.type === "community" &&
 																	station.owner === session.userId
 																)
-																	socket.dispatch(
-																		"event:station.nextSong",
-																		station._id,
-																		station.currentSong
-																	);
+																	socket.dispatch("event:station.nextSong", {
+																		data: {
+																			stationId: station._id,
+																			song: station.currentSong
+																		}
+																	});
 															}
 														}
 													);

+ 6 - 6
backend/logic/ws.js

@@ -515,7 +515,7 @@ class _WSModule extends CoreClass {
 					`A user tried to connect, but is currently banned. IP: ${socket.ip}.${sessionInfo}`
 				);
 
-				socket.dispatch("keep.event:banned", socket.banishment.ban);
+				socket.dispatch("keep.event:banned", { data: { ban: socket.banishment.ban } });
 
 				return socket.close(); // close socket connection
 			}
@@ -544,7 +544,7 @@ class _WSModule extends CoreClass {
 					.then(session => {
 						if (session && session.userId) {
 							WSModule.userModel.findOne({ _id: session.userId }, (err, user) => {
-								if (err || !user) return socket.dispatch("ready", false);
+								if (err || !user) return socket.dispatch("ready", { data: { loggedIn: false } });
 
 								let role = "";
 								let username = "";
@@ -556,12 +556,12 @@ class _WSModule extends CoreClass {
 									userId = session.userId;
 								}
 
-								return socket.dispatch("ready", true, role, username, userId);
+								return socket.dispatch("ready", { data: { loggedIn: true, role, username, userId } });
 							});
-						} else socket.dispatch("ready", false);
+						} else socket.dispatch("ready", { data: { loggedIn: false } });
 					})
-					.catch(() => socket.dispatch("ready", false));
-			} else socket.dispatch("ready", false);
+					.catch(() => socket.dispatch("ready", { data: { loggedIn: false } }));
+			} else socket.dispatch("ready", { data: { loggedIn: false } });
 
 			socket.onmessage = message => {
 				const data = JSON.parse(message.data);

+ 2 - 2
frontend/src/App.vue

@@ -136,9 +136,9 @@ export default {
 		});
 
 		this.socket.dispatch("users.getPreferences", res => {
-			const { preferences } = res.data;
-
 			if (res.status === "success") {
+				const { preferences } = res.data;
+
 				this.changeAutoSkipDisliked(preferences.autoSkipDisliked);
 				this.changeNightmode(preferences.nightmode);
 				this.changeActivityLogPublic(preferences.activityLogPublic);

+ 7 - 7
frontend/src/components/AddToPlaylistDropdown.vue

@@ -77,22 +77,22 @@ export default {
 			}
 		});
 
-		this.socket.on("event:playlist.create", playlist => {
-			this.playlists.push(playlist);
+		this.socket.on("event:playlist.create", res => {
+			this.playlists.push(res.data.playlist);
 		});
 
-		this.socket.on("event:playlist.delete", playlistId => {
+		this.socket.on("event:playlist.delete", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === playlistId) {
+				if (playlist._id === res.data.playlistId) {
 					this.playlists.splice(index, 1);
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.updateDisplayName", data => {
+		this.socket.on("event:playlist.updateDisplayName", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
-					this.playlists[index].displayName = data.displayName;
+				if (playlist._id === res.data.playlistId) {
+					this.playlists[index].displayName = res.data.displayName;
 				}
 			});
 		});

+ 21 - 7
frontend/src/components/Confirm.vue

@@ -5,14 +5,15 @@
 		theme="confirm"
 		ref="confirm"
 		trigger="click"
-		@hide="confirm(false)"
 	>
 		<template #trigger>
 			<div @click.shift.stop="confirm(true)" @click.exact="confirm()">
 				<slot />
 			</div>
 		</template>
-		<a @click.exact="confirm(true)"> Click to Confirm </a>
+		<a @click="confirm(null, $event)">
+			Click to Confirm
+		</a>
 	</tippy>
 </template>
 
@@ -30,15 +31,28 @@ export default {
 		};
 	},
 	methods: {
-		confirm(confirm) {
+		confirm(confirm, event) {
+			if (confirm === null) {
+				/* eslint-disable no-param-reassign */
+				if (
+					event &&
+					event.type === "click" &&
+					!event.altKey &&
+					!event.ctrlKey &&
+					!event.metaKey &&
+					!event.shiftKey
+				)
+					confirm = true;
+				else confirm = false;
+			}
+
 			if (confirm === false) {
 				this.clickedOnce = false;
+				this.$refs.confirm.tip.hide();
 			} else if (confirm === true || this.clickedOnce === true) {
-				this.$emit("confirm");
 				this.clickedOnce = false;
-			} else {
-				this.clickedOnce = true;
-			}
+				this.$emit("confirm");
+			} else this.clickedOnce = true;
 		}
 	}
 };

+ 4 - 0
frontend/src/components/ProfilePicture.vue

@@ -82,6 +82,10 @@ export default {
 			background-color: var(--teal);
 			color: var(--white);
 		}
+		&.grey {
+			background-color: var(--grey);
+			color: var(--white);
+		}
 	}
 }
 </style>

+ 13 - 13
frontend/src/components/modals/EditPlaylist.vue

@@ -442,37 +442,37 @@ export default {
 			} else new Toast(res.message);
 		});
 
-		this.socket.on("event:playlist.addSong", data => {
-			if (this.playlist._id === data.playlistId)
-				this.playlist.songs.push(data.song);
+		this.socket.on("event:playlist.addSong", res => {
+			if (this.playlist._id === res.data.playlistId)
+				this.playlist.songs.push(res.data.song);
 		});
 
-		this.socket.on("event:playlist.removeSong", data => {
-			if (this.playlist._id === data.playlistId) {
+		this.socket.on("event:playlist.removeSong", res => {
+			if (this.playlist._id === res.data.playlistId) {
 				// remove song from array of playlists
 				this.playlist.songs.forEach((song, index) => {
-					if (song.youtubeId === data.youtubeId)
+					if (song.youtubeId === res.data.youtubeId)
 						this.playlist.songs.splice(index, 1);
 				});
 
 				// if this song is in search results, mark it available to add to the playlist again
 				this.search.songs.results.forEach((searchItem, index) => {
-					if (data.youtubeId === searchItem.id) {
+					if (res.data.youtubeId === searchItem.id) {
 						this.search.songs.results[index].isAddedToQueue = false;
 					}
 				});
 			}
 		});
 
-		this.socket.on("event:playlist.updateDisplayName", data => {
-			if (this.playlist._id === data.playlistId)
-				this.playlist.displayName = data.displayName;
+		this.socket.on("event:playlist.updateDisplayName", res => {
+			if (this.playlist._id === res.data.playlistId)
+				this.playlist.displayName = res.data.displayName;
 		});
 
-		this.socket.on("event:playlist.repositionSongs", data => {
-			if (this.playlist._id === data.playlistId) {
+		this.socket.on("event:playlist.repositionSongs", res => {
+			if (this.playlist._id === res.data.playlistId) {
 				// for each song that has a new position
-				data.songsBeingChanged.forEach(changedSong => {
+				res.data.songsBeingChanged.forEach(changedSong => {
 					this.playlist.songs.forEach((song, index) => {
 						// find song locally
 						if (song.youtubeId === changedSong.youtubeId) {

+ 12 - 8
frontend/src/main.js

@@ -183,24 +183,28 @@ lofig.folder = "../config/default.json";
 	const websocketsDomain = await lofig.get("websocketsDomain");
 	ws.init(websocketsDomain);
 
-	ws.socket.on("ready", (loggedIn, role, username, userId) =>
+	ws.socket.on("ready", res => {
+		const { loggedIn, role, username, userId } = res.data;
+
 		store.dispatch("user/auth/authData", {
 			loggedIn,
 			role,
 			username,
 			userId
-		})
-	);
+		});
+	});
 
-	ws.socket.on("keep.event:banned", ban =>
-		store.dispatch("user/auth/banUser", ban)
+	ws.socket.on("keep.event:banned", res =>
+		store.dispatch("user/auth/banUser", res.data.ban)
 	);
 
-	ws.socket.on("event:user.username.changed", username =>
-		store.dispatch("user/auth/updateUsername", username)
+	ws.socket.on("event:user.username.changed", res =>
+		store.dispatch("user/auth/updateUsername", res.data.username)
 	);
 
-	ws.socket.on("keep.event:user.preferences.changed", preferences => {
+	ws.socket.on("keep.event:user.preferences.changed", res => {
+		const { preferences } = res.data;
+
 		store.dispatch(
 			"user/preferences/changeAutoSkipDisliked",
 			preferences.autoSkipDisliked

+ 6 - 6
frontend/src/pages/Admin/tabs/HiddenSongs.vue

@@ -220,16 +220,16 @@ export default {
 		}
 	},
 	mounted() {
-		this.socket.on("event:admin.hiddenSong.added", song => {
-			this.addSong(song);
+		this.socket.on("event:admin.hiddenSong.added", res => {
+			this.addSong(res.data.song);
 		});
 
-		this.socket.on("event:admin.hiddenSong.removed", youtubeId => {
-			this.removeSong(youtubeId);
+		this.socket.on("event:admin.hiddenSong.removed", res => {
+			this.removeSong(res.data.youtubeId);
 		});
 
-		this.socket.on("event:admin.hiddenSong.updated", updatedSong => {
-			this.updateSong(updatedSong);
+		this.socket.on("event:admin.hiddenSong.updated", res => {
+			this.updateSong(res.data.song);
 		});
 
 		if (this.socket.readyState === 1) this.init();

+ 7 - 5
frontend/src/pages/Admin/tabs/News.vue

@@ -254,14 +254,16 @@ export default {
 				res.data.news.forEach(news => this.addNews(news));
 		});
 
-		this.socket.on("event:admin.news.created", news => this.addNews(news));
+		this.socket.on("event:admin.news.created", res =>
+			this.addNews(res.data.news)
+		);
 
-		this.socket.on("event:admin.news.updated", updatedNews =>
-			this.updateNews(updatedNews)
+		this.socket.on("event:admin.news.updated", res =>
+			this.updateNews(res.data.news)
 		);
 
-		this.socket.on("event:admin.news.removed", news =>
-			this.removeNews(news._id)
+		this.socket.on("event:admin.news.removed", res =>
+			this.removeNews(res.data.news._id)
 		);
 
 		if (this.socket.readyState === 1) this.init();

+ 2 - 2
frontend/src/pages/Admin/tabs/Punishments.vue

@@ -128,8 +128,8 @@ export default {
 		if (this.socket.readyState === 1) this.init();
 		ws.onConnect(() => this.init());
 
-		this.socket.on("event:admin.punishment.added", punishment =>
-			this.punishments.push(punishment)
+		this.socket.on("event:admin.punishment.added", res =>
+			this.punishments.push(res.data.punishment)
 		);
 	},
 	methods: {

+ 4 - 4
frontend/src/pages/Admin/tabs/Reports.vue

@@ -101,14 +101,14 @@ export default {
 			if (res.status === "success") this.reports = res.data.reports;
 		});
 
-		this.socket.on("event:admin.report.resolved", reportId => {
+		this.socket.on("event:admin.report.resolved", res => {
 			this.reports = this.reports.filter(report => {
-				return report._id !== reportId;
+				return report._id !== res.data.reportId;
 			});
 		});
 
-		this.socket.on("event:admin.report.created", report =>
-			this.reports.push(report)
+		this.socket.on("event:admin.report.created", res =>
+			this.reports.push(res.data.report)
 		);
 
 		if (this.$route.query.id) {

+ 4 - 4
frontend/src/pages/Admin/tabs/Stations.vue

@@ -233,12 +233,12 @@ export default {
 		if (this.socket.readyState === 1) this.init();
 		ws.onConnect(() => this.init());
 
-		this.socket.on("event:admin.station.added", station =>
-			this.stationAdded(station)
+		this.socket.on("event:admin.station.added", res =>
+			this.stationAdded(res.data.station)
 		);
 
-		this.socket.on("event:admin.station.removed", stationId =>
-			this.stationRemoved(stationId)
+		this.socket.on("event:admin.station.removed", res =>
+			this.stationRemoved(res.data.stationId)
 		);
 	},
 	methods: {

+ 6 - 6
frontend/src/pages/Admin/tabs/UnverifiedSongs.vue

@@ -236,16 +236,16 @@ export default {
 		}
 	},
 	mounted() {
-		this.socket.on("event:admin.unverifiedSong.added", song => {
-			this.addSong(song);
+		this.socket.on("event:admin.unverifiedSong.added", res => {
+			this.addSong(res.data.song);
 		});
 
-		this.socket.on("event:admin.unverifiedSong.removed", youtubeId => {
-			this.removeSong(youtubeId);
+		this.socket.on("event:admin.unverifiedSong.removed", res => {
+			this.removeSong(res.data.youtubeId);
 		});
 
-		this.socket.on("event:admin.unverifiedSong.updated", updatedSong => {
-			this.updateSong(updatedSong);
+		this.socket.on("event:admin.unverifiedSong.updated", res => {
+			this.updateSong(res.data.song);
 		});
 
 		if (this.socket.readyState === 1) this.init();

+ 6 - 6
frontend/src/pages/Admin/tabs/VerifiedSongs.vue

@@ -317,16 +317,16 @@ export default {
 		}
 	},
 	mounted() {
-		this.socket.on("event:admin.verifiedSong.added", song =>
-			this.addSong(song)
+		this.socket.on("event:admin.verifiedSong.added", res =>
+			this.addSong(res.data.song)
 		);
 
-		this.socket.on("event:admin.verifiedSong.removed", youtubeId =>
-			this.removeSong(youtubeId)
+		this.socket.on("event:admin.verifiedSong.removed", res =>
+			this.removeSong(res.data.youtubeId)
 		);
 
-		this.socket.on("event:admin.verifiedSong.updated", updatedSong =>
-			this.updateSong(updatedSong)
+		this.socket.on("event:admin.verifiedSong.updated", res =>
+			this.updateSong(res.data.song)
 		);
 
 		if (this.socket.readyState === 1) this.init();

+ 28 - 22
frontend/src/pages/Home.vue

@@ -538,7 +538,8 @@ export default {
 		ws.onConnect(() => this.init());
 
 		this.socket.on("event:stations.created", res => {
-			const station = res;
+			const station = res.data;
+
 			if (this.stations.find(_station => _station._id === station._id)) {
 				this.stations.forEach(s => {
 					const _station = s;
@@ -558,7 +559,8 @@ export default {
 		});
 
 		this.socket.on("event:station.removed", res => {
-			const { stationId } = res;
+			const { stationId } = res.data;
+
 			const station = this.stations.find(
 				station => station._id === stationId
 			);
@@ -574,44 +576,44 @@ export default {
 			}
 		});
 
-		this.socket.on("event:userCount.updated", (stationId, userCount) => {
+		this.socket.on("event:userCount.updated", res => {
 			const station = this.stations.find(
-				station => station._id === stationId
+				station => station._id === res.data.stationId
 			);
 
-			if (station) station.userCount = userCount;
+			if (station) station.userCount = res.data.userCount;
 		});
 
 		this.socket.on("event:station.updatePrivacy", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
-			if (station) station.privacy = res.privacy;
+			if (station) station.privacy = res.data.privacy;
 		});
 
 		this.socket.on("event:station.updateName", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
-			if (station) station.name = res.name;
+			if (station) station.name = res.data.name;
 		});
 
 		this.socket.on("event:station.updateDisplayName", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
-			if (station) station.displayName = res.displayName;
+			if (station) station.displayName = res.data.displayName;
 		});
 
 		this.socket.on("event:station.updateDescription", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
-			if (station) station.description = res.description;
+			if (station) station.description = res.data.description;
 		});
 
 		this.socket.on("event:station.updateTheme", res => {
@@ -622,13 +624,13 @@ export default {
 			if (station) station.theme = res.theme;
 		});
 
-		this.socket.on("event:station.nextSong", (stationId, song) => {
+		this.socket.on("event:station.nextSong", res => {
 			const station = this.stations.find(
-				station => station._id === stationId
+				station => station._id === res.data.stationId
 			);
 
 			if (station) {
-				let newSong = song;
+				let newSong = res.data.song;
 
 				if (!newSong)
 					newSong = {
@@ -641,7 +643,7 @@ export default {
 
 		this.socket.on("event:station.pause", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
 			if (station) station.paused = true;
@@ -649,13 +651,15 @@ export default {
 
 		this.socket.on("event:station.resume", res => {
 			const station = this.stations.find(
-				station => station._id === res.stationId
+				station => station._id === res.data.stationId
 			);
 
 			if (station) station.paused = false;
 		});
 
-		this.socket.on("event:user.favoritedStation", stationId => {
+		this.socket.on("event:user.favoritedStation", res => {
+			const { stationId } = res.data;
+
 			const station = this.stations.find(
 				station => station._id === stationId
 			);
@@ -666,7 +670,9 @@ export default {
 			}
 		});
 
-		this.socket.on("event:user.unfavoritedStation", stationId => {
+		this.socket.on("event:user.unfavoritedStation", res => {
+			const { stationId } = res.data;
+
 			const station = this.stations.find(
 				station => station._id === stationId
 			);
@@ -679,8 +685,8 @@ export default {
 			}
 		});
 
-		this.socket.on("event:user.orderOfFavoriteStations.changed", order => {
-			this.orderOfFavoriteStations = order;
+		this.socket.on("event:user.orderOfFavoriteStations.changed", res => {
+			this.orderOfFavoriteStations = res.data.order;
 		});
 	},
 	methods: {

+ 9 - 7
frontend/src/pages/News.vue

@@ -107,19 +107,21 @@ export default {
 				if (this.news.length === 0) this.noFound = true;
 			}
 		});
-		this.socket.on("event:admin.news.created", news => {
-			this.news.unshift(news);
+		this.socket.on("event:admin.news.created", res => {
+			this.news.unshift(res.data.news);
 			this.noFound = false;
 		});
-		this.socket.on("event:admin.news.updated", news => {
+		this.socket.on("event:admin.news.updated", res => {
 			for (let n = 0; n < this.news.length; n += 1) {
-				if (this.news[n]._id === news._id) {
-					this.$set(this.news, n, news);
+				if (this.news[n]._id === res.data.news._id) {
+					this.$set(this.news, n, res.data.news);
 				}
 			}
 		});
-		this.socket.on("event:admin.news.removed", news => {
-			this.news = this.news.filter(item => item._id !== news._id);
+		this.socket.on("event:admin.news.removed", res => {
+			this.news = this.news.filter(
+				item => item._id !== res.data.news._id
+			);
 			if (this.news.length === 0) this.noFound = true;
 		});
 	},

+ 26 - 29
frontend/src/pages/Profile/tabs/Playlists.vue

@@ -158,31 +158,31 @@ export default {
 			this.orderOfPlaylists = this.calculatePlaylistOrder(); // order in regards to the database
 		});
 
-		this.socket.on("event:playlist.create", playlist => {
-			this.playlists.push(playlist);
+		this.socket.on("event:playlist.create", res => {
+			this.playlists.push(res.data.playlist);
 		});
 
-		this.socket.on("event:playlist.delete", playlistId => {
+		this.socket.on("event:playlist.delete", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === playlistId) {
+				if (playlist._id === res.data.playlistId) {
 					this.playlists.splice(index, 1);
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.addSong", data => {
+		this.socket.on("event:playlist.addSong", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
-					this.playlists[index].songs.push(data.song);
+				if (playlist._id === res.data.playlistId) {
+					this.playlists[index].songs.push(res.data.song);
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.removeSong", data => {
+		this.socket.on("event:playlist.removeSong", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
+				if (playlist._id === res.data.playlistId) {
 					this.playlists[index].songs.forEach((song, index2) => {
-						if (song.youtubeId === data.youtubeId) {
+						if (song.youtubeId === res.data.youtubeId) {
 							this.playlists[index].songs.splice(index2, 1);
 						}
 					});
@@ -190,37 +190,34 @@ export default {
 			});
 		});
 
-		this.socket.on("event:playlist.updateDisplayName", data => {
+		this.socket.on("event:playlist.updateDisplayName", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
-					this.playlists[index].displayName = data.displayName;
+				if (playlist._id === res.data.playlistId) {
+					this.playlists[index].displayName = res.data.displayName;
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.updatePrivacy", data => {
+		this.socket.on("event:playlist.updatePrivacy", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlist._id) {
-					this.playlists[index].privacy = data.playlist.privacy;
+				if (playlist._id === res.data.playlist._id) {
+					this.playlists[index].privacy = res.data.playlist.privacy;
 				}
 			});
 		});
 
-		this.socket.on(
-			"event:user.orderOfPlaylists.changed",
-			orderOfPlaylists => {
-				const sortedPlaylists = [];
+		this.socket.on("event:user.orderOfPlaylists.changed", res => {
+			const sortedPlaylists = [];
 
-				this.playlists.forEach(playlist => {
-					sortedPlaylists[
-						orderOfPlaylists.indexOf(playlist._id)
-					] = playlist;
-				});
+			this.playlists.forEach(playlist => {
+				sortedPlaylists[
+					res.data.order.indexOf(playlist._id)
+				] = playlist;
+			});
 
-				this.playlists = sortedPlaylists;
-				this.orderOfPlaylists = this.calculatePlaylistOrder();
-			}
-		);
+			this.playlists = sortedPlaylists;
+			this.orderOfPlaylists = this.calculatePlaylistOrder();
+		});
 	},
 	methods: {
 		showPlaylist(playlistId) {

+ 4 - 4
frontend/src/pages/Profile/tabs/RecentActivity.vue

@@ -98,14 +98,14 @@ export default {
 			}
 		});
 
-		this.socket.on("event:activity.create", activity => {
-			this.activities.unshift(activity);
+		this.socket.on("event:activity.create", res => {
+			this.activities.unshift(res.data.activity);
 			this.offsettedFromNextSet += 1;
 		});
 
-		this.socket.on("event:activity.hide", activityId => {
+		this.socket.on("event:activity.hide", res => {
 			this.activities = this.activities.filter(
-				activity => activity._id !== activityId
+				activity => activity._id !== res.data.activityId
 			);
 
 			this.offsettedFromNextSet -= 1;

+ 3 - 1
frontend/src/pages/Settings/tabs/Preferences.vue

@@ -107,7 +107,9 @@ export default {
 			}
 		});
 
-		this.socket.on("keep.event:user.preferences.changed", preferences => {
+		this.socket.on("keep.event:user.preferences.changed", res => {
+			const { preferences } = res.data;
+
 			this.localNightmode = preferences.nightmode;
 			this.localAutoSkipDisliked = preferences.autoSkipDisliked;
 			this.localActivityLogPublic = preferences.activityLogPublic;

+ 16 - 16
frontend/src/pages/Station/Sidebar/Playlists.vue

@@ -108,31 +108,31 @@ export default {
 			this.orderOfPlaylists = this.calculatePlaylistOrder(); // order in regards to the database
 		});
 
-		this.socket.on("event:playlist.create", playlist => {
-			this.playlists.push(playlist);
+		this.socket.on("event:playlist.create", res => {
+			this.playlists.push(res.data.playlist);
 		});
 
-		this.socket.on("event:playlist.delete", playlistId => {
+		this.socket.on("event:playlist.delete", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === playlistId) {
+				if (playlist._id === res.data.playlistId) {
 					this.playlists.splice(index, 1);
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.addSong", data => {
+		this.socket.on("event:playlist.addSong", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
-					this.playlists[index].songs.push(data.song);
+				if (playlist._id === res.data.playlistId) {
+					this.playlists[index].songs.push(res.data.song);
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.removeSong", data => {
+		this.socket.on("event:playlist.removeSong", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
+				if (playlist._id === res.data.playlistId) {
 					this.playlists[index].songs.forEach((song, index2) => {
-						if (song.youtubeId === data.youtubeId) {
+						if (song.youtubeId === res.data.youtubeId) {
 							this.playlists[index].songs.splice(index2, 1);
 						}
 					});
@@ -140,18 +140,18 @@ export default {
 			});
 		});
 
-		this.socket.on("event:playlist.updateDisplayName", data => {
+		this.socket.on("event:playlist.updateDisplayName", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlistId) {
-					this.playlists[index].displayName = data.displayName;
+				if (playlist._id === res.data.playlistId) {
+					this.playlists[index].displayName = res.data.displayName;
 				}
 			});
 		});
 
-		this.socket.on("event:playlist.updatePrivacy", data => {
+		this.socket.on("event:playlist.updatePrivacy", res => {
 			this.playlists.forEach((playlist, index) => {
-				if (playlist._id === data.playlist._id) {
-					this.playlists[index].privacy = data.playlist.privacy;
+				if (playlist._id === res.data.playlist._id) {
+					this.playlists[index].privacy = res.data.playlist.privacy;
 				}
 			});
 		});

+ 59 - 54
frontend/src/pages/Station/index.vue

@@ -796,14 +796,14 @@ export default {
 			}
 		);
 
-		this.socket.on("event:songs.next", data => {
+		this.socket.on("event:songs.next", res => {
 			const previousSong = this.currentSong.youtubeId
 				? this.currentSong
 				: null;
 
 			this.updatePreviousSong(previousSong);
 
-			const { currentSong } = data;
+			const { currentSong } = res.data;
 
 			this.updateCurrentSong(currentSong || {});
 
@@ -815,9 +815,9 @@ export default {
 			}
 			this.updateNextSong(nextSong);
 
-			this.startedAt = data.startedAt;
-			this.updateStationPaused(data.paused);
-			this.timePaused = data.timePaused;
+			this.startedAt = res.data.startedAt;
+			this.updateStationPaused(res.data.paused);
+			this.timePaused = res.data.timePaused;
 
 			if (currentSong) {
 				this.updateNoSong(false);
@@ -827,12 +827,14 @@ export default {
 
 				this.socket.dispatch(
 					"songs.getOwnSongRatings",
-					data.currentSong.youtubeId,
+					currentSong.youtubeId,
 					res => {
 						if (
 							res.status === "success" &&
 							this.currentSong.youtubeId === res.data.youtubeId
 						) {
+							console.log(res);
+
 							this.liked = res.data.liked;
 							this.disliked = res.data.disliked;
 
@@ -892,14 +894,14 @@ export default {
 			// }
 		});
 
-		this.socket.on("event:stations.pause", data => {
-			this.pausedAt = data.pausedAt;
+		this.socket.on("event:stations.pause", res => {
+			this.pausedAt = res.data.pausedAt;
 			this.updateStationPaused(true);
 			this.pauseLocalPlayer();
 		});
 
-		this.socket.on("event:stations.resume", data => {
-			this.timePaused = data.timePaused;
+		this.socket.on("event:stations.resume", res => {
+			this.timePaused = res.data.timePaused;
 			this.updateStationPaused(false);
 			if (!this.localPaused) this.resumeLocalPlayer();
 		});
@@ -909,53 +911,53 @@ export default {
 			return true;
 		});
 
-		this.socket.on("event:song.like", data => {
+		this.socket.on("event:song.like", res => {
 			if (!this.noSong) {
-				if (data.youtubeId === this.currentSong.youtubeId) {
-					this.currentSong.dislikes = data.dislikes;
-					this.currentSong.likes = data.likes;
+				if (res.data.youtubeId === this.currentSong.youtubeId) {
+					this.currentSong.dislikes = res.data.dislikes;
+					this.currentSong.likes = res.data.likes;
 				}
 			}
 		});
 
-		this.socket.on("event:song.dislike", data => {
+		this.socket.on("event:song.dislike", res => {
 			if (!this.noSong) {
-				if (data.youtubeId === this.currentSong.youtubeId) {
-					this.currentSong.dislikes = data.dislikes;
-					this.currentSong.likes = data.likes;
+				if (res.data.youtubeId === this.currentSong.youtubeId) {
+					this.currentSong.dislikes = res.data.dislikes;
+					this.currentSong.likes = res.data.likes;
 				}
 			}
 		});
 
-		this.socket.on("event:song.unlike", data => {
+		this.socket.on("event:song.unlike", res => {
 			if (!this.noSong) {
-				if (data.youtubeId === this.currentSong.youtubeId) {
-					this.currentSong.dislikes = data.dislikes;
-					this.currentSong.likes = data.likes;
+				if (res.data.youtubeId === this.currentSong.youtubeId) {
+					this.currentSong.dislikes = res.data.dislikes;
+					this.currentSong.likes = res.data.likes;
 				}
 			}
 		});
 
-		this.socket.on("event:song.undislike", data => {
+		this.socket.on("event:song.undislike", res => {
 			if (!this.noSong) {
-				if (data.youtubeId === this.currentSong.youtubeId) {
-					this.currentSong.dislikes = data.dislikes;
-					this.currentSong.likes = data.likes;
+				if (res.data.youtubeId === this.currentSong.youtubeId) {
+					this.currentSong.dislikes = res.data.dislikes;
+					this.currentSong.likes = res.data.likes;
 				}
 			}
 		});
 
-		this.socket.on("event:song.newRatings", data => {
+		this.socket.on("event:song.newRatings", res => {
 			if (!this.noSong) {
-				if (data.youtubeId === this.currentSong.youtubeId) {
-					this.liked = data.liked;
-					this.disliked = data.disliked;
+				if (res.data.youtubeId === this.currentSong.youtubeId) {
+					this.liked = res.data.liked;
+					this.disliked = res.data.disliked;
 				}
 			}
 		});
 
-		this.socket.on("event:queue.update", queue => {
-			this.updateSongsList(queue);
+		this.socket.on("event:queue.update", res => {
+			this.updateSongsList(res.data.queue);
 
 			let nextSong = null;
 			if (this.songsList[0])
@@ -966,8 +968,8 @@ export default {
 			this.updateNextSong(nextSong);
 		});
 
-		this.socket.on("event:queue.repositionSong", song => {
-			this.repositionSongInList(song);
+		this.socket.on("event:queue.repositionSong", res => {
+			this.repositionSongInList(res.data.song);
 
 			let nextSong = null;
 			if (this.songsList[0])
@@ -982,9 +984,9 @@ export default {
 			if (this.currentSong) this.currentSong.skipVotes += 1;
 		});
 
-		this.socket.on("event:privatePlaylist.selected", playlistId => {
+		this.socket.on("event:privatePlaylist.selected", res => {
 			if (this.station.type === "community") {
-				this.station.privatePlaylist = playlistId;
+				this.station.privatePlaylist = res.data.playlistId;
 			}
 		});
 
@@ -994,24 +996,25 @@ export default {
 			}
 		});
 
-		this.socket.on("event:partyMode.updated", partyMode => {
+		this.socket.on("event:partyMode.updated", res => {
 			if (this.station.type === "community") {
-				this.station.partyMode = partyMode;
+				this.station.partyMode = res.data.partyMode;
 			}
 		});
 
-		this.socket.on("event:station.themeUpdated", theme => {
+		this.socket.on("event:station.themeUpdated", res => {
+			const { theme } = res.data;
 			this.station.theme = theme;
 			document.body.style.cssText = `--primary-color: var(--${theme})`;
 		});
 
 		this.socket.on("event:station.updateName", res => {
-			this.station.name = res.name;
+			this.station.name = res.data.name;
 			// eslint-disable-next-line no-restricted-globals
 			history.pushState(
 				{},
 				null,
-				`${res.name}?${Object.keys(this.$route.query)
+				`${res.data.name}?${Object.keys(this.$route.query)
 					.map(key => {
 						return `${encodeURIComponent(key)}=${encodeURIComponent(
 							this.$route.query[key]
@@ -1022,35 +1025,37 @@ export default {
 		});
 
 		this.socket.on("event:station.updateDisplayName", res => {
-			this.station.displayName = res.displayName;
+			this.station.displayName = res.data.displayName;
 		});
 
 		this.socket.on("event:station.updateDescription", res => {
-			this.station.description = res.description;
+			this.station.description = res.data.description;
 		});
 
-		// this.socket.on("event:newOfficialPlaylist", playlist => {
+		// this.socket.on("event:newOfficialPlaylist", res => {
 		// 	if (this.station.type === "official")
-		// 		this.updateSongsList(playlist);
+		// 		this.updateSongsList(res.data.playlist);
 		// });
 
-		this.socket.on("event:users.updated", users => this.updateUsers(users));
+		this.socket.on("event:users.updated", res =>
+			this.updateUsers(res.data.users)
+		);
 
-		this.socket.on("event:userCount.updated", userCount =>
-			this.updateUserCount(userCount)
+		this.socket.on("event:userCount.updated", res =>
+			this.updateUserCount(res.data.userCount)
 		);
 
-		this.socket.on("event:queueLockToggled", locked => {
-			this.station.locked = locked;
+		this.socket.on("event:queueLockToggled", res => {
+			this.station.locked = res.data.locked;
 		});
 
-		this.socket.on("event:user.favoritedStation", stationId => {
-			if (stationId === this.station._id)
+		this.socket.on("event:user.favoritedStation", res => {
+			if (res.data.stationId === this.station._id)
 				this.updateIfStationIsFavorited({ isFavorited: true });
 		});
 
-		this.socket.on("event:user.unfavoritedStation", stationId => {
-			if (stationId === this.station._id)
+		this.socket.on("event:user.unfavoritedStation", res => {
+			if (res.data.stationId === this.station._id)
 				this.updateIfStationIsFavorited({ isFavorited: false });
 		});
 

+ 322 - 151
frontend/src/pages/Team.vue

@@ -2,118 +2,117 @@
 	<div class="app">
 		<metadata title="Team" />
 		<main-header />
-		<div class="container">
-			<div class="content-wrapper">
-				<h2 class="has-text-centered page-title">Our Team</h2>
-				<div class="columns">
-					<div
-						class="card column is-6-desktop is-offset-3-desktop is-12-mobile"
-					>
-						<header class="card-header">
-							<p class="card-header-title">Kris</p>
-						</header>
-						<div class="card-content">
-							<div class="content">
-								<span class="role"
-									><span class="custom-tag purple"
-										>Senior Project Manager</span
-									>
-									and
-									<span class="custom-tag blue"
-										>Co-Founder</span
-									></span
-								>
-								<ul>
-									<li>
-										<b>Joined: </b>
-										September 23, 2015
-									</li>
-									<li>
-										<b>Email: </b>
-										<a href="mailto:kris@musare.com"
-											>&#107;&#114;&#105;&#115;&#064;&#109;&#117;&#115;&#097;&#114;&#101;&#046;&#099;&#111;&#109;</a
-										>
-									</li>
-								</ul>
-							</div>
-						</div>
+		<h2 class="has-text-centered">Current Team</h2>
+		<div class="group">
+			<div
+				v-for="(member, index) in currentTeam"
+				:key="index"
+				class="card"
+			>
+				<header class="card-header">
+					<profile-picture
+						:avatar="member.avatar"
+						:name="member.name"
+					/>
+					<div>
+						<strong>{{ member.name }}</strong>
+						<span v-if="member.active"
+							>Active: {{ member.active }}</span
+						>
 					</div>
-				</div>
-				<br />
-				<div class="columns">
-					<div
-						class="card column is-6-desktop is-offset-3-desktop is-12-mobile"
+					<a
+						v-if="member.link"
+						:href="member.link"
+						target="_blank"
+						class="material-icons"
 					>
-						<header class="card-header">
-							<p class="card-header-title">Jonathan</p>
-						</header>
-						<div class="card-content">
-							<div class="content">
-								<span class="role"
-									><span class="custom-tag light-blue"
-										>Lead Developer</span
-									></span
-								>
-								<ul>
-									<li>
-										<b>Joined: </b>
-										August 28, 2016
-									</li>
-									<li>
-										<b>Email: </b>
-										<a href="mailto:jonathan@musare.com"
-											>&#106;&#111;&#110;&#097;&#116;&#104;&#097;&#110;&#064;&#109;&#117;&#115;&#097;&#114;&#101;&#046;&#099;&#111;&#109;</a
-										>
-									</li>
-								</ul>
-							</div>
-						</div>
+						link
+					</a>
+				</header>
+				<div class="card-content">
+					<div v-if="member.bio" class="bio">
+						{{ member.bio }}
+					</div>
+					<div v-if="member.projects" class="projects">
+						<a
+							v-for="(project, index) in member.projects"
+							:key="index"
+							:href="
+								'https://github.com/Musare/' +
+									project +
+									'/commits?author=' +
+									member.github
+							"
+							target="_blank"
+						>
+							{{ project }}
+						</a>
 					</div>
 				</div>
-				<br />
-				<div class="columns">
-					<div
-						class="card column is-6-desktop is-offset-3-desktop is-12-mobile"
+			</div>
+		</div>
+		<h3 class="has-text-centered">Previous Team</h3>
+		<div class="group">
+			<div
+				v-for="(member, index) in previousTeam"
+				:key="index"
+				class="card"
+			>
+				<header class="card-header">
+					<profile-picture
+						:avatar="{ type: 'text', color: 'grey' }"
+						:name="member.name"
+					/>
+					<div>
+						<strong>{{ member.name }}</strong>
+						<span v-if="member.active"
+							>Active: {{ member.active }}</span
+						>
+					</div>
+					<a
+						v-if="member.link"
+						:href="member.link"
+						target="_blank"
+						class="material-icons"
 					>
-						<header class="card-header">
-							<p class="card-header-title">Antonio</p>
-						</header>
-						<div class="card-content">
-							<div class="content">
-								<span class="role"
-									><span class="custom-tag light-green"
-										>Moderator</span
-									></span
-								>
-								<ul>
-									<li>
-										<b>Joined: </b>
-										November 11, 2015
-									</li>
-									<li>
-										<b>Email: </b>
-										<a href="mailto:antonio@musare.com"
-											>&#97;&#110;&#116;&#111;&#110;&#105;&#111;&#64;&#109;&#117;&#115;&#97;&#114;&#101;&#46;&#99;&#111;&#109;</a
-										>
-									</li>
-								</ul>
-							</div>
-						</div>
+						link
+					</a>
+				</header>
+				<div class="card-content">
+					<div v-if="member.bio" class="bio">
+						{{ member.bio }}
+					</div>
+					<div v-if="member.projects" class="projects">
+						<a
+							v-for="(project, index) in member.projects"
+							:key="index"
+							:href="
+								'https://github.com/Musare/' +
+									project +
+									'/commits?author=' +
+									member.github
+							"
+							target="_blank"
+						>
+							{{ project }}
+						</a>
 					</div>
-				</div>
-				<div id="special-thanks">
-					<h4 class="has-text-centered">Special Thanks</h4>
-					<br />
-					<p class="has-text-centered thanks">
-						Special thanks to Owen Diffey, Zachery, Adryd, Cameron
-						Kline, Wesley McCann,
-						<strong>Akira Laine (Co-Founder)</strong>, Johannes
-						Andersen and Aaron Gildea for their contributions to
-						Musare.
-					</p>
 				</div>
 			</div>
 		</div>
+		<div class="other-contributors">
+			<h4>Other Contributors</h4>
+			<div>
+				<a
+					v-for="(member, index) in otherContributors"
+					:key="index"
+					:href="member.link"
+					target="_blank"
+				>
+					{{ member.name }}
+				</a>
+			</div>
+		</div>
 		<main-footer />
 	</div>
 </template>
@@ -121,77 +120,249 @@
 <script>
 import MainHeader from "@/components/layout/MainHeader.vue";
 import MainFooter from "@/components/layout/MainFooter.vue";
+import ProfilePicture from "@/components/ProfilePicture.vue";
 
 export default {
-	components: { MainHeader, MainFooter }
+	components: { MainHeader, MainFooter, ProfilePicture },
+	data() {
+		return {
+			currentTeam: [
+				{
+					name: "Kristian Vos",
+					bio:
+						"Co-Founder, Owner, Lead Developer, System Admin and QA Tester.",
+					projects: [
+						"MusareMeteor",
+						"MusareReact",
+						"MusareNode",
+						"MusareStatus",
+						"MusareTranslation",
+						"aw-watcher-musare",
+						"lofig"
+					],
+					active: "Sept 2015 - present",
+					github: "KrisVos130",
+					link: "https://kvos.dev",
+					avatar: {
+						type: "text",
+						color: "orange"
+					}
+				},
+				{
+					name: "Owen Diffey",
+					bio:
+						"Developer, Designer, System Admin and QA Tester. Previously Owner and Project Manager.",
+					projects: ["MusareMeteor", "MusareReact", "MusareNode"],
+					active: "Feb 2016 - present",
+					github: "odiffey",
+					link: "https://diffey.dev",
+					avatar: {
+						type: "text",
+						color: "purple"
+					}
+				},
+				{
+					name: "Jonathan Graham",
+					bio: "Lead Developer, Designer and QA Tester.",
+					projects: [
+						"MusareMeteor",
+						"MusareReact",
+						"MusareNode",
+						"vue-roaster",
+						"lofig"
+					],
+					active: "Aug 2016 - present",
+					github: "jonathan-grah",
+					link: "https://jgraham.dev",
+					avatar: {
+						type: "text",
+						color: "blue"
+					}
+				}
+			],
+			previousTeam: [
+				{
+					name: "Akira Laine",
+					bio:
+						"Co-Founder, Leader Developer, Designer and QA Tester.",
+					projects: ["MusareMeteor"],
+					active: "Sept 2015 - Feb 2016",
+					github: "darthmeme",
+					link: "https://github.com/AkiraLaine"
+				},
+				{
+					name: "Cameron Kline",
+					bio: "Developer, Designer and QA Tester.",
+					projects: ["MusareMeteor", "MusareReact", "MusareNode"],
+					active: "Aug - Nov 2016",
+					github: "luveti",
+					link: "https://github.com/luveti"
+				},
+				{
+					name: "Antonio",
+					bio: "Official instance Moderator.",
+					active: "Unknown"
+				},
+				{
+					name: "Aaron Gildea",
+					bio: "Official instance Moderator.",
+					active: "Unknown"
+				},
+				{
+					name: "Adryd",
+					bio: "Created Logo.",
+					active: "May 2016",
+					link: "https://github.com/Adryd"
+				}
+			],
+			otherContributors: [
+				{
+					name: "arvind-iyer",
+					link: "https://github.com/arvind-iyer"
+				},
+				{
+					name: "CullenIO",
+					link: "https://github.com/CullenIO"
+				},
+				{
+					name: "Wesley McCann",
+					link: "https://github.com/Septimus"
+				},
+				{
+					name: "Johannes Andersen",
+					link: "https://github.com/Johannes-Andersen"
+				}
+			]
+		};
+	}
 };
 </script>
 
 <style lang="scss" scoped>
 .night-mode {
-	.card {
+	.group .card {
 		background-color: var(--dark-grey-3);
 		p {
 			color: var(--light-grey-2);
 		}
 	}
+	.group .card .card-content .projects a,
+	.other-contributors div a {
+		background-color: var(--dark-grey);
+	}
 }
 
-li a {
-	color: dodgerblue;
-	border-bottom: 0 !important;
-}
-
-ul {
-	margin-left: 0;
-	margin-right: 0;
-	list-style: none;
-}
-
-.columns {
-	margin: 0;
-}
-
-.card-content .content {
-	font-size: 15px;
-}
-
-.card-header-title {
-	font-size: 17px;
-	font-weight: 700;
-}
-
-.role {
-	font-size: 16px;
-	font-weight: 500;
-}
-
-.custom-tag.blue {
-	border-bottom: 2px var(--dark-blue) solid;
+a {
+	color: var(--primary-color);
+	&:hover,
+	&:focus {
+		filter: brightness(95%);
+	}
 }
 
-.custom-tag.pink {
-	border-bottom: 2px var(--light-pink) solid;
+h2,
+h3,
+h4 {
+	margin: 20px 0;
 }
-
-.custom-tag.light-blue {
-	border-bottom: 2px var(--blue) solid;
-	background-color: transparent !important;
+h2 {
+	margin-top: 50px;
 }
+.other-contributors {
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	text-align: center;
+	margin-bottom: 50px;
 
-.custom-tag.light-green {
-	border-bottom: 2px var(--teal) solid;
+	div {
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: center;
+		a {
+			background: var(--white);
+			padding: 10px;
+			border-radius: 5px;
+			white-space: nowrap;
+			margin-top: 5px;
+			font-size: 16px;
+			text-align: center;
+			box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1),
+				0 0 0 1px rgba(10, 10, 10, 0.1);
+			&:not(:last-of-type) {
+				margin-right: 5px;
+			}
+		}
+	}
 }
 
-.custom-tag.purple {
-	border-bottom: 2px var(--purple) solid;
-}
+.group {
+	display: flex;
+	flex-wrap: wrap;
+	justify-content: center;
+	margin: 0 auto;
+	max-width: 1260px;
 
-#special-thanks {
-	margin-top: 60px;
+	.card {
+		display: inline-flex;
+		flex-direction: column;
+		width: calc(100% - 30px);
+		max-width: 400px;
+		margin: 10px;
+		text-align: left;
+		border-radius: 5px;
+		box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1),
+			0 0 0 1px rgba(10, 10, 10, 0.1);
+		.card-header {
+			line-height: 22.5px;
+			padding: 10px;
+			.profile-picture {
+				margin-right: 10px;
+				width: 45px;
+				height: 45px;
+				font-size: 20px;
+			}
+			div {
+				display: flex;
+				flex-direction: column;
+				line-height: 20px;
+				margin: auto 0;
+				strong {
+					font-size: 18px;
+				}
+			}
+			a {
+				margin-top: auto;
+				margin-bottom: auto;
+				margin-left: auto;
+			}
+		}
+		.card-content {
+			display: flex;
+			flex-direction: column;
+			flex-grow: 1;
+			.bio {
+				font-size: 16px;
+				margin-bottom: 10px;
+			}
+			.projects {
+				display: flex;
+				flex-wrap: wrap;
+				margin-top: auto;
 
-	.thanks {
-		font-size: 15px;
+				a {
+					background: var(--light-grey-2);
+					height: 30px;
+					padding: 5px;
+					border-radius: 5px;
+					white-space: nowrap;
+					margin-top: 5px;
+					&:not(:last-of-type) {
+						margin-right: 5px;
+					}
+				}
+			}
+		}
 	}
 }
 </style>