Browse Source

Fixed conflicts

theflametrooper 8 years ago
parent
commit
a901ec67af

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

@@ -2,7 +2,8 @@
 
 const request = require('request'),
 	  config  = require('config'),
-		utils = require('../utils');
+		utils = require('../utils'),
+		hooks = require('./hooks');
 
 module.exports = {
 
@@ -40,6 +41,13 @@ module.exports = {
 			utils.socketJoinRoom(session.socketId, page);
 		}
 		cb({});
-	}
+	},
+
+	joinAdminRoom: hooks.adminRequired((session, page, cb) => {
+		if (page === 'queue' || page === 'songs' || page === 'stations' || page === 'reports') {
+			utils.socketJoinRoom(session.socketId, `admin.${page}`);
+		}
+		cb({});
+	})
 
 };

+ 10 - 6
backend/logic/actions/queueSongs.js

@@ -9,15 +9,19 @@ const config = require('config');
 const request = require('request');
 const hooks = require('./hooks');
 
-notifications.subscribe('queue.newSong', songId => {
-	utils.emitToRoom('admin.queue', 'event:song.new', { songId });
+cache.sub('queue.newSong', songId => {
+	console.log(123321);
+	db.models.queueSong.findOne({_id: songId}, (err, song) => {
+		console.log(err, song);
+		utils.emitToRoom('admin.queue', 'event:admin.queueSong.added', song);
+	});
 });
 
-notifications.subscribe('queue.removedSong', songId => {
-	utils.emitToRoom('admin.queue', 'event:song.removed', { songId });
+cache.sub('queue.removedSong', songId => {
+	utils.emitToRoom('admin.queue', 'event:admin.queueSong.removed', songId);
 });
 
-notifications.subscribe('queue.updatedSong', songId => {
+cache.sub('queue.updatedSong', songId => {
 	//TODO Retrieve new Song object
 	utils.emitToRoom('admin.queue', 'event:song.updated', { songId });
 });
@@ -51,7 +55,7 @@ module.exports = {
 	remove: hooks.adminRequired((session, songId, cb) => {
 		db.models.queueSong.remove({ _id: songId }, (err, res) => {
 			if (err) return cb({ status: 'failure', message: err.message });
-			//TODO Pub/sub for (queue)songs on admin pages.
+			cache.pub('queue.removedSong', songId);
 			cb({ status: 'success', message: 'Song was removed successfully' });
 		});
 	}),

+ 8 - 5
backend/logic/actions/reports.js

@@ -4,6 +4,7 @@ const async = require('async');
 
 const db = require('../db');
 const hooks = require('./hooks');
+const songs = require('../songs');
 
 module.exports = {
 
@@ -25,14 +26,14 @@ module.exports = {
 		});
 	}),
 
-	create: hooks.loginRequired((session, data, cb) => {
+	create: hooks.loginRequired((session, data, cb, userId) => {
 		async.waterfall([
 
 			(next) => {
-				db.models.report.find({ createdBy: data.createdBy, createdAt: data.createdAt }).exec((err, report) => {
-					if (err) console.error(err);
-					if (report) return cb({ status: 'failure', message: 'Report already exists' });
-					else next();
+				songs.getSong(data.songId, (err, song) => {
+					if (err) return next(err);
+					if (!song) return next('Song does not exist in our Database.');
+					next();
 				});
 			},
 
@@ -93,6 +94,8 @@ module.exports = {
 			},
 
 			(next) => {
+				data.createdBy = userId;
+				data.createdAt = Date.now();
 				db.models.report.create(data, next);
 			}
 

+ 22 - 9
backend/logic/actions/songs.js

@@ -8,12 +8,13 @@ const utils = require('../utils');
 const hooks = require('./hooks');
 const queueSongs = require('./queueSongs');
 
-cache.sub('song.like', (data) => {
-	utils.emitToRoom(`song.${data.songId}`, 'event:song.like', {songId: data.songId, undisliked: data.undisliked});
-	utils.socketsFromUser(data.userId, (sockets) => {
-		sockets.forEach((socket) => {
-			socket.emit('event:song.newRatings', {songId: data.songId, liked: true, disliked: false});
-		});
+cache.sub('song.removed', songId => {
+	utils.emitToRoom('admin.songs', 'event:admin.song.removed', songId);
+});
+
+cache.sub('song.added', songId => {
+	db.models.queueSong.findOne({_id: songId}, (err, song) => {
+		utils.emitToRoom('admin.songs', 'event:admin.song.added', song);
 	});
 });
 
@@ -64,7 +65,14 @@ module.exports = {
 	}),
 
 	remove: hooks.adminRequired((session, songId, cb) => {
-		db.models.song.remove({ _id: songId });
+		db.models.song.remove({ _id: songId }, (err) => {
+			if (err) return cb({status: 'failure', message: err.message});
+			cache.hdel('songs', songId, (err) => {
+				if (err) return cb({status: 'failure', message: err.message});
+				cache.pub('song.removed', songId);
+				cb({status: 'success', message: 'Successfully removed the song.'});
+			});
+		});
 	}),
 
 	add: hooks.adminRequired((session, song, cb, userId) => {
@@ -75,8 +83,13 @@ module.exports = {
 				newSong.acceptedBy = userId;
 				newSong.acceptedAt = Date.now();
 				if (!existingSong) newSong.save(err => {
-					if (err) console.error(err);
-					else cb({ status: 'success', message: 'Song has been moved from Queue' })
+					if (err) {
+						console.error(err);
+						cb({ status: 'failure', message: 'Something went wrong while adding the song to the queue.' });
+					} else {
+						cache.pub('song.added', songId);
+						cb({ status: 'success', message: 'Song has been moved from Queue' });
+					}
 				});
 			});
 			//TODO Check if video is in queue and Add the song to the appropriate stations

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

@@ -13,6 +13,14 @@ const stations = require('../stations');
 const songs = require('../songs');
 const hooks = require('./hooks');
 
+cache.sub('station.updatePartyMode', data => {
+	utils.emitToRoom(`station.${data.stationId}`, "event:partyMode.updated", data.partyMode);
+});
+
+cache.sub('privatePlaylist.selected', data => {
+	utils.emitToRoom(`station.${data.stationId}`, "event:privatePlaylist.selected", data.playlistId);
+});
+
 cache.sub('station.pause', stationId => {
 	utils.emitToRoom(`station.${stationId}`, "event:stations.pause");
 });
@@ -35,10 +43,14 @@ cache.sub('station.voteSkipSong', stationId => {
 	utils.emitToRoom(`station.${stationId}`, "event:song.voteSkipSong");
 });
 
+cache.sub('station.remove', stationId => {
+	utils.emitToRoom('admin.stations', 'event:admin.station.removed', stationId);
+});
+
 cache.sub('station.create', stationId => {
 	stations.initializeStation(stationId, (err, station) => {
 		if (err) console.error(err);
-		//TODO Emit to admin station page
+		utils.emitToRoom('admin.stations', 'event:admin.station.added', station);
 		// TODO If community, check if on whitelist
 		if (station.privacy === 'public') utils.emitToRoom('home', "event:stations.created", station);
 		else {
@@ -202,7 +214,8 @@ module.exports = {
 								displayName: station.displayName,
 								privacy: station.privacy,
 								partyMode: station.partyMode,
-								owner: station.owner
+								owner: station.owner,
+								privatePlaylist: station.privatePlaylist
 							}
 						});
 					}
@@ -322,6 +335,7 @@ module.exports = {
 				if (err) return cb({ status: 'failure', message: 'Something went wrong when saving the station.' });
 				stations.updateStation(stationId, () => {
 					//TODO Pub/sub for privacy change
+					cache.pub('station.updatePartyMode', {stationId: stationId, partyMode: newPartyMode});
 					stations.skipStation(stationId)();
 					cb({ status: 'success', message: 'Successfully updated the party mode.' });
 				})
@@ -382,6 +396,7 @@ module.exports = {
 		db.models.station.remove({ _id: stationId }, (err) => {
 			if (err) return cb({status: 'failure', message: 'Something went wrong when deleting that station.'});
 			cache.hdel('stations', stationId, () => {
+				cache.pub('station.remove', stationId);
 				return cb({ status: 'success', message: 'Station successfully removed' });
 			});
 		});
@@ -530,6 +545,7 @@ module.exports = {
 							stations.updateStation(stationId, (err, station) => {
 								if (err) return cb(err);
 								stations.skipStation(stationId)();
+								cache.pub('privatePlaylist.selected', {playlistId, stationId});
 								cb({'status': 'success', 'message': 'Playlist selected.'});
 							});
 						});

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

@@ -1,7 +1,7 @@
 module.exports = {
 	resolved: { type: Boolean, default: false, required: true },
 	songId: { type: String, required: true },
-	description: { type: String, required: true },
+	description: { type: String },
 	issues: [{
 		name: String,
 		reasons: Array

+ 1 - 1
backend/logic/utils.js

@@ -259,7 +259,7 @@ module.exports = {
 			});
 			dur = dur.replace(/([\d]*)M/, (v, v2) => {
 				v2 = Number(v2);
-				duration = (v2 * 60);
+				duration += (v2 * 60);
 				return '';
 			});
 			dur = dur.replace(/([\d]*)S/, (v, v2) => {

+ 20 - 3
frontend/components/Admin/QueueSongs.vue

@@ -130,18 +130,35 @@
 				});
 			},
 			remove: function (id, index) {
-				this.songs.splice(index, 1);
 				this.socket.emit('queueSongs.remove', id, res => {
 					if (res.status == 'success') Toast.methods.addToast(res.message, 2000);
 				});
+			},
+			init: function() {
+				let _this = this;
+				_this.socket.emit('queueSongs.index', data => {
+					_this.songs = data;
+				});
+				_this.socket.emit('apis.joinAdminRoom', 'queue', data => {});
 			}
 		},
 		ready: function () {
 			let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;
-				_this.socket.emit('queueSongs.index', data => {
-					_this.songs = data;
+				if (_this.socket.connected) {
+					_this.init();
+					_this.socket.on('event:admin.queueSong.added', queueSong => {
+						_this.songs.push(queueSong);
+					});
+					_this.socket.on('event:admin.queueSong.removed', songId => {
+						_this.songs = _this.songs.filter(function(song) {
+							return song._id !== songId;
+						});
+					});
+				}
+				io.onConnect(() => {
+					_this.init();
 				});
 			});
 

+ 23 - 4
frontend/components/Admin/Songs.vue

@@ -41,6 +41,7 @@
 	import { Toast } from 'vue-roaster';
 
 	import EditSong from '../Modals/EditSong.vue';
+	import io from '../../io';
 
 	export default {
 		components: { EditSong },
@@ -123,18 +124,36 @@
 				});
 			},
 			remove: function (id, index) {
-				this.songs.splice(index, 1);
 				this.socket.emit('songs.remove', id, res => {
-					if (res.status == 'success') Toast.methods.addToast(res.message, 2000);
+					if (res.status == 'success') Toast.methods.addToast(res.message, 4000);
+					else Toast.methods.addToast(res.message, 8000);
 				});
+			},
+			init: function() {
+				let _this = this;
+				_this.socket.emit('songs.index', data => {
+					_this.songs = data;
+				});
+				_this.socket.emit('apis.joinAdminRoom', 'songs', data => {});
 			}
 		},
 		ready: function () {
 			let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;
-				_this.socket.emit('songs.index', data => {
-					_this.songs = data;
+				if (_this.socket.connected) {
+					_this.init();
+					_this.socket.on('event:admin.song.added', song => {
+						_this.songs.push(song);
+					});
+					_this.socket.on('event:admin.song.removed', songId => {
+						_this.songs = _this.songs.filter(function(song) {
+							return song._id !== songId;
+						});
+					});
+				}
+				io.onConnect(() => {
+					_this.init();
 				});
 			});
 

+ 22 - 4
frontend/components/Admin/Stations.vue

@@ -119,7 +119,7 @@
 			},
 			removeStation: function (index) {
 				this.socket.emit('stations.remove', this.stations[index]._id, res => {
-					if (res.status == 'success') this.stations.splice(index, 1); Toast.methods.addToast(res.message, 3000);
+					Toast.methods.addToast(res.message, 3000);
 				});
 			},
 			addGenre: function () {
@@ -137,14 +137,32 @@
 				if (genre) this.newStation.blacklistedGenres.push(genre);
 				else Toast.methods.addToast('Genre cannot be empty', 3000);
 			},
-			removeBlacklistedGenre: function (index) { this.newStation.blacklistedGenres.splice(index, 1); }
+			removeBlacklistedGenre: function (index) { this.newStation.blacklistedGenres.splice(index, 1); },
+			init: function() {
+				let _this = this;
+				_this.socket.emit('stations.index', data => {
+					_this.stations = data.stations;
+				});
+				_this.socket.emit('apis.joinAdminRoom', 'stations', data => {});
+			}
 		},
 		ready: function () {
 			let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;
-				_this.socket.emit('stations.index', data => {
-					_this.stations = data.stations;
+				if (_this.socket.connected) {
+					_this.init();
+				}
+				_this.socket.on('event:admin.station.added', station => {
+					_this.stations.push(station);
+				});
+				_this.socket.on('event:admin.station.removed', stationId => {
+					_this.stations = _this.stations.filter(function(station) {
+						return station._id !== stationId;
+					});
+				});
+				io.onConnect(() => {
+					_this.init();
 				});
 			});
 		}

+ 7 - 1
frontend/components/Modals/AddSongToQueue.vue

@@ -71,7 +71,13 @@
 			},
 			submitQuery: function () {
 				let _this = this;
-				_this.socket.emit('apis.searchYoutube', _this.querySearch, results => {
+				let query = _this.querySearch;
+				if (query.indexOf('&index=') !== -1) {
+					query = query.split('&index=');
+					query.pop();
+					query = query.join('');
+				}
+				_this.socket.emit('apis.searchYoutube', query, results => {
 					results = results.data;
 					_this.queryResults = [];
 					for (let i = 0; i < results.items.length; i++) {

+ 23 - 8
frontend/components/Modals/EditStation.vue

@@ -10,7 +10,7 @@
 				<label class='label'>Display name</label>
 				<div class='control is-grouped'>
 					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Station Display Name' v-model='$parent.station.displayName'>
+						<input class='input' type='text' placeholder='Station Display Name' v-model='data.displayName'>
 					</p>
 					<p class='control'>
 						<a class='button is-info' @click='updateDisplayName()'>Update</a>
@@ -19,7 +19,7 @@
 				<label class='label'>Description</label>
 				<div class='control is-grouped'>
 					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Station Display Name' v-model='$parent.station.description'>
+						<input class='input' type='text' placeholder='Station Display Name' v-model='data.description'>
 					</p>
 					<p class='control'>
 						<a class='button is-info' @click='updateDescription()'>Update</a>
@@ -29,7 +29,7 @@
 				<div class='control is-grouped'>
 					<p class='control is-expanded'>
 						<span class='select'>
-							<select v-model='$parent.station.privacy'>
+							<select v-model='data.privacy'>
 								<option :value='"public"'>Public</option>
 								<option :value='"unlisted"'>Unlisted</option>
 								<option :value='"private"'>Private</option>
@@ -43,7 +43,7 @@
 				<div class='control is-grouped' v-if="$parent.type === 'community'">
 					<p class="control is-expanded">
 						<label class="checkbox">
-							<input type="checkbox" v-model="$parent.station.partyMode">
+							<input type="checkbox" v-model="data.partyMode">
 							Party mode
 						</label>
 					</p>
@@ -61,27 +61,37 @@
 	import io from '../../io';
 
 	export default {
+		data: function() {
+			return {
+				data: {
+					displayName: '',
+					description: '',
+					privacy: 'private',
+					partyMode: false
+				}
+			}
+		},
 		methods: {
 			updateDisplayName: function () {
-				this.socket.emit('stations.updateDisplayName', this.$parent.stationId, this.$parent.station.displayName, res => {
+				this.socket.emit('stations.updateDisplayName', this.data.stationId, this.data.displayName, res => {
 					if (res.status == 'success') return Toast.methods.addToast(res.message, 4000);
 					Toast.methods.addToast(res.message, 8000);
 				});
 			},
 			updateDescription: function () {
-				this.socket.emit('stations.updateDescription', this.$parent.stationId, this.$parent.station.description, res => {
+				this.socket.emit('stations.updateDescription', this.data.stationId, this.data.description, res => {
 					if (res.status == 'success') return Toast.methods.addToast(res.message, 4000);
 					Toast.methods.addToast(res.message, 8000);
 				});
 			},
 			updatePrivacy: function () {
-				this.socket.emit('stations.updatePrivacy', this.$parent.stationId, this.$parent.station.privacy, res => {
+				this.socket.emit('stations.updatePrivacy', this.data.stationId, this.data.privacy, res => {
 					if (res.status == 'success') return Toast.methods.addToast(res.message, 4000);
 					Toast.methods.addToast(res.message, 8000);
 				});
 			},
 			updatePartyMode: function () {
-				this.socket.emit('stations.updatePartyMode', this.$parent.stationId, this.$parent.station.partyMode, res => {
+				this.socket.emit('stations.updatePartyMode', this.data.stationId, this.data.partyMode, res => {
 					if (res.status == 'success') return Toast.methods.addToast(res.message, 4000);
 					Toast.methods.addToast(res.message, 8000);
 				});
@@ -92,6 +102,11 @@
 			io.getSocket((socket) => {
 				_this.socket = socket;
 			});
+			this.data.stationId = this.$parent.stationId;
+			this.data.partyMode = this.$parent.station.partyMode;
+			this.data.description = this.$parent.station.description;
+			this.data.privacy = this.$parent.station.privacy;
+			this.data.displayName = this.$parent.station.displayName;
 		},
 		events: {
 			closeModal: function() {

+ 6 - 7
frontend/components/Modals/Report.vue

@@ -8,7 +8,7 @@
 			</header>
 			<section class='modal-card-body'>
 				<div class='columns song-types'>
-					<div class='column song-type' v-if='$parent.previousSong !== null'>
+					<div class='column song-type' v-if='$parent.previousSong !== null && $parent.previousSong.likes !== -1 && $parent.previousSong.dislikes !== -1'>
 						<div class='card is-fullwidth' :class="{ 'is-highlight-active': isPreviousSongActive }" @click="highlight('previousSong')">
 							<header class='card-header'>
 								<p class='card-header-title'>
@@ -35,7 +35,7 @@
 							</div>
 						</div>
 					</div>
-					<div class='column song-type' v-if='$parent.currentSong !== null'>
+					<div class='column song-type' v-if='$parent.currentSong !== null && $parent.currentSong.likes !== -1 && $parent.currentSong.dislikes !== -1'>
 						<div class='card is-fullwidth'  :class="{ 'is-highlight-active': isCurrentSongActive }" @click="highlight('currentSong')">
 							<header class='card-header'>
 								<p class='card-header-title'>
@@ -63,7 +63,8 @@
 						</div>
 					</div>
 				</div>
-				<div class='edit-report-wrapper'>
+				<h4 v-if='($parent.currentSong === null || ($parent.currentSong.likes === -1 && $parent.currentSong.dislikes === -1)) && ($parent.previousSong === null || ($parent.previousSong.likes === -1 || $parent.previousSong.dislikes === -1))'>There are currently no songs to report.</h4>
+				<div class='edit-report-wrapper' v-else>
 					<div class='columns is-multiline'>
 						<div class='column is-half' v-for='issue in issues'>
 							<label class='label'>{{ issue.name }}</label>
@@ -83,7 +84,7 @@
 				</div>
 			</section>
 			<footer class='modal-card-foot'>
-				<a class='button is-success' @click='create()'>
+				<a class='button is-success' @click='create()' v-if='!(($parent.currentSong === null || ($parent.currentSong.likes === -1 && $parent.currentSong.dislikes === -1)) && ($parent.previousSong === null || ($parent.previousSong.likes === -1 || $parent.previousSong.dislikes === -1)))'>
 					<i class='material-icons save-changes'>done</i>
 					<span>&nbsp;Create</span>
 				</a>
@@ -115,9 +116,7 @@
 						{ name: 'Duration', reasons: [] },
 						{ name: 'Artists', reasons: [] },
 						{ name: 'Thumbnail', reasons: [] }
-					],
-					createdBy: this.$parent.$parent.userId,
-					createdAt: Date.now()
+					]
 				},
 				issues: [
 					{

+ 3 - 3
frontend/components/Station/CommunityHeader.vue

@@ -37,9 +37,9 @@
 			</a>
 		</div>
 
-		<!--<div class='nav-center'>
-			{{title}}
-		</div>-->
+		<div class='nav-center stationDisplayName'>
+			{{$parent.station.displayName}}
+		</div>
 
 		<span class="nav-toggle" :class="{ 'is-active': isMobile }" @click="isMobile = !isMobile">
 			<span></span>

+ 3 - 3
frontend/components/Station/OfficialHeader.vue

@@ -42,9 +42,9 @@
 			</a>
 		</div>
 
-		<!--<div class='nav-center'>
-			{{title}}
-		</div>-->
+		<div class='nav-center stationDisplayName'>
+			{{$parent.station.displayName}}
+		</div>
 
 		<span class="nav-toggle" :class="{ 'is-active': isMobile }" @click="isMobile = !isMobile">
 			<span></span>

+ 18 - 2
frontend/components/Station/Station.vue

@@ -90,7 +90,7 @@
 				type: '',
 				playerReady: false,
 				previousSong: null,
-				currentSong: null,
+				currentSong: {},
 				player: undefined,
 				timePaused: 0,
 				paused: false,
@@ -342,7 +342,7 @@
 				});
 
 				_this.socket.on('event:songs.next', data => {
-					_this.previousSong = _this.currentSong;
+					_this.previousSong = (_this.currentSong._id) ? _this.currentSong : null;
 					_this.currentSong = (data.currentSong) ? data.currentSong : {};
 					_this.startedAt = data.startedAt;
 					_this.paused = data.paused;
@@ -422,6 +422,18 @@
 				_this.socket.on('event:song.voteSkipSong', () => {
 					if (this.currentSong) this.currentSong.skipVotes++;
 				});
+
+				_this.socket.on('event:privatePlaylist.selected', (playlistId) => {
+					if (this.type === 'community') {
+						this.station.privatePlaylist = playlistId;
+					}
+				});
+
+				_this.socket.on('event:partyMode.updated', (partyMode) => {
+					if (this.type === 'community') {
+						this.station.partyMode = partyMode;
+					}
+				});
 			});
 
 			let volume = parseInt(localStorage.getItem("volume"));
@@ -449,6 +461,10 @@
 		text-align: center;
 	}
 
+	.stationDisplayName {
+		color: white !important;
+	}
+
 	.slideout {
 		top: 50px;
 		height: 100%;

+ 2 - 1
frontend/components/User/Settings.vue

@@ -13,7 +13,7 @@
 			</p>
 		</div>
 		<label class="label">Email</label>
-		<div class="control is-grouped">
+		<div class="control is-grouped" v-if="user.email">
 			<p class="control is-expanded has-icon has-icon-right">
 				<input class="input" type="text" placeholder="Change email address" v-model="user.email.address">
 				<!--Remove validation if it's their own without changing-->
@@ -33,6 +33,7 @@
 	import MainFooter from '../MainFooter.vue';
 
 	import LoginModal from '../Modals/Login.vue'
+	import io from '../../io'
 
 	export default {
 		data() {

+ 1 - 0
frontend/components/User/Show.vue

@@ -36,6 +36,7 @@
 
 	import MainHeader from '../MainHeader.vue';
 	import MainFooter from '../MainFooter.vue';
+	import io from '../../io';
 
 	export default {
 		data() {