Created hidden Admin Panel
This commit is contained in:
		@@ -8,7 +8,7 @@ export const set_role = (
 | 
				
			|||||||
	user: number,
 | 
						user: number,
 | 
				
			||||||
	role: UserRole,
 | 
						role: UserRole,
 | 
				
			||||||
	token: string
 | 
						token: string
 | 
				
			||||||
): Promise<Responses.Admin.SetUserRole> =>
 | 
					): Promise<Responses.Admin.SetUserRole | Responses.ErrorResponse> =>
 | 
				
			||||||
	post_token<Requests.Admin.SetUserRole>(
 | 
						post_token<Requests.Admin.SetUserRole>(
 | 
				
			||||||
		'/api/admin/set_role',
 | 
							'/api/admin/set_role',
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -21,7 +21,7 @@ export const set_role = (
 | 
				
			|||||||
export const logout = (
 | 
					export const logout = (
 | 
				
			||||||
	user: number,
 | 
						user: number,
 | 
				
			||||||
	token: string
 | 
						token: string
 | 
				
			||||||
): Promise<Responses.Admin.LogoutAllUser> =>
 | 
					): Promise<Responses.Admin.LogoutAllUser | Responses.ErrorResponse> =>
 | 
				
			||||||
	post_token<Requests.Admin.LogoutAll>(
 | 
						post_token<Requests.Admin.LogoutAll>(
 | 
				
			||||||
		'/api/admin/logout',
 | 
							'/api/admin/logout',
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -33,7 +33,7 @@ export const logout = (
 | 
				
			|||||||
export const delete_user = (
 | 
					export const delete_user = (
 | 
				
			||||||
	user: number,
 | 
						user: number,
 | 
				
			||||||
	token: string
 | 
						token: string
 | 
				
			||||||
): Promise<Responses.Admin.DeleteUser> =>
 | 
					): Promise<Responses.Admin.DeleteUser | Responses.ErrorResponse> =>
 | 
				
			||||||
	post_token<Requests.Admin.DeleteUser>(
 | 
						post_token<Requests.Admin.DeleteUser>(
 | 
				
			||||||
		'/api/admin/delete',
 | 
							'/api/admin/delete',
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -45,7 +45,7 @@ export const delete_user = (
 | 
				
			|||||||
export const disable_tfa = (
 | 
					export const disable_tfa = (
 | 
				
			||||||
	user: number,
 | 
						user: number,
 | 
				
			||||||
	token: string
 | 
						token: string
 | 
				
			||||||
): Promise<Responses.Admin.DisableTfa> =>
 | 
					): Promise<Responses.Admin.DisableTfa | Responses.ErrorResponse> =>
 | 
				
			||||||
	post_token<Requests.Admin.DisableTfa>(
 | 
						post_token<Requests.Admin.DisableTfa>(
 | 
				
			||||||
		'/api/admin/disable_2fa',
 | 
							'/api/admin/disable_2fa',
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import FSView from '@/views/FSView.vue';
 | 
				
			|||||||
import SetTokenView from '@/views/SetTokenView.vue';
 | 
					import SetTokenView from '@/views/SetTokenView.vue';
 | 
				
			||||||
import ProfileView from '@/views/ProfileView.vue';
 | 
					import ProfileView from '@/views/ProfileView.vue';
 | 
				
			||||||
import TFAView from '@/views/TFAView.vue';
 | 
					import TFAView from '@/views/TFAView.vue';
 | 
				
			||||||
 | 
					import AdminView from '@/views/AdminView.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes: Array<RouteRecordRaw> = [
 | 
					const routes: Array<RouteRecordRaw> = [
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -24,6 +25,10 @@ const routes: Array<RouteRecordRaw> = [
 | 
				
			|||||||
		name: '2fa',
 | 
							name: '2fa',
 | 
				
			||||||
		component: TFAView
 | 
							component: TFAView
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							path: '/admin',
 | 
				
			||||||
 | 
							component: AdminView
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		path: '/about',
 | 
							path: '/about',
 | 
				
			||||||
		component: AboutView
 | 
							component: AboutView
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										109
									
								
								frontend/src/views/AdminView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								frontend/src/views/AdminView.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { inject, onBeforeMount, ref } from 'vue';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
						Responses,
 | 
				
			||||||
 | 
						check_token,
 | 
				
			||||||
 | 
						TokenInjectType,
 | 
				
			||||||
 | 
						Admin,
 | 
				
			||||||
 | 
						isErrorResponse
 | 
				
			||||||
 | 
					} from '@/api';
 | 
				
			||||||
 | 
					import { onBeforeRouteUpdate } from 'vue-router';
 | 
				
			||||||
 | 
					import router from '@/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const users = ref<Responses.Admin.GetUsersEntry[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onBeforeRouteUpdate(async () => {
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					onBeforeMount(async () => {
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					async function updatePanel() {
 | 
				
			||||||
 | 
						const token = await check_token(jwt);
 | 
				
			||||||
 | 
						if (!token) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await Admin.get_users(token);
 | 
				
			||||||
 | 
						if (isErrorResponse(res)) return router.replace({ path: '/' });
 | 
				
			||||||
 | 
						users.value = res.users;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function setRole(user: number, roleStr: string) {
 | 
				
			||||||
 | 
						const token = await check_token(jwt);
 | 
				
			||||||
 | 
						if (!token) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await Admin.set_role(user, parseInt(roleStr, 10), token);
 | 
				
			||||||
 | 
						if (isErrorResponse(res)) console.error(res.message);
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function disableTfa(user: number) {
 | 
				
			||||||
 | 
						const token = await check_token(jwt);
 | 
				
			||||||
 | 
						if (!token) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await Admin.disable_tfa(user, token);
 | 
				
			||||||
 | 
						if (isErrorResponse(res)) console.error(res.message);
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function logoutUser(user: number) {
 | 
				
			||||||
 | 
						const token = await check_token(jwt);
 | 
				
			||||||
 | 
						if (!token) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await Admin.logout(user, token);
 | 
				
			||||||
 | 
						if (isErrorResponse(res)) console.error(res.message);
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function deleteUser(user: number) {
 | 
				
			||||||
 | 
						const token = await check_token(jwt);
 | 
				
			||||||
 | 
						if (!token) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await Admin.delete_user(user, token);
 | 
				
			||||||
 | 
						if (isErrorResponse(res)) console.error(res.message);
 | 
				
			||||||
 | 
						await updatePanel();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
						<table>
 | 
				
			||||||
 | 
							<tr>
 | 
				
			||||||
 | 
								<th>Name</th>
 | 
				
			||||||
 | 
								<th>Type</th>
 | 
				
			||||||
 | 
								<th>Role</th>
 | 
				
			||||||
 | 
								<th>Tfa Status</th>
 | 
				
			||||||
 | 
								<th>Actions</th>
 | 
				
			||||||
 | 
							</tr>
 | 
				
			||||||
 | 
							<tr v-for="user in users" :key="user.id">
 | 
				
			||||||
 | 
								<td>{{ user.name }}</td>
 | 
				
			||||||
 | 
								<td>{{ user.gitlab ? 'Gitlab' : 'Password' }}</td>
 | 
				
			||||||
 | 
								<td>
 | 
				
			||||||
 | 
									<select @change="setRole(user.id, $event.target.value)">
 | 
				
			||||||
 | 
										<option value="0" :selected="user.role === 0 ? true : null">
 | 
				
			||||||
 | 
											Disabled
 | 
				
			||||||
 | 
										</option>
 | 
				
			||||||
 | 
										<option value="1" :selected="user.role === 1 ? true : null">
 | 
				
			||||||
 | 
											User
 | 
				
			||||||
 | 
										</option>
 | 
				
			||||||
 | 
										<option value="2" :selected="user.role === 2 ? true : null">
 | 
				
			||||||
 | 
											Admin
 | 
				
			||||||
 | 
										</option>
 | 
				
			||||||
 | 
									</select>
 | 
				
			||||||
 | 
								</td>
 | 
				
			||||||
 | 
								<td v-if="user.gitlab"></td>
 | 
				
			||||||
 | 
								<td v-else>
 | 
				
			||||||
 | 
									{{ user.tfaEnabled ? 'Enabled' : 'Disabled' }}
 | 
				
			||||||
 | 
								</td>
 | 
				
			||||||
 | 
								<td>
 | 
				
			||||||
 | 
									<button v-if="user.tfaEnabled" @click="disableTfa(user.id)">
 | 
				
			||||||
 | 
										Disable Tfa
 | 
				
			||||||
 | 
									</button>
 | 
				
			||||||
 | 
									<button @click="logoutUser(user.id)">Logout all</button>
 | 
				
			||||||
 | 
									<button @click="deleteUser(user.id)">Delete</button>
 | 
				
			||||||
 | 
								</td>
 | 
				
			||||||
 | 
							</tr>
 | 
				
			||||||
 | 
						</table>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
@@ -10,22 +10,16 @@ import {
 | 
				
			|||||||
import { AuthService } from 'services/auth';
 | 
					import { AuthService } from 'services/auth';
 | 
				
			||||||
import { Requests, Responses, UserRole } from 'dto';
 | 
					import { Requests, Responses, UserRole } from 'dto';
 | 
				
			||||||
import { Role } from 'authguards';
 | 
					import { Role } from 'authguards';
 | 
				
			||||||
import { InjectRepository } from '@nestjs/typeorm';
 | 
					import { tfaTypes } from 'entities';
 | 
				
			||||||
import { tfaTypes, User } from 'entities';
 | 
					 | 
				
			||||||
import { Repository } from 'typeorm';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Controller('api/admin')
 | 
					@Controller('api/admin')
 | 
				
			||||||
export default class AdminController {
 | 
					export default class AdminController {
 | 
				
			||||||
	constructor(
 | 
						constructor(private authService: AuthService) {}
 | 
				
			||||||
		@InjectRepository(User)
 | 
					 | 
				
			||||||
		private userRepo: Repository<User>,
 | 
					 | 
				
			||||||
		private authService: AuthService
 | 
					 | 
				
			||||||
	) {}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Role(UserRole.ADMIN)
 | 
						@Role(UserRole.ADMIN)
 | 
				
			||||||
	@Get('users')
 | 
						@Get('users')
 | 
				
			||||||
	async getUsers(): Promise<Responses.Admin.GetUsers> {
 | 
						async getUsers(): Promise<Responses.Admin.GetUsers> {
 | 
				
			||||||
		const users = await this.userRepo.find();
 | 
							const users = await this.authService.getUsers();
 | 
				
			||||||
		const entries = users.map(
 | 
							const entries = users.map(
 | 
				
			||||||
			(user) =>
 | 
								(user) =>
 | 
				
			||||||
				new Responses.Admin.GetUsersEntry(
 | 
									new Responses.Admin.GetUsersEntry(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,10 @@ export default class BaseAuthService {
 | 
				
			|||||||
		protected fsService: FileSystemService
 | 
							protected fsService: FileSystemService
 | 
				
			||||||
	) {}
 | 
						) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getUsers(): Promise<User[]> {
 | 
				
			||||||
 | 
							return this.userRepo.find();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	async getUser(userId: number): Promise<User | null> {
 | 
						async getUser(userId: number): Promise<User | null> {
 | 
				
			||||||
		return this.userRepo.findOneBy({
 | 
							return this.userRepo.findOneBy({
 | 
				
			||||||
			id: userId
 | 
								id: userId
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user