diff --git a/ui/src/pages/Banned.vue b/ui/src/pages/Banned.vue new file mode 100644 index 0000000..5908fa3 --- /dev/null +++ b/ui/src/pages/Banned.vue @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/ui/src/router/index.js b/ui/src/router/index.js index 9801bd4..925b831 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -2,82 +2,91 @@ import { useUserStore } from '@/stores/user' import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ - history: createWebHistory(), - routes: [ - // PUBLIC - { path: '/join', component: () => import('@/pages/Join.vue') }, - { path: '/applications', component: () => import('@/pages/MyApplications.vue'), meta: { requiresAuth: true } }, - { path: '/applications/:id', component: () => import('@/pages/MyApplications.vue'), meta: { requiresAuth: true } }, + history: createWebHistory(), + routes: [ + // PUBLIC + { path: '/join', component: () => import('@/pages/Join.vue') }, + { path: '/applications', component: () => import('@/pages/MyApplications.vue'), meta: { requiresAuth: true } }, + { path: '/applications/:id', component: () => import('@/pages/MyApplications.vue'), meta: { requiresAuth: true } }, - // AUTH REQUIRED - { path: '/', component: () => import('@/pages/Homepage.vue') }, + // AUTH REQUIRED + { path: '/', component: () => import('@/pages/Homepage.vue') }, - // MEMBER ROUTES - { path: '/members', component: () => import('@/pages/memberList.vue'), meta: { requiresAuth: true, memberOnly: true } }, - { path: '/loa', component: () => import('@/pages/SubmitLOA.vue'), meta: { requiresAuth: true, memberOnly: true } }, - { path: '/transfer', component: () => import('@/pages/Transfer.vue'), meta: { requiresAuth: true, memberOnly: true } }, - { path: '/profile', component: () => import('@/pages/MyProfile.vue'), meta: { requiresAuth: true } }, + // MEMBER ROUTES + { path: '/members', component: () => import('@/pages/memberList.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/loa', component: () => import('@/pages/SubmitLOA.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/transfer', component: () => import('@/pages/Transfer.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/profile', component: () => import('@/pages/MyProfile.vue'), meta: { requiresAuth: true } }, - { path: '/calendar', component: () => import('@/pages/Calendar.vue') }, - { path: '/calendar/event/:id', component: () => import('@/pages/Calendar.vue') }, - // disabled in favor of linking - // { path: '/documents', component: () => import('@/pages/Documentation.vue'), meta: { requiresAuth: true, memberOnly: true }, }, - { path: '/trainingReport', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, - { path: '/trainingReport/new', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, - { path: '/trainingReport/:id', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/calendar', component: () => import('@/pages/Calendar.vue') }, + { path: '/calendar/event/:id', component: () => import('@/pages/Calendar.vue') }, - // ADMIN / STAFF ROUTES - { - path: '/administration', - meta: { requiresAuth: true, memberOnly: true, roles: ['17th Administrator', '17th HQ', '17th Command'] }, - children: [ - { path: 'applications', component: () => import('@/pages/ManageApplications.vue') }, - { path: 'applications/:id', component: () => import('@/pages/ManageApplications.vue') }, - { path: 'rankChange', component: () => import('@/pages/RankChange.vue') }, - { path: 'applications/:id', component: () => import('@/pages/Application.vue') }, - { path: 'transfer', component: () => import('@/pages/ManageTransfers.vue') }, - { path: 'loa', component: () => import('@/pages/ManageLOA.vue') }, - { path: 'roles', component: () => import('@/pages/ManageRoles.vue') } - ] - }, + // disabled in favor of linking + // { path: '/documents', component: () => import('@/pages/Documentation.vue'), meta: { requiresAuth: true, memberOnly: true }, }, - // UNAUTHORIZED PAGE - { path: '/unauthorized', component: () => import('@/pages/Unauthorized.vue') } - ] + { path: '/trainingReport', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/trainingReport/new', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, + { path: '/trainingReport/:id', component: () => import('@/pages/TrainingReport.vue'), meta: { requiresAuth: true, memberOnly: true } }, + + // ADMIN / STAFF ROUTES + { + path: '/administration', + meta: { requiresAuth: true, memberOnly: true, roles: ['17th Administrator', '17th HQ', '17th Command'] }, + children: [ + { path: 'applications', component: () => import('@/pages/ManageApplications.vue') }, + { path: 'applications/:id', component: () => import('@/pages/ManageApplications.vue') }, + { path: 'rankChange', component: () => import('@/pages/RankChange.vue') }, + { path: 'applications/:id', component: () => import('@/pages/Application.vue') }, + { path: 'transfer', component: () => import('@/pages/ManageTransfers.vue') }, + { path: 'loa', component: () => import('@/pages/ManageLOA.vue') }, + { path: 'roles', component: () => import('@/pages/ManageRoles.vue') } + ] + }, + + // UNAUTHORIZED PAGE + { path: '/unauthorized', component: () => import('@/pages/Unauthorized.vue') }, + + { path: '/restricted', component: () => import('@/pages/Banned.vue'), meta: { requiresAuth: true } }, + + ] }) const addr = import.meta.env.VITE_APIHOST; router.beforeEach(async (to) => { - const user = useUserStore() + const user = useUserStore() - // Make sure user state is loaded before checking - if (!user.loaded) { - await user.loadUser(); - } + // Make sure user state is loaded before checking + if (!user.loaded) { + await user.loadUser(); + } - // Not logged in - if (to.meta.requiresAuth && !user.isLoggedIn) { - // Redirect back to original page after login - const redirectUrl = encodeURIComponent(window.location.origin + to.fullPath) - window.location.href = `${addr}/login?redirect=${redirectUrl}` - return false // Prevent Vue Router from continuing - } + // Not logged in + if (to.meta.requiresAuth && !user.isLoggedIn) { + // Redirect back to original page after login + const redirectUrl = encodeURIComponent(window.location.origin + to.fullPath) + window.location.href = `${addr}/login?redirect=${redirectUrl}` + return false // Prevent Vue Router from continuing + } + // banned state + if (user.state === 'banned' && to.path !== '/restricted') { + return '/restricted'; + } - // Must be a member - if (to.meta.memberOnly && user.state !== 'member') { - return '/unauthorized' - } + // Must be a member + if (to.meta.memberOnly && user.state !== 'member') { + return '/unauthorized' + } - // Must have specific role - if (to.meta.roles && !user.hasRole('Dev') && !user.hasAnyRole(to.meta.roles)) { - return '/unauthorized' - } + // Must have specific role + if (to.meta.roles && !user.hasRole('Dev') && !user.hasAnyRole(to.meta.roles)) { + return '/unauthorized' + } }) export default router; \ No newline at end of file