Admin navigation permissions
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import pool from '../db';
|
import pool from '../db';
|
||||||
|
import { Role } from '@app/shared/types/roles'
|
||||||
|
|
||||||
export async function assignUserGroup(userID: number, roleID: number) {
|
export async function assignUserGroup(userID: number, roleID: number) {
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ export async function createGroup(name: string, color: string, description: stri
|
|||||||
return { id: result.insertId, name, color, description };
|
return { id: result.insertId, name, color, description };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserRoles(userID: number) {
|
export async function getUserRoles(userID: number): Promise<Role[]> {
|
||||||
const sql = `SELECT r.id, r.name
|
const sql = `SELECT r.id, r.name
|
||||||
FROM members_roles mr
|
FROM members_roles mr
|
||||||
INNER JOIN roles r ON mr.role_id = r.id
|
INNER JOIN roles r ON mr.role_id = r.id
|
||||||
|
|||||||
6
shared/types/roles.ts
Normal file
6
shared/types/roles.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface Role {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
color?: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
@@ -17,8 +17,11 @@ import NavigationMenuLink from '../ui/navigation-menu/NavigationMenuLink.vue';
|
|||||||
import NavigationMenuTrigger from '../ui/navigation-menu/NavigationMenuTrigger.vue';
|
import NavigationMenuTrigger from '../ui/navigation-menu/NavigationMenuTrigger.vue';
|
||||||
import NavigationMenuContent from '../ui/navigation-menu/NavigationMenuContent.vue';
|
import NavigationMenuContent from '../ui/navigation-menu/NavigationMenuContent.vue';
|
||||||
import { navigationMenuTriggerStyle } from '../ui/navigation-menu/'
|
import { navigationMenuTriggerStyle } from '../ui/navigation-menu/'
|
||||||
|
import { useAuth } from '@/composables/useAuth';
|
||||||
|
import { CircleArrowOutUpRight } from 'lucide-vue-next';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const auth = useAuth();
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const APIHOST = import.meta.env.VITE_APIHOST;
|
const APIHOST = import.meta.env.VITE_APIHOST;
|
||||||
@@ -88,50 +91,57 @@ function blurAfter() {
|
|||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
|
|
||||||
<!-- Administration (Dropdown) -->
|
<!-- Administration (Dropdown) -->
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem v-if="auth.hasAnyRole(['17th Administrator', '17th HQ', '17th Command', 'Recruiter'])">
|
||||||
<NavigationMenuTrigger>Administration</NavigationMenuTrigger>
|
<NavigationMenuTrigger>Administration</NavigationMenuTrigger>
|
||||||
<NavigationMenuContent
|
<NavigationMenuContent
|
||||||
class="grid gap-1 p-2 text-left [&_a]:w-full [&_a]:block [&_a]:whitespace-nowrap *:bg-transparent">
|
class="grid gap-1 p-2 text-left [&_a]:w-full [&_a]:block [&_a]:whitespace-nowrap *:bg-transparent">
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
<NavigationMenuLink
|
||||||
|
v-if="auth.hasAnyRole(['17th Administrator', '17th HQ', '17th Command'])"
|
||||||
|
as-child :class="navigationMenuTriggerStyle()">
|
||||||
<RouterLink to="/administration/rankChange" @click="blurAfter">
|
<RouterLink to="/administration/rankChange" @click="blurAfter">
|
||||||
Promotions
|
Promotions
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
<NavigationMenuLink
|
||||||
|
v-if="auth.hasAnyRole(['17th Administrator', '17th HQ', '17th Command'])"
|
||||||
|
as-child :class="navigationMenuTriggerStyle()">
|
||||||
<RouterLink to="/administration/loa" @click="blurAfter">
|
<RouterLink to="/administration/loa" @click="blurAfter">
|
||||||
Leave of Absence
|
Leave of Absence
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
<NavigationMenuLink
|
||||||
|
v-if="auth.hasAnyRole(['17th Administrator', '17th HQ', '17th Command'])"
|
||||||
|
as-child :class="navigationMenuTriggerStyle()">
|
||||||
<RouterLink to="/administration/transfer" @click="blurAfter">
|
<RouterLink to="/administration/transfer" @click="blurAfter">
|
||||||
Transfer Requests
|
Transfer Requests
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
<NavigationMenuLink v-if="auth.hasRole('Recruiter')" as-child
|
||||||
|
:class="navigationMenuTriggerStyle()">
|
||||||
<RouterLink to="/administration/applications" @click="blurAfter">
|
<RouterLink to="/administration/applications" @click="blurAfter">
|
||||||
Recruitment
|
Recruitment
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
<NavigationMenuLink v-if="auth.hasRole('17th Administrator')" as-child
|
||||||
|
:class="navigationMenuTriggerStyle()">
|
||||||
<RouterLink to="/administration/roles" @click="blurAfter">
|
<RouterLink to="/administration/roles" @click="blurAfter">
|
||||||
Role Management
|
Role Management
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
|
||||||
<NavigationMenuLink as-child :class="navigationMenuTriggerStyle()">
|
|
||||||
<RouterLink to="/members" @click="blurAfter">
|
|
||||||
Members (debug)
|
|
||||||
</RouterLink>
|
|
||||||
</NavigationMenuLink>
|
|
||||||
|
|
||||||
</NavigationMenuContent>
|
</NavigationMenuContent>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
|
|
||||||
|
<NavigationMenuItem as-child :class="navigationMenuTriggerStyle()">
|
||||||
|
<RouterLink to="/members" @click="blurAfter">
|
||||||
|
Members (debug)
|
||||||
|
</RouterLink>
|
||||||
|
</NavigationMenuItem>
|
||||||
|
|
||||||
</NavigationMenuList>
|
</NavigationMenuList>
|
||||||
</NavigationMenu>
|
</NavigationMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
32
ui/src/composables/useAuth.ts
Normal file
32
ui/src/composables/useAuth.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { useUserStore } from "@/stores/user"
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { Role } from "@shared/types/roles"
|
||||||
|
|
||||||
|
export function useAuth() {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const roles = computed<string[]>(() => {
|
||||||
|
return userStore.user?.roleData?.map((r: Role) => r.name) ?? [];
|
||||||
|
});
|
||||||
|
|
||||||
|
function isDev() {
|
||||||
|
return roles.value.includes('Dev');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasRole(roleName: string): boolean {
|
||||||
|
if (isDev()) return true;
|
||||||
|
return roles.value.includes(roleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAnyRole(roleNames: string[]): boolean {
|
||||||
|
if (isDev()) return true;
|
||||||
|
return roles.value.some(name => roleNames.includes(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAllRoles(roleNames: string[]): boolean {
|
||||||
|
if (isDev()) return true;
|
||||||
|
return roles.value.every(name => roleNames.includes(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
return { hasRole, hasAnyRole, hasAllRoles }
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
console.log(data);
|
||||||
user.value = data;
|
user.value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user