Explorar el Código

Completely finished creating and listing of playlists in frontend backend. Nearly finished with editing playlists.

theflametrooper hace 8 años
padre
commit
10e2c9a208

+ 4 - 34
backend/index.js

@@ -9,6 +9,7 @@ const app = require('./logic/app');
 const io = require('./logic/io');
 const stations = require('./logic/stations');
 const songs = require('./logic/songs');
+const playlists = require('./logic/playlists');
 const cache = require('./logic/cache');
 const notifications = require('./logic/notifications');
 const config = require('config');
@@ -18,40 +19,6 @@ async.waterfall([
 	// setup our Redis cache
 	(next) => {
 		cache.init(config.get('redis').url, () => {
-			// load some test stations into the cache
-			/*async.waterfall([
-				(next) => cache.hset('stations', 'edm', cache.schemas.station({
-					name: 'edm',
-					genres: ['edm'],
-					type: 'official',
-					displayName: 'EDM',
-					description: 'EDM Music',
-					playlist: [
-						'gCYcHz2k5x0'
-					],
-					currentSong: {
-						id: 'gCYcHz2k5x0',
-						title: 'Title',
-						artists: ['Artist1'],
-						genres: ['edm', 'pop'],
-						thumbnail: 'test',
-						duration: 100,
-						skipDuration: 10,
-						likes: 0,
-						dislikes: 0
-					}
-				}), next),
-				(next) => cache.hset('stations', 'chill', cache.schemas.station({
-					name: 'chill',
-					genres: ['chill'],
-					type: 'official',
-					displayName: 'Chill',
-					description: 'Chill Music',
-					playlist: [
-						'gCYcHz2k5x0'
-					]
-				}), next),
-			], next);*/
 			next();
 		});
 	},
@@ -74,6 +41,9 @@ async.waterfall([
 	// setup the songs
 	(next) => songs.init(next),
 
+	// setup the playlists
+	(next) => playlists.init(next),
+
 	// setup the frontend for local setups
 	(next) => {
 		if (!config.get("isDocker")) {

+ 65 - 9
backend/logic/actions/playlists.js

@@ -5,25 +5,81 @@ const io = require('../io');
 const cache = require('../cache');
 const utils = require('../utils');
 const hooks = require('./hooks');
+const async = require('async');
+const playlists = require('../playlists');
 
 module.exports = {
 
-	indexForUser: (session, username, cb) => {
-		db.models.playlist.find({ username }, (err, playlists) => {
+	indexForUser: (session, createdBy, cb) => {
+		db.models.playlist.find({ createdBy }, (err, playlists) => {
 			if (err) throw err;
-			cb(playlists);
+			cb({
+				status: 'success',
+				data: playlists
+			});
 		});
 	},
 
-	update: hooks.adminRequired((session, _id, playlist, cb) => {
-		db.models.playlist.findOneAndUpdate({ _id }, playlist, { upsert: true }, (err, updatedPlaylist) => {
+	create: (session, data, cb) => {
+		async.waterfall([
+
+			(next) => {
+				return (data) ? next() : cb({ 'status': 'failure', 'message': 'Invalid data' });
+			},
+
+			// check the cache for the playlist
+			(next) => cache.hget('playlists', data._id, next),
+
+			// if the cached version exist
+			(playlist, next) => {
+				if (playlist) return next({ 'status': 'failure', 'message': 'A playlist with that id already exists' });
+				db.models.playlist.findOne({ _id: data._id }, next);
+			},
+
+			(playlist, next) => {
+				if (playlist) return next({ 'status': 'failure', 'message': 'A playlist with that id already exists' });
+				const { _id, displayName, songs, createdBy } = data;
+				db.models.playlist.create({
+					_id,
+					displayName,
+					songs,
+					createdBy,
+					createdAt: Date.now()
+				}, next);
+			}
+
+		], (err, playlist) => {
+			if (err) {console.log(err); return cb({ 'status': 'failure', 'message': 'Something went wrong'});}
+			cache.pub('playlist.create', data._id);
+			return cb(null, { 'status': 'success', 'message': 'Successfully created playlist' });
+		});
+	},
+
+	getPlaylist: (session, id, cb) => {
+		playlists.getPlaylist(id, (err, playlist) => {
+			if (err == null) return cb({
+				status: 'success',
+				data: playlist
+			});
+		});
+	},
+
+	update: (session, _id, playlist, cb) => {
+		db.models.playlist.findOneAndUpdate({ _id }, playlist, { upsert: true }, (err, data) => {
+			if (err) throw err;
+			return cb({ status: 'success', message: 'Playlist has been successfully updated', data });
+		});
+	},
+
+	updateDisplayName: (session, _id, displayName, cb) => {
+		db.models.playlist.findOneAndUpdate({ _id }, { displayName }, { upsert: true }, (err, data) => {
 			if (err) throw err;
-			return cb({ status: 'success', message: 'Playlist has been successfully updated', data: updatedPlaylist });
+			return cb({ status: 'success', message: 'Playlist has been successfully updated', data });
 		});
-	}),
+	},
 
-	remove: hooks.adminRequired((session, _id, cb) => {
+	remove: (session, _id, cb) => {
 		db.models.playlist.remove({ _id });
-	})
+	}
 
 };

+ 63 - 0
backend/logic/playlists.js

@@ -0,0 +1,63 @@
+'use strict';
+
+const cache = require('./cache');
+const db = require('./db');
+const async = require('async');
+
+module.exports = {
+
+	init: cb => {
+		db.models.playlist.find({}, (err, playlists) => {
+			if (!err) {
+				playlists.forEach((playlist) => {
+					cache.hset('playlists', playlist._id, cache.schemas.playlist(playlist));
+				});
+				cb();
+			}
+		});
+	},
+
+	getPlaylist: (_id, cb) => {
+		async.waterfall([
+
+			(next) => {
+				cache.hget('playlists', _id, next);
+			},
+
+			(playlist, next) => {
+				if (playlist) return next(true, playlist);
+				db.models.playlist.findOne({ _id }, next);
+			},
+
+			(playlist, next) => {
+				if (playlist) {
+					cache.hset('playlists', _id, playlist);
+					next(true, playlist);
+				} else next('Playlist not found');
+			},
+
+		], (err, playlist) => {
+			if (err && err !== true) return cb(err);
+			else cb(null, playlist);
+		});
+	},
+
+	updatePlaylist: (_id, cb) => {
+		async.waterfall([
+
+			(next) => {
+				db.models.playlist.findOne({ _id }, next);
+			},
+
+			(playlist, next) => {
+				if (!playlist) return next('Playlist not found');
+				cache.hset('playlists', _id, playlist, next);
+			}
+
+		], (err, playlist) => {
+			if (err && err !== true) cb(err);
+			cb(null, playlist);
+		});
+	}
+
+};

+ 13 - 14
frontend/components/Modals/EditPlaylist.vue

@@ -3,19 +3,18 @@
 		<div class='modal-background'></div>
 		<div class='modal-card'>
 			<header class='modal-card-head'>
-				<p class='modal-card-title'>Editing: {{ 'Ultimate Playlist' }}</p>
+				<p class='modal-card-title'>Editing: {{ playlist.displayName }}</p>
 				<button class='delete' @click='$parent.toggleModal("editPlaylist")'></button>
 			</header>
 			<section class='modal-card-body'>
 				<aside class='menu'>
 					<ul class='menu-list'>
-						<li>
-							<!--repeat for each song in playlist-->
-							<a :href='' target='_blank'>Clean Bandit - Rockabye ft. Sean Paul & Anne-Marie</a>
+						<li v-for='song in playlist.songs'>
+							<a :href='' target='_blank'>{{ song.title }}</a>
 							<div class='controls'>
 								<a href='#' @click=''><i class='material-icons'>keyboard_arrow_down</i></a>
 								<a href='#' @click=''><i class='material-icons'>keyboard_arrow_up</i></a>
-								<a href='#' @click=''><i class='material-icons'>delete</i></a>
+								<a href='#' @click='removeSongFromPlaylist(song._id)'><i class='material-icons'>delete</i></a>
 							</div>
 						</li>
 					</ul>
@@ -55,7 +54,7 @@
 				<h5>Edit playlist details:</h5>
 				<div class='control is-grouped'>
 					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Playlist Display Name'>
+						<input class='input' type='text' placeholder='Playlist Display Name' v-model='playlist.displayName'>
 					</p>
 					<p class='control'>
 						<a class='button is-info' @click='renamePlaylist()'>Rename</a>
@@ -97,14 +96,12 @@
 					} else if (res.status == 'error') Toast.methods.addToast(res.message, 3000);
 				});
 			},
-			addSongToPlaylist: function () {
-
-			},
-			addPlaylist: function () {
-
-			},
+			addSongToPlaylist: function (id) {},
+			removeSongFromPlaylist: function (id) {},
 			renamePlaylist: function () {
-
+				_this.socket.emit('playlists.updateDisplayName', _this.playlist._id, _this.playlist.displayName, res => {
+					if (res.status == 'success') Toast.methods.addToast(res.message, 3000);
+				});
 			}
 		},
 		ready: function () {
@@ -112,7 +109,9 @@
 			let socketInterval = setInterval(() => {
 				if (!!_this.$parent.$parent.socket) {
 					_this.socket = _this.$parent.$parent.socket;
-					// _this.$parent.playlistBeingEdited - get that playlist id from socket
+					_this.socket.emit('playlists.getPlaylist', _this.$parent.playlistBeingEdited, res => {
+						if (res.status == 'success') _this.playlist = res.data;
+					});
 					clearInterval(socketInterval);
 				}
 			}, 100);

+ 11 - 5
frontend/components/Modals/createPlaylist.vue

@@ -8,7 +8,7 @@
 			</header>
 			<section class='modal-card-body'>
 				<p class='control is-expanded'>
-					<input class='input' type='text' placeholder='Playlist ID' v-model='playlist.id'>
+					<input class='input' type='text' placeholder='Playlist ID' v-model='playlist._id'>
 				</p>
 				<p class='control is-expanded'>
 					<input class='input' type='text' placeholder='Playlist Display Name' v-model='playlist.displayName'>
@@ -28,15 +28,21 @@
 		data() {
 			return {
 				playlist: {
-					id: null,
-					displayName: null
+					_id: null,
+					displayName: null,
+					songs: [],
+					createdBy: this.$parent.$parent.username,
+					createdAt: Date.now()
 				}
 			}
 		},
 		methods: {
 			createPlaylist: function () {
-				// socket
-				this.$parent.toggleModal("createPlaylist");
+				let _this = this;
+				_this.socket.emit('playlists.create', _this.playlist, res => {
+					Toast.methods.addToast(res.message, 3000);
+				});
+				this.$parent.toggleModal('createPlaylist');
 			}
 		},
 		ready: function () {

+ 22 - 6
frontend/components/Sidebars/Playlist.vue

@@ -3,17 +3,19 @@
 		<div class='inner-wrapper'>
 			<div class='title'>Playlists</div>
 
-			<aside class='menu'>
+			<aside class='menu' v-if='playlists.length > 0'>
 				<ul class='menu-list'>
-					<li>
-						<a href='#'>Top 40</a>
-						<a href='#' @click='$parent.editPlaylist(56);'>
+					<li v-for='playlist in playlists'>
+						<a href='#'>{{ playlist.displayName }}</a>
+						<a href='#' @click='editPlaylist(playlist._id)'>
 							<i class='material-icons'>edit</i>
 						</a>
 					</li>
 				</ul>
 			</aside>
 
+			<div class='none-found' v-else>No Playlists found</div>
+
 			<a class='button create-playlist' @click='$parent.toggleModal("createPlaylist")'>Create Playlist</a>
 		</div>
 	</div>
@@ -21,12 +23,24 @@
 
 <script>
 	export default {
+		data() {
+			return {
+				playlists: []
+			}
+		},
+		methods: {
+			editPlaylist: function (id) {
+				this.$parent.editPlaylist(id);
+			}
+		},
 		ready: function () {
 			let _this = this;
 			let socketInterval = setInterval(() => {
 				if (!!_this.$parent.$parent.socket) {
 					_this.socket = _this.$parent.$parent.socket;
-					// get users playlists
+					_this.socket.emit('playlists.indexForUser', _this.$parent.$parent.username, res => {
+						if (res.status == 'success') _this.playlists = res.data;
+					});
 					clearInterval(socketInterval);
 				}
 			}, 100);
@@ -67,7 +81,7 @@
 
 	.create-playlist {
 		width: 100%;
-    	margin-top: 25px;
+    	margin-top: 20px;
 		height: 40px;
 		border-radius: 0;
 		background: rgb(3, 169, 244);
@@ -90,4 +104,6 @@
 		display: flex;
     	align-items: center;
 	}
+
+	.none-found { text-align: center; }
 </style>

+ 1 - 1
frontend/components/Station/Station.vue

@@ -90,7 +90,7 @@
 				sidebars: {
 					queue: false,
 					users: false,
-					playlist: true
+					playlist: false
 				},
 				noSong: false,
 				simpleSong: false