| @@ -22,8 +22,8 @@ | |||
| <RouterLink to="/admin/dashboard" class="button is-primary"> | |||
| Admin | |||
| </RouterLink> | |||
| <RouterLink to="/register" class="button is-white"> | |||
| Register | |||
| <RouterLink to="/logout" class="button is-white"> | |||
| Log out | |||
| </RouterLink> | |||
| </div> | |||
| </div> | |||
| @@ -5,19 +5,15 @@ import { | |||
| } from 'vue-router'; | |||
| import RegisterView from '@/views/RegisterView.vue'; | |||
| import LoginView from '@/views/LoginView.vue'; | |||
| import { | |||
| Privileges, | |||
| SuccessResponse, | |||
| } from '@/api/types'; | |||
| import { Privileges } from '@/api/types'; | |||
| import HomeView from '@/views/HomeView.vue'; | |||
| import FundView from '@/views/FundView.vue'; | |||
| import AddFundView from '@/views/AddFundView.vue'; | |||
| import hasPermission from '@/lib/auth'; | |||
| import AdminView from '@/views/AdminView.vue'; | |||
| import ModifyQueueView from '@/views/ModifyQueueView.vue'; | |||
| import AdminDashboardView from '@/views/AdminDashboardView.vue'; | |||
| import { usersExist } from '@/api/composed'; | |||
| import ModifyUserView from '@/views/ModifyUserView.vue'; | |||
| import LogoutView from '@/views/LogoutView.vue'; | |||
| const routes: Array<RouteRecordRaw> = [ | |||
| { | |||
| @@ -39,17 +35,9 @@ const routes: Array<RouteRecordRaw> = [ | |||
| meta: { title: 'Login' }, | |||
| }, | |||
| { | |||
| path: '/register', | |||
| name: 'register', | |||
| component: RegisterView, | |||
| meta: { | |||
| requiredRights: Privileges.AdminPlus, | |||
| accessible: async () => { | |||
| const canProceed = await usersExist(); | |||
| return canProceed?.success; | |||
| }, | |||
| title: 'Register', | |||
| }, | |||
| path: '/logout', | |||
| name: 'logout', | |||
| component: LogoutView, | |||
| }, | |||
| { | |||
| path: '/admin', | |||
| @@ -126,6 +114,11 @@ const routes: Array<RouteRecordRaw> = [ | |||
| title: 'Administrator', | |||
| }, | |||
| }, | |||
| { | |||
| path: '/:pathMatch(.*)*', | |||
| name: 'wildcard', | |||
| redirect: '/', | |||
| }, | |||
| ]; | |||
| const router = createRouter({ | |||
| @@ -136,16 +129,7 @@ const router = createRouter({ | |||
| router.beforeEach(async (to, from, next) => { | |||
| document.title = `Beignet - ${to.meta.title}`; | |||
| const requiredRights = to.meta.requiredRights as number | undefined; | |||
| const accessible = to.meta.accessible as (() => SuccessResponse) | undefined; | |||
| const allowed = requiredRights ? hasPermission(requiredRights) | |||
| || (accessible && !accessible().success) : true; | |||
| if (allowed) { | |||
| next(); | |||
| } else { | |||
| next('/'); | |||
| } | |||
| return next(); | |||
| }); | |||
| export default router; | |||
| @@ -0,0 +1,20 @@ | |||
| <template> | |||
| <div> | |||
| Logging out... | |||
| </div> | |||
| </template> | |||
| <script setup lang="ts"> | |||
| import { useRouter } from 'vue-router'; | |||
| import store from '@/store'; | |||
| store.commit('clearToken'); | |||
| window.sessionStorage.removeItem('jwt'); | |||
| const router = useRouter(); | |||
| router.push('/'); | |||
| </script> | |||
| <style scoped lang="stylus"> | |||
| </style> | |||
| @@ -1,39 +1,47 @@ | |||
| <template> | |||
| <section class="section"> | |||
| <table> | |||
| <tr> | |||
| <th class="p-2"> | |||
| Username | |||
| </th> | |||
| <th class="p-2"> | |||
| Password | |||
| </th> | |||
| <th class="p-2"> | |||
| Privileges | |||
| </th> | |||
| </tr> | |||
| <tr v-for="user in users" :key="user.username"> | |||
| <td class="p-2">{{ user.username }}</td> | |||
| <td class="p-2"> | |||
| <template v-if="userData.username === user.username || userData.privileges < 2"> | |||
| <input type="password" | |||
| class="input is-small" :aria-label="`${user.username}'s Password`"> | |||
| </template> | |||
| <template v-else> | |||
| ******** | |||
| </template> | |||
| </td> | |||
| <td class="p-2"> | |||
| <select class="select is-small" name="" id="" aria-label="User Privilege"> | |||
| <option :value="privilege" | |||
| :selected="getPrivilege(user.admin) === privilege" | |||
| v-for="(privilege, i) in Object.values(privileges)" :key="i"> | |||
| {{ privilege }} | |||
| </option> | |||
| </select> | |||
| </td> | |||
| </tr> | |||
| </table> | |||
| <template v-if="userData.privileges < 2"> | |||
| <table> | |||
| <tr> | |||
| <th class="p-2"> | |||
| Username | |||
| </th> | |||
| <th class="p-2"> | |||
| Password | |||
| </th> | |||
| <th class="p-2"> | |||
| Privileges | |||
| </th> | |||
| </tr> | |||
| <tr v-for="user in users" :key="user.username"> | |||
| <td class="p-2">{{ user.username }}</td> | |||
| <td class="p-2"> | |||
| <template v-if="userData.username === user.username || userData.privileges < 2"> | |||
| <input type="password" | |||
| class="input is-small" :aria-label="`${user.username}'s Password`"> | |||
| </template> | |||
| <template v-else> | |||
| ******** | |||
| </template> | |||
| </td> | |||
| <td class="p-2"> | |||
| <div class="select is-small"> | |||
| <select name="" id="" aria-label="User Privilege"> | |||
| <option :value="privilege" | |||
| :selected="getPrivilege(user.admin) === privilege" | |||
| v-for="(privilege, i) in Object.values(privileges)" :key="i" | |||
| :disabled="userData.privileges >= 2"> | |||
| {{ privilege }} | |||
| </option> | |||
| </select> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| </table> | |||
| </template> | |||
| <template v-else> | |||
| <p>You don't have permission to change users.</p> | |||
| </template> | |||
| </section> | |||
| </template> | |||
| @@ -49,8 +57,12 @@ import jwtDecode from 'jwt-decode'; | |||
| import store from '@/store'; | |||
| const users = ref<User[]>(); | |||
| const resp = await getUsers(); | |||
| users.value = resp?.users; | |||
| try { | |||
| const resp = await getUsers(); | |||
| users.value = resp?.users; | |||
| } catch { | |||
| users.value = undefined; | |||
| } | |||
| const userData = ref<Claims>({ | |||
| username: '', | |||