-
Notifications
You must be signed in to change notification settings - Fork 24
Permissions refactored #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a comprehensive role-based access control (RBAC) system with granular permissions, user banning functionality, and various improvements. The old hardcoded role enum is replaced with a dynamic database-backed roles system with a permissions bitmask architecture.
- Replaces hardcoded roles with a database-backed roles system using permission bitmasks
- Adds user banning/suspension functionality with ban tracking
- Implements permission-based access control across admin features
- Removes deprecated backup app dependencies from pnpm-lock.yaml
Reviewed Changes
Copilot reviewed 56 out of 58 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Removes unused backup app dependencies and deprecated package entries |
| packages/db/schema.ts | Adds roles and bannedUsers tables, converts role field to role_id foreign key |
| packages/db/types.ts | Adds UserWithRole type including role relation |
| packages/db/functions/*.ts | Updates queries to include role relations |
| apps/web/src/lib/constants/permission.ts | Defines PermissionType enum with bitwise flags |
| apps/web/src/lib/utils/shared/permission.ts | Implements PermissionMask class for permission management |
| apps/web/src/lib/utils/server/admin.ts | Refactors admin checks to use permission-based system |
| apps/web/src/components/admin/roles/* | Adds role management UI components |
| apps/web/src/components/admin/users/BanUserDialog.tsx | Adds user banning dialog |
| apps/web/src/components/Restricted.tsx | Permission-based component visibility wrapper |
| apps/web/src/middleware.ts | Adds ban check middleware |
| apps/web/src/actions/admin/*.ts | Updates actions with permission checks |
| apps/web/src/app/admin/**/*.tsx | Updates admin pages with permission-based guards |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <Badge>{currentRoleName}</Badge> | ||
| <span>→</span> | ||
| <Badge> | ||
| {titleCase(roleToSet.replace("_", " "))} | ||
| </Badge> | ||
| <Badge>{currentRoleName}</Badge> |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The target role badge displays currentRoleName instead of the new role name. Line 94 should display the name of the role being changed to (roleToSet), not the current role.
| <DialogHeader> | ||
| <DialogTitle>Ban {name}.</DialogTitle> | ||
| <DialogDescription> | ||
| Ban this user (not permament action). |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'permament' to 'permanent'.
| Ban this user (not permament action). | |
| Ban this user (not permanent action). |
| const { execute } = useAction(removeUserBan, { | ||
| async onSuccess() { | ||
| toast.dismiss(); | ||
| toast.success("Suspension successfuly removed!"); |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'successfuly' to 'successfully'.
| }, | ||
| async onError(e) { | ||
| toast.dismiss(); | ||
| toast.error("An error occurred while removing suspenssion."); |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'suspenssion' to 'suspension'.
| {!!banInstance && ( | ||
| <div className="absolute left-0 top-28 w-screen bg-destructive p-2 text-center"> | ||
| <strong> | ||
| This user has been suspended, reason for suspenssion:{" "} |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'suspenssion' to 'suspension'.
| This user has been suspended, reason for suspenssion:{" "} | |
| This user has been suspended, reason for suspension:{" "} |
| const canDeleteRole = (() => { | ||
| try { | ||
| return ( | ||
| userHasPermission(currentUser, PermissionType.DELETE_ROLES) && | ||
| compareUserPosition(currentUser, role.position, "higher") | ||
| ); | ||
| } catch (e) { | ||
| return false; | ||
| } | ||
| })(); |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable canDeleteRole.
| const canDeleteRole = (() => { | |
| try { | |
| return ( | |
| userHasPermission(currentUser, PermissionType.DELETE_ROLES) && | |
| compareUserPosition(currentUser, role.position, "higher") | |
| ); | |
| } catch (e) { | |
| return false; | |
| } | |
| })(); |
| import { | ||
| Body, | ||
| Button, | ||
| Container, | ||
| Column, | ||
| Head, | ||
| Heading, | ||
| Hr, | ||
| Html, | ||
| Img, | ||
| Link, | ||
| Preview, | ||
| Row, | ||
| Section, | ||
| Tailwind, | ||
| Text, | ||
| } from "@react-email/components"; |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused imports Button, Column, Head, Hr, Html, Link, Preview, Row.
packages/db/functions/user.ts
Outdated
| @@ -1,18 +1,24 @@ | |||
| import { db, eq } from ".."; | |||
| import { userCommonData, userHackerData } from "../schema"; | |||
| import { SQLiteRelationalQuery } from "drizzle-orm/sqlite-core/query-builders/query"; | |||
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import SQLiteRelationalQuery.
packages/db/functions/user.ts
Outdated
| import { db, eq } from ".."; | ||
| import { userCommonData, userHackerData } from "../schema"; | ||
| import { SQLiteRelationalQuery } from "drizzle-orm/sqlite-core/query-builders/query"; | ||
| import { db, eq, InferSelectModel } from ".."; |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import InferSelectModel.
packages/db/functions/user.ts
Outdated
| import { userCommonData, userHackerData } from "../schema"; | ||
| import { SQLiteRelationalQuery } from "drizzle-orm/sqlite-core/query-builders/query"; | ||
| import { db, eq, InferSelectModel } from ".."; | ||
| import { roles, userCommonData, userHackerData } from "../schema"; |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import roles.
Deploying hackkit with
|
| Latest commit: |
f5f2a1b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8c961bbf.hackkit.pages.dev |
| Branch Preview URL: | https://permissions-refactored.hackkit.pages.dev |
joshuasilva414
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some concerns about this use case I found where a role can move themselves up above other roles and then change the lower roles permissions if they have the right boxes checked.
I'm also curious about this disable checkbox. Why can't I turn off this permission, but I can turn off all the other ones?

Why
The previous role and permissions system was dangerous and unscalable
What
Satisfies
https://linear.app/acmutsa/issue/HK-201/revamps-permission-system-for-hackkit
resolves #198