Browse Source

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

Kristian Vos 3 years ago
parent
commit
694ff9d417

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

@@ -481,8 +481,9 @@ export default {
 					userId: session.userId,
 					type: "song__report",
 					payload: {
-						message: `Reported song <youtubeId>${song.title} by ${song.artists.join(", ")}</youtubeId>`,
+						message: `Created a <reportId>${report._id}</reportId> for song <youtubeId>${song.title}</youtubeId>`,
 						youtubeId: report.song.youtubeId,
+						reportId: report._id,
 						thumbnail: song.thumbnail
 					}
 				});

+ 9 - 3
backend/logic/actions/users.js

@@ -1100,14 +1100,17 @@ export default {
 					}
 				});
 
-				if (preferences.nightmode !== user.preferences.nightmode)
+				if (preferences.nightmode !== undefined && preferences.nightmode !== user.preferences.nightmode)
 					ActivitiesModule.runJob("ADD_ACTIVITY", {
 						userId: session.userId,
 						type: "user__toggle_nightmode",
 						payload: { message: preferences.nightmode ? "Enabled nightmode" : "Disabled nightmode" }
 					});
 
-				if (preferences.autoSkipDisliked !== user.preferences.autoSkipDisliked)
+				if (
+					preferences.autoSkipDisliked !== undefined &&
+					preferences.autoSkipDisliked !== user.preferences.autoSkipDisliked
+				)
 					ActivitiesModule.runJob("ADD_ACTIVITY", {
 						userId: session.userId,
 						type: "user__toggle_autoskip_disliked_songs",
@@ -1118,7 +1121,10 @@ export default {
 						}
 					});
 
-				if (preferences.activityWatch !== user.preferences.activityWatch)
+				if (
+					preferences.activityWatch !== undefined &&
+					preferences.activityWatch !== user.preferences.activityWatch
+				)
 					ActivitiesModule.runJob("ADD_ACTIVITY", {
 						userId: session.userId,
 						type: "user__toggle_activity_watch",

+ 11 - 1
backend/logic/activities.js

@@ -44,6 +44,7 @@ class _ActivitiesModule extends CoreClass {
 	 * @param {string} payload.payload.message - the main message describing the activity e.g. 50 songs added to playlist 'playlist name'
 	 * @param {string} payload.payload.thumbnail - url to a thumbnail e.g. song album art to be used when display an activity
 	 * @param {string} payload.payload.youtubeId - (optional) if relevant, the youtube id of the song related to the activity
+	 * @param {string} payload.payload.reportId - (optional) if relevant, the id of the report related to the activity
 	 * @param {string} payload.payload.playlistId - (optional) if relevant, the id of the playlist related to the activity
 	 * @param {string} payload.payload.stationId - (optional) if relevant, the id of the station related to the activity
 	 * @returns {Promise} - returns promise (reject, resolve)
@@ -300,8 +301,9 @@ class _ActivitiesModule extends CoreClass {
 	 * Removes any references to a station, playlist or song in activities
 	 *
 	 * @param {object} payload - object that contains the payload
-	 * @param {string} payload.type - type of reference. enum: ["youtubeId", "stationId", "playlistId"]
+	 * @param {string} payload.type - type of reference. enum: ["youtubeId", "stationId", "playlistId", "playlistId"]
 	 * @param {string} payload.stationId - (optional) the id of a station
+	 * @param {string} payload.reportId - (optional) the id of a report
 	 * @param {string} payload.playlistId - (optional) the id of a playlist
 	 * @param {string} payload.youtubeId - (optional) the id of a song
 	 * @returns {Promise} - returns promise (reject, resolve)
@@ -316,6 +318,7 @@ class _ActivitiesModule extends CoreClass {
 						if (
 							(payload.type !== "youtubeId" &&
 								payload.type !== "stationId" &&
+								payload.type !== "reportId" &&
 								payload.type !== "playlistId") ||
 							!payload.type
 						)
@@ -351,6 +354,13 @@ class _ActivitiesModule extends CoreClass {
 									);
 								}
 
+								if (payload.reportId) {
+									activity.payload.message = activity.payload.message.replace(
+										/<reportId>(.*)<\/reportId>/g,
+										"$1"
+									);
+								}
+
 								if (payload.playlistId) {
 									activity.payload.message = activity.payload.message.replace(
 										/<playlistId>(.*)<\/playlistId>/g,

+ 2 - 1
backend/logic/db/schemas/activity.js

@@ -50,7 +50,8 @@ export default {
 		thumbnail: { type: String, required: false },
 		youtubeId: { type: String, required: false },
 		stationId: { type: String, required: false },
-		playlistId: { type: String, required: false }
+		playlistId: { type: String, required: false },
+		reportId: { type: String, required: false }
 	},
 	documentVersion: { type: Number, default: 2, required: true }
 };

+ 36 - 4
frontend/src/components/ActivityItem.vue

@@ -46,7 +46,12 @@ export default {
 	},
 	computed: {
 		formattedMessage() {
-			const { youtubeId, playlistId, stationId } = this.activity.payload;
+			const {
+				youtubeId,
+				playlistId,
+				stationId,
+				reportId
+			} = this.activity.payload;
 			let { message } = this.activity.payload;
 
 			if (youtubeId) {
@@ -56,6 +61,13 @@ export default {
 				);
 			}
 
+			if (reportId) {
+				message = message.replace(
+					/<reportId>(.*)<\/reportId>/g,
+					`<a href='#' class='activity-item-link' @click='showReport("${reportId}")'>report</a>`
+				);
+			}
+
 			if (playlistId) {
 				message = message.replace(
 					/<playlistId>(.*)<\/playlistId>/g,
@@ -72,13 +84,28 @@ export default {
 
 			return {
 				template: `<p>${message}</p>`,
-				methods: { showPlaylist: this.showPlaylist }
+				methods: {
+					showPlaylist: this.showPlaylist,
+					showReport: this.showReport
+				}
 			};
 		},
 		textOnlyMessage() {
-			const { youtubeId, playlistId, stationId } = this.activity.payload;
+			const {
+				youtubeId,
+				playlistId,
+				stationId,
+				reportId
+			} = this.activity.payload;
 			let { message } = this.activity.payload;
 
+			if (reportId) {
+				message = message.replace(
+					/<reportId>(.*)<\/reportId>/g,
+					"report"
+				);
+			}
+
 			if (youtubeId) {
 				message = message.replace(
 					/<youtubeId>(.*)<\/youtubeId>/g,
@@ -154,6 +181,10 @@ export default {
 
 			return icons[this.activity.type];
 		},
+		showReport(reportId) {
+			this.viewReport(reportId);
+			this.openModal("viewReport");
+		},
 		showPlaylist(playlistId) {
 			this.editPlaylist(playlistId);
 			this.openModal("editPlaylist");
@@ -161,7 +192,8 @@ export default {
 		...mapActions("user/playlists", ["editPlaylist"]),
 		formatDistance,
 		parseISO,
-		...mapActions("modalVisibility", ["openModal"])
+		...mapActions("modalVisibility", ["openModal"]),
+		...mapActions("modals/viewReport", ["viewReport"])
 	}
 };
 </script>

+ 21 - 0
frontend/src/components/Modal.vue

@@ -103,4 +103,25 @@ p {
 		column-gap: 16px;
 	}
 }
+
+@media screen and (max-width: 600px) {
+	.modal-card {
+		max-height: none;
+
+		.modal-card-body {
+			// padding: 0;
+		}
+
+		.modal-card-head,
+		.modal-card-foot {
+			border-radius: 0;
+		}
+	}
+}
+
+@media screen and (max-height: 650px) {
+	.modal-card {
+		height: 100%;
+	}
+}
 </style>

+ 5 - 1
frontend/src/components/ReportInfoItem.vue

@@ -18,6 +18,7 @@
 						path: `/u/${createdBy.username}`
 					}"
 					:title="createdBy._id"
+					@click="closeModal('viewReport')"
 				>
 					{{ createdBy.username }}
 				</router-link>
@@ -39,7 +40,9 @@
 </template>
 
 <script>
+import { mapActions } from "vuex";
 import { formatDistance } from "date-fns";
+
 import ProfilePicture from "@/components/ProfilePicture.vue";
 
 export default {
@@ -49,7 +52,8 @@ export default {
 		createdAt: { type: String, default: "" }
 	},
 	methods: {
-		formatDistance
+		formatDistance,
+		...mapActions("modalVisibility", ["closeModal"])
 	}
 };
 </script>

+ 12 - 1
frontend/src/components/modals/Login.vue

@@ -39,6 +39,7 @@
 								type="password"
 								ref="password"
 								placeholder="Password..."
+								@input="checkForAutofill($event)"
 								@keypress="submitOnEnter(submitModal, $event)"
 							/>
 							<a @click="togglePasswordVisibility()">
@@ -143,7 +144,17 @@ export default {
 		if (this.$route.path === "/login") this.isPage = true;
 	},
 	methods: {
-		submitOnEnter: (cb, event) => {
+		checkForAutofill(event) {
+			if (
+				event.target.value !== "" &&
+				event.inputType === undefined &&
+				event.data === undefined &&
+				event.dataTransfer === undefined &&
+				event.isComposing === undefined
+			)
+				this.submitModal();
+		},
+		submitOnEnter(cb, event) {
 			if (event.which === 13) cb();
 		},
 		submitModal() {

+ 48 - 10
frontend/src/components/modals/Report.vue

@@ -193,7 +193,7 @@
 				</a>
 			</template>
 		</modal>
-		<view-report v-if="modals.viewReport" :report-id="viewingReportId" />
+		<view-report v-if="modals.viewReport" />
 	</div>
 </template>
 
@@ -210,7 +210,6 @@ export default {
 	components: { Modal, ViewReport, SongItem, ReportInfoItem },
 	data() {
 		return {
-			viewingReportId: "",
 			icons: {
 				duration: "timer",
 				video: "tv",
@@ -353,13 +352,30 @@ export default {
 	},
 	mounted() {
 		this.socket.dispatch("reports.myReportsForSong", this.song._id, res => {
-			if (res.status === "success")
+			if (res.status === "success") {
 				this.existingReports = res.data.reports;
+				this.existingReports.forEach(report =>
+					this.socket.dispatch(
+						"apis.joinRoom",
+						`view-report.${report._id}`
+					)
+				);
+			}
 		});
+
+		this.socket.on(
+			"event:admin.report.resolved",
+			res => {
+				this.existingReports = this.existingReports.filter(
+					report => report._id !== res.data.reportId
+				);
+			},
+			{ modal: "report" }
+		);
 	},
 	methods: {
 		view(reportId) {
-			this.viewingReportId = reportId;
+			this.viewReport(reportId);
 			this.openModal("viewReport");
 		},
 		create() {
@@ -397,8 +413,8 @@ export default {
 				}
 			);
 		},
-		...mapActions("modals/report", ["reportSong"]),
-		...mapActions("modalVisibility", ["openModal", "closeModal"])
+		...mapActions("modalVisibility", ["openModal", "closeModal"]),
+		...mapActions("modals/viewReport", ["viewReport"])
 	}
 };
 </script>
@@ -420,19 +436,41 @@ export default {
 </style>
 
 <style lang="scss" scoped>
+.night-mode {
+	@media screen and (max-width: 900px) {
+		#right-part {
+			background-color: var(--dark-grey-3) !important;
+		}
+	}
+}
+
 .report-modal-inner-container {
 	display: flex;
 
+	@media screen and (max-width: 900px) {
+		flex-wrap: wrap-reverse;
+
+		#left-part {
+			width: 100%;
+		}
+
+		#right-part {
+			border-left: 0 !important;
+			margin-left: 0 !important;
+			width: 100%;
+			min-width: 0 !important;
+			margin-bottom: 20px;
+			padding: 20px;
+			background-color: var(--light-grey);
+		}
+	}
+
 	#right-part {
 		border-left: 1px solid var(--light-grey-3);
 		padding-left: 20px;
 		margin-left: 20px;
 		min-width: 325px;
 
-		@media screen and (max-width: 900px) {
-			display: none;
-		}
-
 		.report-items {
 			max-height: 485px;
 			overflow: auto;

+ 11 - 9
frontend/src/components/modals/ViewReport.vue

@@ -54,7 +54,7 @@
 								content="Resolve"
 								v-tippy
 								v-if="!issue.resolved"
-								@click="toggleIssue(report._id, issue._id)"
+								@click="toggleIssue(issue._id)"
 							>
 								done
 							</i>
@@ -63,7 +63,7 @@
 								content="Unresolve"
 								v-tippy
 								v-else
-								@click="toggleIssue(report._id, issue._id)"
+								@click="toggleIssue(issue._id)"
 							>
 								remove
 							</i>
@@ -83,7 +83,7 @@
 				</i>
 				Edit Song
 			</a>
-			<a class="button is-success" href="#" @click="resolve(report._id)">
+			<a class="button is-success" href="#" @click="resolve()">
 				<i
 					class="material-icons icon-with-button"
 					content="Resolve"
@@ -98,7 +98,7 @@
 </template>
 
 <script>
-import { mapActions, mapGetters } from "vuex";
+import { mapActions, mapGetters, mapState } from "vuex";
 import Toast from "toasters";
 
 import Modal from "@/components/Modal.vue";
@@ -108,7 +108,6 @@ import ReportInfoItem from "@/components/ReportInfoItem.vue";
 export default {
 	components: { Modal, SongItem, ReportInfoItem },
 	props: {
-		reportId: { type: String, default: "" },
 		sector: { type: String, default: "admin" }
 	},
 	data() {
@@ -126,6 +125,9 @@ export default {
 		};
 	},
 	computed: {
+		...mapState("modals/viewReport", {
+			reportId: state => state.viewingReportId
+		}),
 		...mapGetters({
 			socket: "websockets/getSocket"
 		})
@@ -185,17 +187,17 @@ export default {
 		this.socket.dispatch("apis.leaveRoom", `view-report.${this.reportId}`);
 	},
 	methods: {
-		resolve(reportId) {
-			return this.resolveReport(reportId)
+		resolve() {
+			return this.resolveReport(this.reportId)
 				.then(res => {
 					if (res.status === "success") this.closeModal("viewReport");
 				})
 				.catch(err => new Toast(err.message));
 		},
-		toggleIssue(reportId, issueId) {
+		toggleIssue(issueId) {
 			this.socket.dispatch(
 				"reports.toggleIssue",
-				reportId,
+				this.reportId,
 				issueId,
 				res => {
 					if (res.status !== "success") new Toast(res.message);

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

@@ -78,11 +78,7 @@
 			</table>
 		</div>
 
-		<view-report
-			v-if="modals.viewReport"
-			:report-id="viewingReportId"
-			sector="admin"
-		/>
+		<view-report v-if="modals.viewReport" sector="admin" />
 
 		<edit-song v-if="modals.editSong" song-type="songs" />
 	</div>
@@ -108,7 +104,6 @@ export default {
 	},
 	data() {
 		return {
-			viewingReportId: "",
 			reports: []
 		};
 	},
@@ -164,7 +159,7 @@ export default {
 			return categories;
 		},
 		view(reportId) {
-			this.viewingReportId = reportId;
+			this.viewReport(reportId);
 			this.openModal("viewReport");
 		},
 		resolve(reportId) {
@@ -176,7 +171,8 @@ export default {
 				.catch(err => new Toast(err.message));
 		},
 		...mapActions("modalVisibility", ["openModal", "closeModal"]),
-		...mapActions("admin/reports", ["resolveReport"])
+		...mapActions("admin/reports", ["resolveReport"]),
+		...mapActions("modals/viewReport", ["viewReport"])
 	}
 };
 </script>

+ 4 - 0
frontend/src/pages/Profile/index.vue

@@ -2,6 +2,7 @@
 	<div v-if="isUser">
 		<edit-playlist v-if="modals.editPlaylist" />
 		<report v-if="modals.report" />
+		<view-report v-if="modals.viewReport" />
 		<edit-song v-if="modals.editSong" song-type="songs" />
 
 		<metadata :title="`Profile | ${user.username}`" />
@@ -131,6 +132,9 @@ export default {
 		Report: defineAsyncComponent(() =>
 			import("@/components/modals/Report.vue")
 		),
+		ViewReport: defineAsyncComponent(() =>
+			import("@/components/modals/ViewReport.vue")
+		),
 		EditSong: defineAsyncComponent(() =>
 			import("@/components/modals/EditSong")
 		)

+ 1 - 1
frontend/src/pages/ResetPassword.vue

@@ -78,7 +78,7 @@
 						</h2>
 						<p
 							class="content-box-description"
-							v-if="!this.email.hasBeenSentAlready"
+							v-if="!email.hasBeenSentAlready"
 						>
 							A code has been sent to
 							<strong>{{ email.value }}.</strong>

+ 3 - 1
frontend/src/store/index.js

@@ -15,6 +15,7 @@ import editPlaylistModal from "./modules/modals/editPlaylist";
 import manageStationModal from "./modules/modals/manageStation";
 import editUserModal from "./modules/modals/editUser";
 import viewPunishmentModal from "./modules/modals/viewPunishment";
+import viewReportModal from "./modules/modals/viewReport";
 import reportModal from "./modules/modals/report";
 
 export default createStore({
@@ -34,7 +35,8 @@ export default createStore({
 				manageStation: manageStationModal,
 				editUser: editUserModal,
 				viewPunishment: viewPunishmentModal,
-				report: reportModal
+				report: reportModal,
+				viewReport: viewReportModal
 			}
 		}
 	},

+ 16 - 0
frontend/src/store/modules/modals/viewReport.js

@@ -0,0 +1,16 @@
+/* eslint no-param-reassign: 0 */
+
+export default {
+	namespaced: true,
+	state: {
+		viewingReportId: ""
+	},
+	actions: {
+		viewReport: ({ commit }, reportId) => commit("viewReport", reportId)
+	},
+	mutations: {
+		viewReport(state, reportId) {
+			state.viewingReportId = reportId;
+		}
+	}
+};