Created hidden Admin Panel

This commit is contained in:
Mutzi 2022-08-25 21:27:39 +02:00
parent bcd2beb980
commit eb95d308f9
5 changed files with 125 additions and 13 deletions

View File

@ -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',
{ {

View File

@ -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

View 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>

View File

@ -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(

View File

@ -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