| @@ -22,8 +22,8 @@ | |||||
| <RouterLink to="/admin/dashboard" class="button is-primary"> | <RouterLink to="/admin/dashboard" class="button is-primary"> | ||||
| Admin | Admin | ||||
| </RouterLink> | </RouterLink> | ||||
| <RouterLink to="/register" class="button is-white"> | |||||
| Register | |||||
| <RouterLink to="/logout" class="button is-white"> | |||||
| Log out | |||||
| </RouterLink> | </RouterLink> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -5,19 +5,15 @@ import { | |||||
| } from 'vue-router'; | } from 'vue-router'; | ||||
| import RegisterView from '@/views/RegisterView.vue'; | import RegisterView from '@/views/RegisterView.vue'; | ||||
| import LoginView from '@/views/LoginView.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 HomeView from '@/views/HomeView.vue'; | ||||
| import FundView from '@/views/FundView.vue'; | import FundView from '@/views/FundView.vue'; | ||||
| import AddFundView from '@/views/AddFundView.vue'; | import AddFundView from '@/views/AddFundView.vue'; | ||||
| import hasPermission from '@/lib/auth'; | |||||
| import AdminView from '@/views/AdminView.vue'; | import AdminView from '@/views/AdminView.vue'; | ||||
| import ModifyQueueView from '@/views/ModifyQueueView.vue'; | import ModifyQueueView from '@/views/ModifyQueueView.vue'; | ||||
| import AdminDashboardView from '@/views/AdminDashboardView.vue'; | import AdminDashboardView from '@/views/AdminDashboardView.vue'; | ||||
| import { usersExist } from '@/api/composed'; | |||||
| import ModifyUserView from '@/views/ModifyUserView.vue'; | import ModifyUserView from '@/views/ModifyUserView.vue'; | ||||
| import LogoutView from '@/views/LogoutView.vue'; | |||||
| const routes: Array<RouteRecordRaw> = [ | const routes: Array<RouteRecordRaw> = [ | ||||
| { | { | ||||
| @@ -39,17 +35,9 @@ const routes: Array<RouteRecordRaw> = [ | |||||
| meta: { title: 'Login' }, | 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', | path: '/admin', | ||||
| @@ -126,6 +114,11 @@ const routes: Array<RouteRecordRaw> = [ | |||||
| title: 'Administrator', | title: 'Administrator', | ||||
| }, | }, | ||||
| }, | }, | ||||
| { | |||||
| path: '/:pathMatch(.*)*', | |||||
| name: 'wildcard', | |||||
| redirect: '/', | |||||
| }, | |||||
| ]; | ]; | ||||
| const router = createRouter({ | const router = createRouter({ | ||||
| @@ -136,16 +129,7 @@ const router = createRouter({ | |||||
| router.beforeEach(async (to, from, next) => { | router.beforeEach(async (to, from, next) => { | ||||
| document.title = `Beignet - ${to.meta.title}`; | 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; | 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> | <template> | ||||
| <section class="section"> | <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> | </section> | ||||
| </template> | </template> | ||||
| @@ -49,8 +57,12 @@ import jwtDecode from 'jwt-decode'; | |||||
| import store from '@/store'; | import store from '@/store'; | ||||
| const users = ref<User[]>(); | 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>({ | const userData = ref<Claims>({ | ||||
| username: '', | username: '', | ||||