From f0185dc7d5241546745b4324353fb845050a8402 Mon Sep 17 00:00:00 2001 From: Sandip Date: Wed, 17 Dec 2025 15:22:23 +0545 Subject: [PATCH] Added Permission Check Function --- .gitignore | 1 + public/config.example.json | 6 +- src/core/app/sidebarItems.ts | 124 ++++++++++++++++++ src/core/types/app/sidebar.type.ts | 2 + src/core/types/auth/auth.type.ts | 2 + src/core/utils/{Common.ts => common.util.ts} | 0 src/core/utils/permission.util.ts | 39 ++++++ src/layouts/AuthLayout.vue | 128 +------------------ src/layouts/components/Header.vue | 4 +- src/layouts/components/Sidebar.vue | 34 ++--- 10 files changed, 192 insertions(+), 148 deletions(-) create mode 100644 src/core/app/sidebarItems.ts rename src/core/utils/{Common.ts => common.util.ts} (100%) create mode 100644 src/core/utils/permission.util.ts diff --git a/.gitignore b/.gitignore index a3f7a51..d174738 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ coverage # Vitest __screenshots__/ +config.json diff --git a/public/config.example.json b/public/config.example.json index ae4aeb2..197fb06 100644 --- a/public/config.example.json +++ b/public/config.example.json @@ -1,9 +1,9 @@ { "ENVIRONMENT": "PRODUCTION || DEVELOPMENT", "PAGE_TITLE": "Dolphin", - "PAGE_TITLE_LOGO": "http://localhost:3000/img/Dolphin/dolphinfav.ico", + "PAGE_TITLE_LOGO": "/img/Dolphin/dolphinfav.ico", "CLIENT_NAME": "Mavorion Systems", - "CLIENT_LOGO": "", "CLIENT_LOCATION": "LAZIMPAT", - "API_BASE_URL": "http://localhost:8000/api/" + "CLIENT_LOGO": "", + "API_BASE_URL": "http://localhost:8000/api/v1/" } diff --git a/src/core/app/sidebarItems.ts b/src/core/app/sidebarItems.ts new file mode 100644 index 0000000..d9fc034 --- /dev/null +++ b/src/core/app/sidebarItems.ts @@ -0,0 +1,124 @@ +import type { SidebarItem } from "../types/app/sidebar.type"; + +const sidebarItems = (): SidebarItem[] => { + return [ + { + label: "Dashboard", + }, + { + label: "Dashboard", + icon: "Home", + to: "/", + }, + { + label: "Stock Verification", + icon: "Blocks", + children: [ + { + label: "Opening Stock", + to: "/stock-verification/opening-stock/", + }, + { + label: "Closing Stock", + to: "/stock-verification/closing-stock/", + }, + ], + }, + { + label: "Components", + }, + { + label: "Content Layout", + icon: "Package", + to: "/component/content-layout", + }, + { + label: "Modal", + icon: "MessageSquareCode", + to: "/component/modal", + }, + { + label: "Switch", + icon: "ToggleLeft", + to: "/component/switch", + }, + { + label: "Toggle", + icon: "ToggleRight", + to: "/component/toggle", + }, + { + label: "Tabulator", + icon: "Table", + to: "/component/tabulator", + }, + { + label: "Towser", + icon: "Blinds", + to: "/component/towser", + }, + { + label: "Date Range", + icon: "CalendarRange", + to: "/component/date-range", + }, + { + label: "Date Selector", + icon: "Calendar", + to: "/component/date-selector", + }, + { + label: "Wizard Stepper", + icon: "WandSparkles", + to: "/component/wizard", + }, + { + label: "Loader", + icon: "Loader", + to: "/component/loader", + }, + { + label: "Directives", + }, + { + label: "Input Error", + icon: "TriangleAlert", + to: "/directives/input-error", + }, + { + label: "Input Currency", + icon: "CircleDollarSign", + to: "/directives/input-currency", + }, + { + label: "Input Select", + icon: "TextCursorInput", + to: "/directives/input-select", + }, + { + label: "Tooltip", + icon: "BookOpenText", + to: "/directives/tooltip", + }, + { + label: "CSS", + }, + { + label: "Buttons", + icon: "SquareArrowLeft", + to: "/css/button", + }, + { + label: "Input", + icon: "TextCursor", + to: "/css/input", + }, + { + label: "Font", + icon: "CaseSensitive", + to: "/css/font", + }, + ]; +}; + +export default sidebarItems; diff --git a/src/core/types/app/sidebar.type.ts b/src/core/types/app/sidebar.type.ts index dc1f71a..0ef0f65 100644 --- a/src/core/types/app/sidebar.type.ts +++ b/src/core/types/app/sidebar.type.ts @@ -4,8 +4,10 @@ export type SidebarItem = { label: string; to?: RouteLocationRaw; icon?: string; + isVisible?: boolean; children?: { label: string; to: RouteLocationRaw; + isVisible?: boolean; }[]; }; diff --git a/src/core/types/auth/auth.type.ts b/src/core/types/auth/auth.type.ts index 872eb11..b62557d 100644 --- a/src/core/types/auth/auth.type.ts +++ b/src/core/types/auth/auth.type.ts @@ -11,5 +11,7 @@ export interface UserDetails { email: string; phone: number | null; department: string | null; + isSuperUser: boolean; roles: []; + permissions: string[]; } diff --git a/src/core/utils/Common.ts b/src/core/utils/common.util.ts similarity index 100% rename from src/core/utils/Common.ts rename to src/core/utils/common.util.ts diff --git a/src/core/utils/permission.util.ts b/src/core/utils/permission.util.ts new file mode 100644 index 0000000..9c7cc51 --- /dev/null +++ b/src/core/utils/permission.util.ts @@ -0,0 +1,39 @@ +import { useAuth } from "@/stores/Auth/auth.store"; +import { storeToRefs } from "pinia"; + +export const hasPermission = ( + permission: string | undefined | null | Array, + requireAll: boolean = true, + allowSuperUser: boolean = true +) => { + const authStore = useAuth(); + const { user } = storeToRefs(authStore); + + if (user.value && user.value.isSuperUser && allowSuperUser) { + return true; + } + const p = new Set(user.value.permissions); + + if (!p) return false; + if (!permission) return true; + if (Array.isArray(permission)) { + if (requireAll) { + return permission.every((perm) => p.has(perm)); + } else { + return permission.some((perm) => p.has(perm)); + } + } + + return p?.has(permission); +}; + +export const isSuperUser = () => { + const authStore = useAuth(); + const { user } = storeToRefs(authStore); + + if (user.value && user.value.isSuperUser) { + return true; + } + + return false; +}; diff --git a/src/layouts/AuthLayout.vue b/src/layouts/AuthLayout.vue index b49882b..8963a7f 100644 --- a/src/layouts/AuthLayout.vue +++ b/src/layouts/AuthLayout.vue @@ -2,7 +2,7 @@
- +
@@ -19,130 +19,4 @@ import Header from "./components/Header.vue"; import { useCore } from "@/stores/App/core.store"; const coreStore = useCore(); - -import type { SidebarItem } from "@/core/types/app/sidebar.type"; - -const sidebarItems: SidebarItem[] = [ - { - label: "Dashboard", - }, - { - label: "Dashboard", - icon: "Home", - to: "/", - }, - { - label: "Stock Verification", - icon: "Blocks", - children: [ - { - label: "Opening Stock", - to: "/stock-verification/opening-stock/", - }, - { - label: "Closing Stock", - to: "/stock-verification/closing-stock/", - }, - ], - }, - { - label: "Components", - }, - { - label: "Content Layout", - icon: "Package", - to: "/component/content-layout", - }, - { - label: "Modal", - icon: "MessageSquareCode", - to: "/component/modal", - }, - { - label: "Switch", - icon: "ToggleLeft", - to: "/component/switch", - }, - { - label: "Toggle", - icon: "ToggleRight", - to: "/component/toggle", - }, - { - label: "Tabulator", - icon: "Table", - to: "/component/tabulator", - }, - { - label: "Towser", - icon: "Blinds", - to: "/component/towser", - }, - { - label: "Date Range", - icon: "CalendarRange", - to: "/component/date-range", - }, - { - label: "Date Selector", - icon: "Calendar", - to: "/component/date-selector", - }, - { - label: "Wizard Stepper", - icon: "WandSparkles", - to: "/component/wizard", - }, - { - label: "Loader", - icon: "Loader", - to: "/component/loader", - }, - // { - // label: "ImageCropper Upload", - // icon: "Crop", - // to: "/component/image-cropper", - // }, - { - label: "Directives", - }, - { - label: "Input Error", - icon: "TriangleAlert", - to: "/directives/input-error", - }, - { - label: "Input Currency", - icon: "CircleDollarSign", - to: "/directives/input-currency", - }, - { - label: "Input Select", - icon: "TextCursorInput", - to: "/directives/input-select", - }, - { - label: "Tooltip", - icon: "BookOpenText", - to: "/directives/tooltip", - }, - { - label: "CSS", - }, - { - label: "Buttons", - icon: "SquareArrowLeft", - to: "/css/button", - }, - { - label: "Input", - icon: "TextCursor", - to: "/css/input", - }, - { - label: "Font", - icon: "CaseSensitive", - to: "/css/font", - }, -]; diff --git a/src/layouts/components/Header.vue b/src/layouts/components/Header.vue index 9844a2c..9cf863c 100644 --- a/src/layouts/components/Header.vue +++ b/src/layouts/components/Header.vue @@ -41,7 +41,7 @@ class="w-[42px] h-[42px] object-cover rounded-full" /> - + {{ getNameInitials(user.full_name ? user.full_name : user.username) }}
@@ -65,7 +65,7 @@