1
0
Эх сурвалжийг харах

Merge remote-tracking branch 'origin/polishing' into owen

Owen Diffey 3 жил өмнө
parent
commit
38a1a9a236

+ 44 - 28
backend/logic/actions/punishments.js

@@ -60,40 +60,56 @@ export default {
 	}),
 	}),
 
 
 	/**
 	/**
-	 * Gets a punishment by id
+	 * Gets all punishments for a user
+	 *
+	 * @param {object} session - the session object automatically added by the websocket
+	 * @param {string} userId - the id of the user
+	 * @param {Function} cb - gets called with the result
+	 */
+	getPunishmentsForUser: isAdminRequired(async function getPunishmentsForUser(session, userId, cb) {
+		const punishmentModel = await DBModule.runJob("GET_MODEL", { modelName: "punishment" }, this);
+
+		punishmentModel.find({ type: "banUserId", value: userId }, async (err, punishments) => {
+			if (err) {
+				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+
+				this.log(
+					"ERROR",
+					"GET_PUNISHMENTS_FOR_USER",
+					`Getting punishments for user ${userId} failed. "${err}"`
+				);
+
+				return cb({ status: "error", message: err });
+			}
+
+			this.log("SUCCESS", "GET_PUNISHMENTS_FOR_USER", `Got punishments for user ${userId} successful.`);
+			return cb({ status: "success", data: { punishments } });
+		});
+	}),
+
+	/**
+	 * Returns a punishment by id
 	 *
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {string} punishmentId - the punishment id
 	 * @param {string} punishmentId - the punishment id
 	 * @param {Function} cb - gets called with the result
 	 * @param {Function} cb - gets called with the result
 	 */
 	 */
-	getPunishmentById: isAdminRequired(async function index(session, punishmentId, cb) {
-		const punishmentModel = await DBModule.runJob(
-			"GET_MODEL",
-			{
-				modelName: "punishment"
-			},
-			this
-		);
-		async.waterfall(
-			[
-				next => {
-					punishmentModel.findOne({ _id: punishmentId }, next);
-				}
-			],
-			async (err, punishment) => {
-				if (err) {
-					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
-					this.log(
-						"ERROR",
-						"GET_PUNISHMENT_BY_ID",
-						`Getting punishment with id ${punishmentId} failed. "${err}"`
-					);
-					return cb({ status: "error", message: err });
-				}
-				this.log("SUCCESS", "GET_PUNISHMENT_BY_ID", `Got punishment with id ${punishmentId} successful.`);
-				return cb({ status: "success", data: { punishment } });
+	findOne: isAdminRequired(async function findOne(session, punishmentId, cb) {
+		const punishmentModel = await DBModule.runJob("GET_MODEL", { modelName: "punishment" }, this);
+
+		async.waterfall([next => punishmentModel.findOne({ _id: punishmentId }, next)], async (err, punishment) => {
+			if (err) {
+				err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+				this.log(
+					"ERROR",
+					"GET_PUNISHMENT_BY_ID",
+					`Getting punishment with id ${punishmentId} failed. "${err}"`
+				);
+				return cb({ status: "error", message: err });
 			}
 			}
-		);
+			this.log("SUCCESS", "GET_PUNISHMENT_BY_ID", `Got punishment with id ${punishmentId} successful.`);
+			return cb({ status: "success", data: { punishment } });
+		});
 	}),
 	}),
 
 
 	/**
 	/**

+ 1 - 1
backend/logic/actions/users.js

@@ -2545,7 +2545,7 @@ export default {
 							value: userId,
 							value: userId,
 							reason,
 							reason,
 							expiresAt,
 							expiresAt,
-							punishedBy: "" // needs changed
+							punishedBy: session.userId
 						},
 						},
 						this
 						this
 					)
 					)

+ 156 - 0
frontend/src/components/PunishmentItem.vue

@@ -0,0 +1,156 @@
+<template>
+	<div class="universal-item punishment-item">
+		<div class="item-icon">
+			<p class="is-expanded checkbox-control">
+				<label class="switch">
+					<input type="checkbox" v-model="active" disabled />
+					<span class="slider round"></span>
+				</label>
+			</p>
+			<p>
+				<strong>{{ active ? "Active" : "Inactive" }}</strong>
+			</p>
+		</div>
+
+		<div class="item-title-description">
+			<h2 v-if="punishment.type === 'banUserId'" class="item-title">
+				<strong>Punishment</strong> for user
+				<user-id-to-username
+					:user-id="punishment.value"
+					:alt="punishment.value"
+					:link="true"
+				/>
+			</h2>
+			<h2 class="item-title" v-else>
+				<strong>Punishment</strong> for IP
+				{{ punishment.value }}
+			</h2>
+			<h3 class="item-title-2">Reason: {{ punishment.reason }}</h3>
+			<ul>
+				<li class="item-description" :title="punishment.expiresAt">
+					Expires
+					{{
+						formatDistance(
+							parseISO(punishment.expiresAt),
+							new Date(),
+							{ addSuffix: true }
+						)
+					}}
+					({{
+						format(
+							parseISO(punishment.expiresAt),
+							"MMMM do yyyy, h:mm:ss a"
+						)
+					}})
+				</li>
+				<li class="item-description">
+					Punished by
+					<user-id-to-username
+						:user-id="punishment.punishedBy"
+						:alt="punishment.punishedBy"
+					/>
+
+					<span :title="punishment.punishedAt">
+						&nbsp;{{
+							formatDistance(
+								parseISO(punishment.punishedAt),
+								new Date(),
+								{ addSuffix: true }
+							)
+						}}
+						({{
+							format(
+								parseISO(punishment.punishedAt),
+								"MMMM do yyyy, h:mm:ss a"
+							)
+						}})
+					</span>
+				</li>
+			</ul>
+		</div>
+	</div>
+</template>
+
+<script>
+import { mapActions } from "vuex";
+import { format, formatDistance, parseISO } from "date-fns";
+
+import UserIdToUsername from "@/components/UserIdToUsername.vue";
+
+export default {
+	components: { UserIdToUsername },
+	props: {
+		punishment: { type: Object, default: () => {} }
+	},
+	data() {
+		return {
+			active: false
+		};
+	},
+	watch: {
+		punishment(punishment) {
+			this.active =
+				punishment.active &&
+				new Date(this.punishment.expiresAt).getTime() > Date.now();
+		}
+	},
+	methods: {
+		formatDistance,
+		format,
+		parseISO,
+		...mapActions("modalVisibility", ["closeModal"])
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.night-mode {
+	.punishment-item {
+		background-color: var(--dark-grey-2) !important;
+		border: 0 !important;
+	}
+}
+
+.punishment-item {
+	padding: 15px;
+	justify-content: flex-start;
+
+	.item-icon {
+		min-width: 85px;
+		max-width: 85px;
+		height: 85px;
+		margin-left: 20px;
+		margin-right: 35px;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-evenly;
+		border: 1px solid var(--light-grey-3);
+		border-radius: 5px;
+
+		.checkbox-control .slider {
+			cursor: default;
+		}
+	}
+
+	.item-title {
+		font-size: 19px;
+		margin: 0;
+	}
+
+	.item-title-2 {
+		font-size: 17px;
+		margin: 0;
+	}
+
+	ul {
+		list-style: inside;
+		margin-top: 10px;
+
+		.item-description {
+			font-size: 14px;
+			margin: 0;
+		}
+	}
+}
+</style>

+ 5 - 2
frontend/src/components/modals/EditNews.vue

@@ -45,8 +45,11 @@
 						<user-id-to-username
 						<user-id-to-username
 							:user-id="createdBy"
 							:user-id="createdBy"
 							:alt="createdBy"
 							:alt="createdBy"
-							:link="true" /></span
-					><span :title="new Date(createdAt)">
+							:link="true"
+						/>
+						&nbsp;
+					</span>
+					<span :title="new Date(createdAt)">
 						{{
 						{{
 							formatDistance(createdAt, new Date(), {
 							formatDistance(createdAt, new Date(), {
 								addSuffix: true
 								addSuffix: true

+ 82 - 58
frontend/src/components/modals/EditUser.vue

@@ -2,64 +2,78 @@
 	<div>
 	<div>
 		<modal title="Edit User">
 		<modal title="Edit User">
 			<template #body v-if="user && user._id">
 			<template #body v-if="user && user._id">
-				<p class="control has-addons">
-					<input
-						v-model="user.username"
-						class="input is-expanded"
-						type="text"
-						placeholder="Username"
-						autofocus
-					/>
-					<a class="button is-info" @click="updateUsername()"
-						>Update Username</a
-					>
-				</p>
-				<p class="control has-addons">
-					<input
-						v-model="user.email.address"
-						class="input is-expanded"
-						type="text"
-						placeholder="Email Address"
-						autofocus
-					/>
-					<a class="button is-info" @click="updateEmail()"
-						>Update Email Address</a
-					>
-				</p>
-				<p class="control has-addons">
-					<span class="select">
-						<select v-model="user.role">
-							<option>default</option>
-							<option>admin</option>
-						</select>
-					</span>
-					<a class="button is-info" @click="updateRole()"
-						>Update Role</a
-					>
-				</p>
-				<hr />
-				<p class="control has-addons">
-					<span class="select">
-						<select v-model="ban.expiresAt">
-							<option value="1h">1 Hour</option>
-							<option value="12h">12 Hours</option>
-							<option value="1d">1 Day</option>
-							<option value="1w">1 Week</option>
-							<option value="1m">1 Month</option>
-							<option value="3m">3 Months</option>
-							<option value="6m">6 Months</option>
-							<option value="1y">1 Year</option>
-						</select>
-					</span>
-					<input
-						v-model="ban.reason"
-						class="input is-expanded"
-						type="text"
-						placeholder="Ban reason"
-						autofocus
-					/>
-					<a class="button is-error" @click="banUser()">Ban user</a>
-				</p>
+				<div class="section">
+					<label class="label"> Change username </label>
+					<p class="control has-addons">
+						<input
+							v-model="user.username"
+							class="input is-expanded"
+							type="text"
+							placeholder="Username"
+							autofocus
+						/>
+						<a class="button is-info" @click="updateUsername()"
+							>Update Username</a
+						>
+					</p>
+
+					<label class="label"> Change email address </label>
+					<p class="control has-addons">
+						<input
+							v-model="user.email.address"
+							class="input is-expanded"
+							type="text"
+							placeholder="Email Address"
+							autofocus
+						/>
+						<a class="button is-info" @click="updateEmail()"
+							>Update Email Address</a
+						>
+					</p>
+
+					<label class="label"> Change user role </label>
+					<div class="control is-grouped input-with-button">
+						<div class="control is-expanded select">
+							<select v-model="user.role">
+								<option>default</option>
+								<option>admin</option>
+							</select>
+						</div>
+						<p class="control">
+							<a class="button is-info" @click="updateRole()"
+								>Update Role</a
+							>
+						</p>
+					</div>
+				</div>
+
+				<div class="section">
+					<label class="label"> Punish/Ban User </label>
+					<p class="control has-addons">
+						<span class="select">
+							<select v-model="ban.expiresAt">
+								<option value="1h">1 Hour</option>
+								<option value="12h">12 Hours</option>
+								<option value="1d">1 Day</option>
+								<option value="1w">1 Week</option>
+								<option value="1m">1 Month</option>
+								<option value="3m">3 Months</option>
+								<option value="6m">6 Months</option>
+								<option value="1y">1 Year</option>
+							</select>
+						</span>
+						<input
+							v-model="ban.reason"
+							class="input is-expanded"
+							type="text"
+							placeholder="Ban reason"
+							autofocus
+						/>
+						<a class="button is-danger" @click="banUser()">
+							Ban user
+						</a>
+					</p>
+				</div>
 			</template>
 			</template>
 			<template #footer>
 			<template #footer>
 				<!--button class='button is-warning'>
 				<!--button class='button is-warning'>
@@ -122,10 +136,12 @@ export default {
 		},
 		},
 		updateUsername() {
 		updateUsername() {
 			const { username } = this.user;
 			const { username } = this.user;
+
 			if (!validation.isLength(username, 2, 32))
 			if (!validation.isLength(username, 2, 32))
 				return new Toast(
 				return new Toast(
 					"Username must have between 2 and 32 characters."
 					"Username must have between 2 and 32 characters."
 				);
 				);
+
 			if (!validation.regex.custom("a-zA-Z0-9_-").test(username))
 			if (!validation.regex.custom("a-zA-Z0-9_-").test(username))
 				return new Toast(
 				return new Toast(
 					"Invalid username format. Allowed characters: a-z, A-Z, 0-9, _ and -."
 					"Invalid username format. Allowed characters: a-z, A-Z, 0-9, _ and -."
@@ -142,10 +158,12 @@ export default {
 		},
 		},
 		updateEmail() {
 		updateEmail() {
 			const email = this.user.email.address;
 			const email = this.user.email.address;
+
 			if (!validation.isLength(email, 3, 254))
 			if (!validation.isLength(email, 3, 254))
 				return new Toast(
 				return new Toast(
 					"Email must have between 3 and 254 characters."
 					"Email must have between 3 and 254 characters."
 				);
 				);
+
 			if (
 			if (
 				email.indexOf("@") !== email.lastIndexOf("@") ||
 				email.indexOf("@") !== email.lastIndexOf("@") ||
 				!validation.regex.emailSimple.test(email) ||
 				!validation.regex.emailSimple.test(email) ||
@@ -174,10 +192,12 @@ export default {
 		},
 		},
 		banUser() {
 		banUser() {
 			const { reason } = this.ban;
 			const { reason } = this.ban;
+
 			if (!validation.isLength(reason, 1, 64))
 			if (!validation.isLength(reason, 1, 64))
 				return new Toast(
 				return new Toast(
 					"Reason must have between 1 and 64 characters."
 					"Reason must have between 1 and 64 characters."
 				);
 				);
+
 			if (!validation.regex.ascii.test(reason))
 			if (!validation.regex.ascii.test(reason))
 				return new Toast(
 				return new Toast(
 					"Invalid reason format. Only ascii characters are allowed."
 					"Invalid reason format. Only ascii characters are allowed."
@@ -205,6 +225,10 @@ export default {
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
+.section {
+	padding: 15px 0 !important;
+}
+
 .save-changes {
 .save-changes {
 	color: var(--white);
 	color: var(--white);
 }
 }

+ 1 - 1
frontend/src/components/modals/Report.vue

@@ -155,7 +155,7 @@
 									? "multiple reports"
 									? "multiple reports"
 									: "a report"
 									: "a report"
 							}}
 							}}
-							about this song already.
+							about this song already
 						</p>
 						</p>
 
 
 						<hr class="section-horizontal-rule" />
 						<hr class="section-horizontal-rule" />

+ 2 - 2
frontend/src/components/modals/RequestSong.vue

@@ -6,7 +6,7 @@
 
 
 				<h4 class="section-title">Choose a song</h4>
 				<h4 class="section-title">Choose a song</h4>
 				<p class="section-description">
 				<p class="section-description">
-					Choose a song by searching or using a link from YouTube.
+					Choose a song by searching or using a link from YouTube
 				</p>
 				</p>
 
 
 				<br />
 				<br />
@@ -89,7 +89,7 @@
 
 
 					<h4 class="section-title">Import a playlist</h4>
 					<h4 class="section-title">Import a playlist</h4>
 					<p class="section-description">
 					<p class="section-description">
-						Import a playlist by using a link from YouTube.
+						Import a playlist by using a link from YouTube
 					</p>
 					</p>
 
 
 					<br />
 					<br />

+ 5 - 56
frontend/src/components/modals/ViewPunishment.vue

@@ -2,58 +2,7 @@
 	<div>
 	<div>
 		<modal title="View Punishment">
 		<modal title="View Punishment">
 			<template #body v-if="punishment && punishment._id">
 			<template #body v-if="punishment && punishment._id">
-				<article class="message">
-					<div class="message-body">
-						<strong>Type:</strong>
-						{{ punishment.type }}
-						<br />
-						<strong>Value:</strong>
-						{{ punishment.value }}
-						<br />
-						<strong>Reason:</strong>
-						{{ punishment.reason }}
-						<br />
-						<strong>Active:</strong>
-						{{ punishment.active }}
-						<br />
-						<strong>Expires at:</strong>
-						{{
-							format(
-								parseISO(punishment.expiresAt),
-								"MMMM do yyyy, h:mm:ss a"
-							)
-						}}
-						({{
-							formatDistance(
-								parseISO(punishment.expiresAt),
-								new Date(),
-								{ addSuffix: true }
-							)
-						}})
-						<br />
-						<strong>Punished at:</strong>
-						{{
-							format(
-								parseISO(punishment.punishedAt),
-								"MMMM do yyyy, h:mm:ss a"
-							)
-						}}
-						({{
-							formatDistance(
-								parseISO(punishment.punishedAt),
-								new Date(),
-								{ addSuffix: true }
-							)
-						}})
-						<br />
-						<strong>Punished by:</strong>
-						<user-id-to-username
-							:user-id="punishment.punishedBy"
-							:alt="punishment.punishedBy"
-						/>
-						<br />
-					</div>
-				</article>
+				<punishment-item :punishment="punishment" />
 			</template>
 			</template>
 		</modal>
 		</modal>
 	</div>
 	</div>
@@ -61,15 +10,15 @@
 
 
 <script>
 <script>
 import { mapState, mapGetters, mapActions } from "vuex";
 import { mapState, mapGetters, mapActions } from "vuex";
-import { format, formatDistance, parseISO } from "date-fns"; // eslint-disable-line no-unused-vars
+import { format, formatDistance, parseISO } from "date-fns";
 import ws from "@/ws";
 import ws from "@/ws";
 
 
 import Toast from "toasters";
 import Toast from "toasters";
 import Modal from "../Modal.vue";
 import Modal from "../Modal.vue";
-import UserIdToUsername from "../UserIdToUsername.vue";
+import PunishmentItem from "../PunishmentItem.vue";
 
 
 export default {
 export default {
-	components: { Modal, UserIdToUsername },
+	components: { Modal, PunishmentItem },
 	props: {
 	props: {
 		punishmentId: { type: String, default: "" },
 		punishmentId: { type: String, default: "" },
 		sector: { type: String, default: "admin" }
 		sector: { type: String, default: "admin" }
@@ -93,7 +42,7 @@ export default {
 	methods: {
 	methods: {
 		init() {
 		init() {
 			this.socket.dispatch(
 			this.socket.dispatch(
-				`punishments.getPunishmentById`,
+				`punishments.findOne`,
 				this.punishmentId,
 				this.punishmentId,
 				res => {
 				res => {
 					if (res.status === "success") {
 					if (res.status === "success") {

+ 9 - 1
frontend/src/pages/Admin/tabs/News.vue

@@ -26,7 +26,7 @@
 							/>
 							/>
 						</td>
 						</td>
 						<td class="news-item-markdown">{{ news.markdown }}</td>
 						<td class="news-item-markdown">{{ news.markdown }}</td>
-						<td>
+						<td id="options-column">
 							<button
 							<button
 								class="button is-primary"
 								class="button is-primary"
 								@click="edit(news._id)"
 								@click="edit(news._id)"
@@ -205,4 +205,12 @@ td {
 	overflow: hidden;
 	overflow: hidden;
 	max-width: 400px;
 	max-width: 400px;
 }
 }
+
+#options-column {
+	display: flex;
+
+	button {
+		margin-right: 5px;
+	}
+}
 </style>
 </style>

+ 28 - 9
frontend/src/pages/Admin/tabs/Punishments.vue

@@ -5,10 +5,10 @@
 			<table class="table is-striped">
 			<table class="table is-striped">
 				<thead>
 				<thead>
 					<tr>
 					<tr>
+						<td>Status</td>
 						<td>Type</td>
 						<td>Type</td>
 						<td>Value</td>
 						<td>Value</td>
 						<td>Reason</td>
 						<td>Reason</td>
-						<td>Status</td>
 						<td>Options</td>
 						<td>Options</td>
 					</tr>
 					</tr>
 				</thead>
 				</thead>
@@ -17,10 +17,6 @@
 						v-for="punishment in sortedPunishments"
 						v-for="punishment in sortedPunishments"
 						:key="punishment._id"
 						:key="punishment._id"
 					>
 					>
-						<td v-if="punishment.type === 'banUserId'">User ID</td>
-						<td v-else>IP Address</td>
-						<td>{{ punishment.value }}</td>
-						<td>{{ punishment.reason }}</td>
 						<td>
 						<td>
 							{{
 							{{
 								punishment.active &&
 								punishment.active &&
@@ -30,13 +26,33 @@
 									: "Inactive"
 									: "Inactive"
 							}}
 							}}
 						</td>
 						</td>
+						<td v-if="punishment.type === 'banUserId'">User ID</td>
+						<td v-else>IP Address</td>
+						<td v-if="punishment.type === 'banUserId'">
+							<user-id-to-username
+								:user-id="punishment.value"
+								:alt="punishment.value"
+								:link="true"
+							/>
+							({{ punishment.value }})
+						</td>
+						<td v-else>
+							{{ punishment.value }}
+						</td>
+						<td>{{ punishment.reason }}</td>
+
 						<td>
 						<td>
-							<button
+							<a
 								class="button is-primary"
 								class="button is-primary"
 								@click="view(punishment)"
 								@click="view(punishment)"
+								content="Expand"
+								v-tippy
 							>
 							>
-								View
-							</button>
+								<i class="material-icons icon-with-button">
+									open_in_full
+								</i>
+								Expand
+							</a>
 						</td>
 						</td>
 					</tr>
 					</tr>
 				</tbody>
 				</tbody>
@@ -100,11 +116,14 @@ import { defineAsyncComponent } from "vue";
 
 
 import ws from "@/ws";
 import ws from "@/ws";
 
 
+import UserIdToUsername from "@/components/UserIdToUsername.vue";
+
 export default {
 export default {
 	components: {
 	components: {
 		ViewPunishment: defineAsyncComponent(() =>
 		ViewPunishment: defineAsyncComponent(() =>
 			import("@/components/modals/ViewPunishment.vue")
 			import("@/components/modals/ViewPunishment.vue")
-		)
+		),
+		UserIdToUsername
 	},
 	},
 	data() {
 	data() {
 		return {
 		return {

+ 1 - 1
frontend/src/pages/Profile/Tabs/Playlists.vue

@@ -15,7 +15,7 @@
 						? "and manage your personal"
 						? "and manage your personal"
 						: `${username}'s`
 						: `${username}'s`
 				}}
 				}}
-				playlists.
+				playlists
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />

+ 1 - 1
frontend/src/pages/Profile/Tabs/RecentActivity.vue

@@ -6,7 +6,7 @@
 			<p class="section-description">
 			<p class="section-description">
 				This is a log of all actions
 				This is a log of all actions
 				{{ userId === myUserId ? "you have" : `${username} has` }}
 				{{ userId === myUserId ? "you have" : `${username} has` }}
-				taken recently.
+				taken recently
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />

+ 2 - 2
frontend/src/pages/Settings/Tabs/Account.vue

@@ -2,7 +2,7 @@
 	<div class="content account-tab">
 	<div class="content account-tab">
 		<h4 class="section-title">Change account details</h4>
 		<h4 class="section-title">Change account details</h4>
 
 
-		<p class="section-description">Keep these details up-to-date.</p>
+		<p class="section-description">Keep these details up-to-date</p>
 
 
 		<hr class="section-horizontal-rule" />
 		<hr class="section-horizontal-rule" />
 
 
@@ -70,7 +70,7 @@
 		<h4 class="section-title">Remove any data we hold on you</h4>
 		<h4 class="section-title">Remove any data we hold on you</h4>
 
 
 		<p class="section-description">
 		<p class="section-description">
-			Permanently remove your account and/or data we store on you.
+			Permanently remove your account and/or data we store on you
 		</p>
 		</p>
 
 
 		<hr class="section-horizontal-rule" />
 		<hr class="section-horizontal-rule" />

+ 1 - 1
frontend/src/pages/Settings/Tabs/Preferences.vue

@@ -2,7 +2,7 @@
 	<div class="content preferences-tab">
 	<div class="content preferences-tab">
 		<h4 class="section-title">Change preferences</h4>
 		<h4 class="section-title">Change preferences</h4>
 
 
-		<p class="section-description">Tailor these settings to your liking.</p>
+		<p class="section-description">Tailor these settings to your liking</p>
 
 
 		<hr class="section-horizontal-rule" />
 		<hr class="section-horizontal-rule" />
 
 

+ 1 - 1
frontend/src/pages/Settings/Tabs/Profile.vue

@@ -2,7 +2,7 @@
 	<div class="content profile-tab">
 	<div class="content profile-tab">
 		<h4 class="section-title">Change Profile</h4>
 		<h4 class="section-title">Change Profile</h4>
 		<p class="section-description">
 		<p class="section-description">
-			Edit your public profile so users can find out more about you.
+			Edit your public profile so users can find out more about you
 		</p>
 		</p>
 
 
 		<hr class="section-horizontal-rule" />
 		<hr class="section-horizontal-rule" />

+ 5 - 5
frontend/src/pages/Settings/Tabs/Security.vue

@@ -4,7 +4,7 @@
 			<h4 class="section-title">Change password</h4>
 			<h4 class="section-title">Change password</h4>
 
 
 			<p class="section-description">
 			<p class="section-description">
-				You will need to know your previous password.
+				You will need to know your previous password
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />
@@ -85,7 +85,7 @@
 		<div v-if="!isPasswordLinked">
 		<div v-if="!isPasswordLinked">
 			<h4 class="section-title">Add a password</h4>
 			<h4 class="section-title">Add a password</h4>
 			<p class="section-description">
 			<p class="section-description">
-				Add a password, as an alternative to signing in with GitHub.
+				Add a password, as an alternative to signing in with GitHub
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />
@@ -101,7 +101,7 @@
 		<div v-if="!isGithubLinked">
 		<div v-if="!isGithubLinked">
 			<h4 class="section-title">Link your GitHub account</h4>
 			<h4 class="section-title">Link your GitHub account</h4>
 			<p class="section-description">
 			<p class="section-description">
-				Link your Musare account with GitHub.
+				Link your Musare account with GitHub
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />
@@ -119,7 +119,7 @@
 		<div v-if="isPasswordLinked && isGithubLinked">
 		<div v-if="isPasswordLinked && isGithubLinked">
 			<h4 class="section-title">Remove login methods</h4>
 			<h4 class="section-title">Remove login methods</h4>
 			<p class="section-description">
 			<p class="section-description">
-				Remove your password as a login method or unlink GitHub.
+				Remove your password as a login method or unlink GitHub
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />
@@ -145,7 +145,7 @@
 		<div>
 		<div>
 			<h4 class="section-title">Log out everywhere</h4>
 			<h4 class="section-title">Log out everywhere</h4>
 			<p class="section-description">
 			<p class="section-description">
-				Remove all currently logged-in sessions for your account.
+				Remove all currently logged-in sessions for your account
 			</p>
 			</p>
 
 
 			<hr class="section-horizontal-rule" />
 			<hr class="section-horizontal-rule" />