Browse Source

Merge branch 'polishing' of github.com:Musare/MusareNode into polishing

Jonathan 4 years ago
parent
commit
b0589101b0

+ 33 - 1
backend/logic/actions/playlists.js

@@ -1,6 +1,6 @@
 import async from "async";
 
-import { isLoginRequired } from "./hooks";
+import { isAdminRequired, isLoginRequired } from "./hooks";
 
 import moduleManager from "../../index";
 
@@ -161,6 +161,38 @@ CacheModule.runJob("SUB", {
 });
 
 export default {
+	/**
+	 * Gets all playlists
+	 *
+	 * @param {object} session - the session object automatically added by socket.io
+	 * @param {Function} cb - gets called with the result
+	 */
+	index: isAdminRequired(async function index(session, cb) {
+		const playlistModel = await DBModule.runJob(
+			"GET_MODEL",
+			{
+				modelName: "playlist"
+			},
+			this
+		);
+		async.waterfall(
+			[
+				next => {
+					playlistModel.find({}).sort({ createdAt: "desc" }).exec(next);
+				}
+			],
+			async (err, playlists) => {
+				if (err) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log("ERROR", "PLAYLISTS_INDEX", `Indexing playlists failed. "${err}"`);
+					return cb({ status: "failure", message: err });
+				}
+				this.log("SUCCESS", "PLAYLISTS_INDEX", "Indexing playlists successful.");
+				return cb({ status: "success", data: playlists });
+			}
+		);
+	}),
+
 	/**
 	 * Gets the first song from a private playlist
 	 *

+ 1 - 0
frontend/package.json

@@ -55,6 +55,7 @@
     "vue-router": "^3.0.7",
     "vuedraggable": "^2.24.3",
     "vuex": "^3.1.1",
+    "webpack-md5-hash": "0.0.6",
     "webpack-merge": "^4.2.1"
   }
 }

+ 18 - 0
frontend/src/pages/Admin/index.vue

@@ -30,6 +30,15 @@
 						<span>&nbsp;Stations</span>
 					</router-link>
 				</li>
+				<li
+					:class="{ 'is-active': currentTab == 'playlists' }"
+					@click="showTab('playlists')"
+				>
+					<router-link class="tab playlists" to="/admin/playlists">
+						<i class="material-icons">library_music</i>
+						<span>&nbsp;Playlists</span>
+					</router-link>
+				</li>
 				<li
 					:class="{ 'is-active': currentTab == 'reports' }"
 					@click="showTab('reports')"
@@ -96,6 +105,7 @@
 		<queue-songs v-if="currentTab == 'queueSongs'" />
 		<songs v-if="currentTab == 'songs'" />
 		<stations v-if="currentTab == 'stations'" />
+		<playlists v-if="currentTab == 'playlists'" />
 		<reports v-if="currentTab == 'reports'" />
 		<news v-if="currentTab == 'news'" />
 		<users v-if="currentTab == 'users'" />
@@ -114,6 +124,7 @@ export default {
 		QueueSongs: () => import("./tabs/QueueSongs.vue"),
 		Songs: () => import("./tabs/Songs.vue"),
 		Stations: () => import("./tabs/Stations.vue"),
+		Playlists: () => import("./tabs/Playlists.vue"),
 		Reports: () => import("./tabs/Reports.vue"),
 		News: () => import("./tabs/News.vue"),
 		Users: () => import("./tabs/Users.vue"),
@@ -146,6 +157,9 @@ export default {
 				case "/admin/stations":
 					this.currentTab = "stations";
 					break;
+				case "/admin/playlists":
+					this.currentTab = "playlists";
+					break;
 				case "/admin/reports":
 					this.currentTab = "reports";
 					break;
@@ -209,6 +223,10 @@ export default {
 		color: $purple;
 		border-color: $purple;
 	}
+	.playlists {
+		color: $light-purple;
+		border-color: $light-purple;
+	}
 	.reports {
 		color: $yellow;
 		border-color: $yellow;

+ 167 - 0
frontend/src/pages/Admin/tabs/Playlists.vue

@@ -0,0 +1,167 @@
+<template>
+	<div>
+		<metadata title="Admin | Playlists" />
+		<div class="container">
+			<table class="table is-striped">
+				<thead>
+					<tr>
+						<td>Display name</td>
+						<td>Is user modifiable</td>
+						<td>Songs #</td>
+						<td>Playlist length</td>
+						<td>Created by</td>
+						<td>Created at</td>
+						<td>Playlist id</td>
+						<!-- <td>Options</td> -->
+					</tr>
+				</thead>
+				<tbody>
+					<tr v-for="playlist in playlists" :key="playlist._id">
+						<td>{{ playlist.displayName }}</td>
+						<td>{{ playlist.isUserModifiable }}</td>
+						<td>{{ playlist.songs.length }}</td>
+						<td>{{ totalLengthForPlaylist(playlist.songs) }}</td>
+						<td>
+							<user-id-to-username
+								:user-id="playlist.createdBy"
+								:link="true"
+							/>
+						</td>
+						<td :title="new Date(playlist.createdAt)">
+							{{ getDateFormatted(playlist.createdAt) }}
+						</td>
+						<td>{{ playlist._id }}</td>
+						<!-- <td>
+							<button
+								class="button is-primary"
+								@click="edit(playlist)"
+							>
+								Edit
+							</button>
+						</td> -->
+					</tr>
+				</tbody>
+			</table>
+		</div>
+		<!-- <edit-playlist
+			v-if="modals.editPlaylist"
+			:user-id="editingPlaylistId"
+			sector="admin"
+		/> -->
+	</div>
+</template>
+
+<script>
+import { mapState, mapActions } from "vuex";
+
+// import EditPlaylist from "../../../components/modals/EditPlaylist.vue";
+import UserIdToUsername from "../../../components/common/UserIdToUsername.vue";
+
+import io from "../../../io";
+import utils from "../../../../js/utils";
+
+export default {
+	components: { /* EditPlaylist, */ UserIdToUsername },
+	data() {
+		return {
+			utils,
+			// editingPlaylistId: "",
+			playlists: []
+		};
+	},
+	computed: {
+		...mapState("modalVisibility", {
+			modals: state => state.modals.admin
+		})
+	},
+	mounted() {
+		console.log("mounted");
+
+		io.getSocket(socket => {
+			this.socket = socket;
+			if (this.socket.connected) this.init();
+			io.onConnect(() => this.init());
+		});
+	},
+	methods: {
+		// edit(playlist) {
+		// 	this.editingPlaylistId = playlist._id;
+		// 	this.openModal({ sector: "admin", modal: "editPlaylist" });
+		// },
+		init() {
+			this.socket.emit("playlists.index", res => {
+				console.log(res);
+				if (res.status === "success") {
+					this.playlists = res.data;
+					// if (this.$route.query.userId) {
+					// 	const user = this.users.find(
+					// 		user => user._id === this.$route.query.userId
+					// 	);
+					// 	if (user) this.edit(user);
+					// }
+				}
+			});
+			this.socket.emit("apis.joinAdminRoom", "playlists", () => {});
+		},
+		getDateFormatted(createdAt) {
+			const date = new Date(createdAt);
+			const year = date.getFullYear();
+			const month = `${date.getMonth() + 1}`.padStart(2, 0);
+			const day = `${date.getDate()}`.padStart(2, 0);
+			const hour = `${date.getHours()}`.padStart(2, 0);
+			const minute = `${date.getMinutes()}`.padStart(2, 0);
+			return `${year}-${month}-${day} ${hour}:${minute}`;
+		},
+		totalLengthForPlaylist(songs) {
+			let length = 0;
+			songs.forEach(song => {
+				length += song.duration;
+			});
+			return this.utils.formatTimeLong(length);
+		},
+		...mapActions("modalVisibility", ["openModal"])
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../../styles/global.scss";
+
+.night-mode {
+	.table {
+		color: $night-mode-text;
+		background-color: $night-mode-bg-secondary;
+
+		thead tr {
+			background: $night-mode-bg-secondary;
+			td {
+				color: #fff;
+			}
+		}
+
+		tbody tr:hover {
+			background-color: #111 !important;
+		}
+
+		tbody tr:nth-child(even) {
+			background-color: #444;
+		}
+
+		strong {
+			color: $night-mode-text;
+		}
+	}
+}
+
+body {
+	font-family: "Hind", sans-serif;
+}
+
+td {
+	vertical-align: middle;
+}
+
+.is-primary:focus {
+	background-color: $primary-color !important;
+}
+</style>

+ 5 - 1
frontend/src/pages/Station/index.vue

@@ -56,6 +56,9 @@
 								<div
 									class="player-cannot-autoplay"
 									v-if="!canAutoplay"
+									@click="
+										increaseVolume() && decreaseVolume()
+									"
 								>
 									<p>
 										Please click anywhere on the screen for
@@ -805,7 +808,8 @@ export default {
 						controls: 0,
 						iv_load_policy: 3,
 						rel: 0,
-						showinfo: 0
+						showinfo: 0,
+						disablekb: 1
 					},
 					events: {
 						onReady: () => {

+ 1 - 0
frontend/src/store/modules/modalVisibility.js

@@ -21,6 +21,7 @@ const state = {
 			editUser: false,
 			editSong: false,
 			editStation: false,
+			editPlaylist: false,
 			viewReport: false,
 			viewPunishment: false
 		}

+ 2 - 0
frontend/webpack.common.js

@@ -1,4 +1,5 @@
 const VueLoaderPlugin = require("vue-loader/lib/plugin");
+const WebpackMd5Hash = require("webpack-md5-hash");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
 
 module.exports = {
@@ -9,6 +10,7 @@ module.exports = {
 	},
 	plugins: [
 		new VueLoaderPlugin(),
+		new WebpackMd5Hash(),
 		new HtmlWebpackPlugin({
 			hash: true,
 			template: "dist/index.tpl.html",

+ 3 - 3
frontend/webpack.dev.js

@@ -24,9 +24,9 @@ module.exports = merge(common, {
 		public: config.get("frontendDomain"),
 		host: "0.0.0.0",
 		watchOptions: {
-			ignored: /node_modules/
+			aggregateTimeout: 300,
+			poll: 1000
 		},
-		disableHostCheck: true,
-		stats: { chunks: false, children: false }
+		disableHostCheck: true
 	}
 });