feat(auth): enforce strict branch scoping for branch-assigned HR and staff accounts
- Introduce authBranchId() helper to resolve assigned branch while allowing company admin/superadmin cross-branch oversight - Restrict branch, department, and employee listings and mutations to assigned branch for branch-scoped accounts - Scope attendance records, biometric logs, leave applications/balances, payslips, shifts, and announcements by assigned branch - Add comprehensive automated feature tests in BranchScopedAccessTest to prevent branch cross-visibility regression
This commit is contained in:
@@ -13,9 +13,12 @@ class DepartmentController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
if (Auth::user()->can('manage-departments')) {
|
||||
|
||||
$query = Department::with(['branch', 'creator'])->where(function ($q) {
|
||||
if (Auth::user()->can('manage-any-departments')) {
|
||||
$scopedBranchId = authBranchId();
|
||||
$query = Department::with(['branch', 'creator'])->where(function ($q) use ($scopedBranchId) {
|
||||
if ($scopedBranchId) {
|
||||
$q->whereIn('created_by', getCompanyAndUsersId())
|
||||
->where('branch_id', $scopedBranchId);
|
||||
} elseif (Auth::user()->can('manage-any-departments')) {
|
||||
$q->whereIn('created_by', getCompanyAndUsersId());
|
||||
} elseif (Auth::user()->can('manage-own-departments')) {
|
||||
$q->where('created_by', Auth::id());
|
||||
@@ -33,7 +36,9 @@ class DepartmentController extends Controller
|
||||
}
|
||||
|
||||
// Handle branch filter
|
||||
if ($request->has('branch_id') && !empty($request->branch_id) && $request->branch_id !== 'all') {
|
||||
if ($scopedBranchId) {
|
||||
$query->where('branch_id', $scopedBranchId);
|
||||
} elseif ($request->has('branch_id') && !empty($request->branch_id) && $request->branch_id !== 'all') {
|
||||
$query->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
@@ -57,9 +62,12 @@ class DepartmentController extends Controller
|
||||
$departments = $query->paginate($request->per_page ?? 10);
|
||||
|
||||
// Get branches for filter dropdown
|
||||
$branches = Branch::whereIn('created_by', getCompanyAndUsersId())
|
||||
->where('status', 'active')
|
||||
->get(['id', 'name']);
|
||||
$branchesQuery = Branch::whereIn('created_by', getCompanyAndUsersId())
|
||||
->where('status', 'active');
|
||||
if ($scopedBranchId) {
|
||||
$branchesQuery->where('id', $scopedBranchId);
|
||||
}
|
||||
$branches = $branchesQuery->get(['id', 'name']);
|
||||
|
||||
return Inertia::render('hr/departments/index', [
|
||||
'departments' => $departments,
|
||||
@@ -74,6 +82,11 @@ class DepartmentController extends Controller
|
||||
public function store(Request $request)
|
||||
{
|
||||
if (Auth::user()->can('create-departments')) {
|
||||
$scopedBranchId = authBranchId();
|
||||
if ($scopedBranchId) {
|
||||
$request->merge(['branch_id' => $scopedBranchId]);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'branch_id' => 'required|exists:branches,id',
|
||||
@@ -81,6 +94,10 @@ class DepartmentController extends Controller
|
||||
'status' => 'nullable|in:active,inactive',
|
||||
]);
|
||||
|
||||
if ($scopedBranchId && (int)$validated['branch_id'] !== (int)$scopedBranchId) {
|
||||
return redirect()->back()->with('error', __('Permission Denied. You can only create departments in your assigned branch.'));
|
||||
}
|
||||
|
||||
$validated['created_by'] = creatorId();
|
||||
$validated['status'] = $validated['status'] ?? 'active';
|
||||
|
||||
@@ -114,9 +131,16 @@ class DepartmentController extends Controller
|
||||
public function update(Request $request, $departmentId)
|
||||
{
|
||||
if (Auth::user()->can('edit-departments')) {
|
||||
$department = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId())
|
||||
->first();
|
||||
$scopedBranchId = authBranchId();
|
||||
$departmentQuery = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId());
|
||||
|
||||
if ($scopedBranchId) {
|
||||
$departmentQuery->where('branch_id', $scopedBranchId);
|
||||
$request->merge(['branch_id' => $scopedBranchId]);
|
||||
}
|
||||
|
||||
$department = $departmentQuery->first();
|
||||
|
||||
if ($department) {
|
||||
try {
|
||||
@@ -127,6 +151,10 @@ class DepartmentController extends Controller
|
||||
'status' => 'nullable|in:active,inactive',
|
||||
]);
|
||||
|
||||
if ($scopedBranchId && (int)$validated['branch_id'] !== (int)$scopedBranchId) {
|
||||
return redirect()->back()->with('error', __('Permission Denied. You can only update departments in your assigned branch.'));
|
||||
}
|
||||
|
||||
// Check if branch belongs to the current user's company
|
||||
$branch = Branch::where('id', $validated['branch_id'])
|
||||
->whereIn('created_by', getCompanyAndUsersId())
|
||||
@@ -164,9 +192,15 @@ class DepartmentController extends Controller
|
||||
public function destroy($departmentId)
|
||||
{
|
||||
if (Auth::user()->can('delete-departments')) {
|
||||
$department = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId())
|
||||
->first();
|
||||
$scopedBranchId = authBranchId();
|
||||
$departmentQuery = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId());
|
||||
|
||||
if ($scopedBranchId) {
|
||||
$departmentQuery->where('branch_id', $scopedBranchId);
|
||||
}
|
||||
|
||||
$department = $departmentQuery->first();
|
||||
|
||||
if ($department) {
|
||||
try {
|
||||
@@ -196,9 +230,15 @@ class DepartmentController extends Controller
|
||||
public function toggleStatus($departmentId)
|
||||
{
|
||||
if (Auth::user()->can('toggle-status-departments')) {
|
||||
$department = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId())
|
||||
->first();
|
||||
$scopedBranchId = authBranchId();
|
||||
$departmentQuery = Department::where('id', $departmentId)
|
||||
->whereIn('created_by', getCompanyAndUsersId());
|
||||
|
||||
if ($scopedBranchId) {
|
||||
$departmentQuery->where('branch_id', $scopedBranchId);
|
||||
}
|
||||
|
||||
$department = $departmentQuery->first();
|
||||
|
||||
if ($department) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user