Parcourir la source

User management

Pitu il y a 6 ans
Parent
commit
7a74647d3e

+ 3 - 3
src/api/routes/admin/userDemote.js

@@ -2,13 +2,13 @@ const Route = require('../../structures/Route');
 
 class userDemote extends Route {
 	constructor() {
-		super('/admin/users/demote', 'get', { adminOnly: true });
+		super('/admin/users/demote', 'post', { adminOnly: true });
 	}
 
 	async run(req, res, db) {
 		if (!req.body) return res.status(400).json({ message: 'No body provided' });
 		const { id } = req.body;
-		if (!id) return res.status(400).json({ message: 'No name provided' });
+		if (!id) return res.status(400).json({ message: 'No id provided' });
 
 		try {
 			await db.table('users')
@@ -19,7 +19,7 @@ class userDemote extends Route {
 		}
 
 		return res.json({
-			message: 'Successfully promoted user'
+			message: 'Successfully demoted user'
 		});
 	}
 }

+ 27 - 0
src/api/routes/admin/userDisable.js

@@ -0,0 +1,27 @@
+const Route = require('../../structures/Route');
+
+class userDisable extends Route {
+	constructor() {
+		super('/admin/users/disable', 'post', { adminOnly: true });
+	}
+
+	async run(req, res, db) {
+		if (!req.body) return res.status(400).json({ message: 'No body provided' });
+		const { id } = req.body;
+		if (!id) return res.status(400).json({ message: 'No id provided' });
+
+		try {
+			await db.table('users')
+				.where({ id })
+				.update({ enabled: false });
+		} catch (error) {
+			return super.error(res, error);
+		}
+
+		return res.json({
+			message: 'Successfully disabled user'
+		});
+	}
+}
+
+module.exports = userDisable;

+ 27 - 0
src/api/routes/admin/userEnable.js

@@ -0,0 +1,27 @@
+const Route = require('../../structures/Route');
+
+class userEnable extends Route {
+	constructor() {
+		super('/admin/users/enable', 'post', { adminOnly: true });
+	}
+
+	async run(req, res, db) {
+		if (!req.body) return res.status(400).json({ message: 'No body provided' });
+		const { id } = req.body;
+		if (!id) return res.status(400).json({ message: 'No id provided' });
+
+		try {
+			await db.table('users')
+				.where({ id })
+				.update({ enabled: true });
+		} catch (error) {
+			return super.error(res, error);
+		}
+
+		return res.json({
+			message: 'Successfully enabled user'
+		});
+	}
+}
+
+module.exports = userEnable;

+ 2 - 2
src/api/routes/admin/userPromote.js

@@ -2,13 +2,13 @@ const Route = require('../../structures/Route');
 
 class userPromote extends Route {
 	constructor() {
-		super('/admin/users/promote', 'get', { adminOnly: true });
+		super('/admin/users/promote', 'post', { adminOnly: true });
 	}
 
 	async run(req, res, db) {
 		if (!req.body) return res.status(400).json({ message: 'No body provided' });
 		const { id } = req.body;
-		if (!id) return res.status(400).json({ message: 'No name provided' });
+		if (!id) return res.status(400).json({ message: 'No id provided' });
 
 		try {
 			await db.table('users')

+ 16 - 8
src/site/components/sidebar/Sidebar.vue

@@ -44,15 +44,23 @@
 		<router-link to="/dashboard/account">
 			<i class="icon-ecommerce-tag-c" />Account
 		</router-link>
-		<hr>
-		<router-link to="/dashboard/users">
-			<i class="icon-setting-gear-a" />Users
-		</router-link>
-		<router-link to="/dashboard/settings">
-			<i class="icon-setting-gear-a" />Settings
-		</router-link>
+		<template v-if="user.isAdmin">
+			<hr>
+			<router-link to="/dashboard/users">
+				<i class="icon-setting-gear-a" />Users
+			</router-link>
+			<router-link to="/dashboard/settings">
+				<i class="icon-setting-gear-a" />Settings
+			</router-link>
+		</template>
 	</div>
 </template>
 <script>
-export default {};
+export default {
+	computed: {
+		user() {
+			return this.$store.state.user;
+		}
+	},
+};
 </script>

+ 257 - 0
src/site/pages/dashboard/users.vue

@@ -0,0 +1,257 @@
+<style lang="scss" scoped>
+	@import '~/assets/styles/_colors.scss';
+	section { background-color: $backgroundLight1 !important; }
+	section.hero div.hero-body {
+		align-items: baseline;
+	}
+	div.search-container {
+		display: flex;
+		justify-content: center;
+	}
+
+	div.view-container {
+		padding: 2rem;
+	}
+	div.album {
+		display: flex;
+		flex-wrap: wrap;
+		margin-bottom: 10px;
+
+		div.arrow-container {
+			width: 2em;
+			height: 64px;
+			position: relative;
+			cursor: pointer;
+
+			i {
+				border: 2px solid $defaultTextColor;
+				border-right: 0;
+				border-top: 0;
+				display: block;
+				height: 1em;
+				position: absolute;
+				transform: rotate(-135deg);
+				transform-origin: center;
+				width: 1em;
+				z-index: 4;
+				top: 22px;
+
+				-webkit-transition: transform 0.1s linear;
+				-moz-transition: transform 0.1s linear;
+				-ms-transition: transform 0.1s linear;
+				-o-transition: transform 0.1s linear;
+				transition: transform 0.1s linear;
+
+				&.active {
+					transform: rotate(-45deg);
+				}
+			}
+		}
+		div.thumb {
+			width: 64px;
+			height: 64px;
+			-webkit-box-shadow: $boxShadowLight;
+					box-shadow: $boxShadowLight;
+		}
+
+		div.info {
+			margin-left: 15px;
+			h4 {
+				font-size: 1.5rem;
+				a {
+					color: $defaultTextColor;
+					font-weight: 400;
+					&:hover { text-decoration: underline; }
+				}
+			}
+			span { display: block; }
+			span:nth-child(3) {
+				font-size: 0.9rem;
+			}
+		}
+
+		div.latest {
+			flex-grow: 1;
+			justify-content: flex-end;
+			display: flex;
+			margin-left: 15px;
+
+			span.no-files {
+				font-size: 1.5em;
+				color: #b1b1b1;
+				padding-top: 17px;
+			}
+
+			div.more {
+				width: 64px;
+				height: 64px;
+				background: white;
+				display: flex;
+				align-items: center;
+				padding: 10px;
+				text-align: center;
+				a {
+					line-height: 1rem;
+					color: $defaultTextColor;
+					&:hover { text-decoration: underline; }
+				}
+			}
+		}
+
+		div.details {
+			flex: 0 1 100%;
+			padding-left: 2em;
+			padding-top: 1em;
+			min-height: 50px;
+
+			.b-table {
+				padding: 2em 0em;
+
+				.table-wrapper {
+					-webkit-box-shadow: $boxShadowLight;
+							box-shadow: $boxShadowLight;
+				}
+			}
+		}
+	}
+
+	div.column > h2.subtitle { padding-top: 1px; }
+</style>
+<style lang="scss">
+	@import '~/assets/styles/_colors.scss';
+
+	.b-table {
+		.table-wrapper {
+			-webkit-box-shadow: $boxShadowLight;
+					box-shadow: $boxShadowLight;
+		}
+	}
+</style>
+
+
+<template>
+	<section class="hero is-fullheight">
+		<div class="hero-body">
+			<div class="container">
+				<div class="columns">
+					<div class="column is-narrow">
+						<Sidebar />
+					</div>
+					<div class="column">
+						<h2 class="subtitle">Manage your users</h2>
+						<hr>
+
+						<div class="view-container">
+							<b-table
+								:data="users || []"
+								:mobile-cards="true">
+								<template slot-scope="props">
+									<b-table-column field="id"
+										label="Id"
+										centered>
+										{{ props.row.id }}
+									</b-table-column>
+
+									<b-table-column field="username"
+										label="Username"
+										centered>
+										{{ props.row.username }}
+									</b-table-column>
+
+									<b-table-column field="enabled"
+										label="Enabled"
+										centered>
+										<b-switch v-model="props.row.enabled"
+											@input="changeEnabledStatus(props.row)" />
+									</b-table-column>
+
+									<b-table-column field="isAdmin"
+										label="Admin"
+										centered>
+										<b-switch v-model="props.row.isAdmin"
+											@input="changeIsAdmin(props.row)" />
+									</b-table-column>
+								</template>
+								<template slot="empty">
+									<div class="has-text-centered">
+										<i class="icon-misc-mood-sad" />
+									</div>
+									<div class="has-text-centered">
+										Nothing here
+									</div>
+								</template>
+								<template slot="footer">
+									<div class="has-text-right">
+										{{ users.length }} users
+									</div>
+								</template>
+							</b-table>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</section>
+</template>
+
+<script>
+import Sidebar from '../../components/sidebar/Sidebar.vue';
+
+export default {
+	components: {
+		Sidebar
+	},
+	data() {
+		return {
+			users: []
+		};
+	},
+	computed: {
+		config() {
+			return this.$store.state.config;
+		}
+	},
+	metaInfo() {
+		return { title: 'Uploads' };
+	},
+	mounted() {
+		this.getUsers();
+		this.$ga.page({
+			page: '/dashboard/users',
+			title: 'Users',
+			location: window.location.href
+		});
+	},
+	methods: {
+		async getUsers() {
+			try {
+				const response = await this.axios.get(`${this.config.baseURL}/admin/users`);
+				this.users = response.data.users;
+				console.log(this.users);
+			} catch (error) {
+				console.error(error);
+			}
+		},
+		async changeEnabledStatus(row) {
+			try {
+				const response = await this.axios.post(`${this.config.baseURL}/admin/users/${row.enabled ? 'enable' : 'disable'}`, {
+					id: row.id
+				});
+				this.$toast.open(response.data.message);
+			} catch (error) {
+				console.error(error);
+			}
+		},
+		async changeIsAdmin(row) {
+			try {
+				const response = await this.axios.post(`${this.config.baseURL}/admin/users/${row.isAdmin ? 'promote' : 'demote'}`, {
+					id: row.id
+				});
+				this.$toast.open(response.data.message);
+			} catch (error) {
+				console.error(error);
+			}
+		}
+	}
+};
+</script>