Ver código fonte

feat: added ability to favorite stations

Kristian Vos 5 anos atrás
pai
commit
124dfbb588

+ 76 - 2
backend/logic/actions/stations.js

@@ -357,9 +357,9 @@ module.exports = {
 						if (station.owner === session.userId) return next(true);
 						next('An error occurred while joining the station.');
 					}
-				], (err) => {
+				], async (err) => {
 					if (err === true) return next(null, station);
-					next(utils.getError(err));
+					next(await utils.getError(err));
 				});
 			},
 
@@ -1180,4 +1180,78 @@ module.exports = {
 			return cb({'status': 'success', 'message': 'Successfully selected playlist.'});
 		});
 	}),
+
+	favoriteStation: hooks.loginRequired((session, stationId, cb, userId) => {
+		async.waterfall([
+			(next) => {
+				stations.getStation(stationId, next);
+			},
+
+			(station, next) => {
+				if (!station) return next('Station not found.');
+				async.waterfall([
+					(next) => {
+						if (station.privacy !== 'private') return next(true);
+						if (!session.userId) return next("You're not allowed to favorite this station.");
+						next();
+					},
+
+					(next) => {
+						db.models.user.findOne({ _id: userId }, next);
+					},
+
+					(user, next) => {
+						if (!user) return next("You're not allowed to favorite this station.");
+						if (user.role === 'admin') return next(true);
+						if (station.type === 'official') return next("You're not allowed to favorite this station.");
+						if (station.owner === session.userId) return next(true);
+						next("You're not allowed to favorite this station.");
+					}
+				], (err) => {
+					if (err === true) return next(null);
+					next(utils.getError(err));
+				});
+			},
+
+			(next) => {
+				db.models.user.updateOne({ _id: userId }, { $addToSet: { favoriteStations: stationId } }, next);
+			},
+
+			(res, next) => {
+				if (res.nModified === 0) return next("The station was already favorited.");
+				next();
+			}
+		], async (err) => {
+			if (err) {
+				err = await utils.getError(err);
+				logger.error("FAVORITE_STATION", `Favoriting station "${stationId}" failed. "${err}"`);
+				return cb({'status': 'failure', 'message': err});
+			}
+			logger.success("FAVORITE_STATION", `Favorited station "${stationId}" successfully.`);
+			cache.pub('user.favoritedStation', { userId, stationId });
+			return cb({'status': 'success', 'message': 'Succesfully favorited station.'});
+		});
+	}),
+
+	unfavoriteStation: hooks.loginRequired((session, stationId, cb, userId) => {
+		async.waterfall([
+			(next) => {
+				db.models.user.updateOne({ _id: userId }, { $pull: { favoriteStations: stationId } }, next);
+			},
+
+			(res, next) => {
+				if (res.nModified === 0) return next("The station wasn't favorited.");
+				next();
+			}
+		], async (err) => {
+			if (err) {
+				err = await utils.getError(err);
+				logger.error("UNFAVORITE_STATION", `Unfavoriting station "${stationId}" failed. "${err}"`);
+				return cb({'status': 'failure', 'message': err});
+			}
+			logger.success("UNFAVORITE_STATION", `Unfavorited station "${stationId}" successfully.`);
+			cache.pub('user.unfavoritedStation', { userId, stationId });
+			return cb({'status': 'success', 'message': 'Succesfully unfavorited station.'});
+		});
+	}),
 };

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

@@ -74,6 +74,22 @@ cache.sub('user.ban', data => {
 	});
 });
 
+cache.sub('user.favoritedStation', data => {
+	utils.socketsFromUser(data.userId, sockets => {
+		sockets.forEach(socket => {
+			socket.emit('event:user.favoritedStation', data.stationId);
+		});
+	});
+});
+
+cache.sub('user.unfavoritedStation', data => {
+	utils.socketsFromUser(data.userId, sockets => {
+		sockets.forEach(socket => {
+			socket.emit('event:user.unfavoritedStation', data.stationId);
+		});
+	});
+});
+
 module.exports = {
 
 	/**
@@ -1124,5 +1140,25 @@ module.exports = {
 				});
 			}
 		});
+	}),
+
+	getFavoriteStations: hooks.loginRequired((session, cb, userId) => {
+		async.waterfall([
+			(next) => {
+				db.models.user.findOne({ _id: userId }, next);
+			}
+		], async (err, user) => {
+			if (err && err !== true) {
+				err = await utils.getError(err);
+				logger.error("GET_FAVORITE_STATIONS", `User ${userId} failed to get favorite stations. '${err}'`);
+				cb({status: 'failure', message: err});
+			} else {
+				logger.success("GET_FAVORITE_STATIONS", `User ${userId} got favorite stations.`);
+				cb({
+					status: 'success',
+					favoriteStations: user.favoriteStations
+				});
+			}
+		});
 	})
 };

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

@@ -28,5 +28,6 @@ module.exports = {
 	},
 	liked: [{ type: String }],
 	disliked: [{ type: String }],
+	favoriteStations: [{ type: String }],
 	createdAt: { type: Date, default: Date.now() }
 };

+ 51 - 2
frontend/components/pages/Home.vue

@@ -108,15 +108,27 @@
 									title="This is your station."
 									>home</i
 								>
+								<button
+									v-if="!isFavorite(station)"
+									@click="favoriteStation($event, station)"
+								>
+									Favorite
+								</button>
+								<button
+									v-if="isFavorite(station)"
+									@click="unfavoriteStation($event, station)"
+								>
+									Unfavorite
+								</button>
 							</div>
 						</div>
-						<router-link
+						<!--router-link
 							class="absolute-a"
 							:to="{
 								name: 'station',
 								params: { id: station.name }
 							}"
-						/>
+						/-->
 					</router-link>
 				</div>
 			</div>
@@ -128,6 +140,7 @@
 
 <script>
 import { mapState, mapActions } from "vuex";
+import { Toast } from "vue-roaster";
 
 import MainHeader from "../MainHeader.vue";
 import MainFooter from "../MainFooter.vue";
@@ -143,6 +156,7 @@ export default {
 				key: ""
 			},
 			stations: [],
+			favoriteStations: [],
 			searchQuery: ""
 		};
 	},
@@ -205,6 +219,12 @@ export default {
 					}
 				});
 			});
+			this.socket.on("event:user.favoritedStation", stationId => {
+				this.favoriteStations.push(stationId);
+			});
+			this.socket.on("event:user.unfavoritedStation", stationId => {
+				this.favoriteStations.$remove(stationId);
+			});
 		});
 	},
 	methods: {
@@ -226,6 +246,10 @@ export default {
 						this.stations.push(station);
 					});
 			});
+			this.socket.emit("users.getFavoriteStations", data => {
+				if (data.status === "success")
+					this.favoriteStations = data.favoriteStations;
+			});
 			this.socket.emit("apis.joinRoom", "home", () => {});
 		},
 		isOwner(station) {
@@ -233,6 +257,31 @@ export default {
 				station.owner === this.userId && station.privacy === "public"
 			);
 		},
+		isFavorite(station) {
+			return this.favoriteStations.indexOf(station._id) !== -1;
+		},
+		favoriteStation(event, station) {
+			event.preventDefault();
+			this.socket.emit("stations.favoriteStation", station._id, res => {
+				if (res.status === "success") {
+					Toast.methods.addToast(
+						"Successfully favorited station.",
+						4000
+					);
+				} else Toast.methods.addToast(res.message, 8000);
+			});
+		},
+		unfavoriteStation(event, station) {
+			event.preventDefault();
+			this.socket.emit("stations.unfavoriteStation", station._id, res => {
+				if (res.status === "success") {
+					Toast.methods.addToast(
+						"Successfully unfavorited station.",
+						4000
+					);
+				} else Toast.methods.addToast(res.message, 8000);
+			});
+		},
 		...mapActions("modals", ["openModal"])
 	},
 	components: {