Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetReportRequest
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 4
1056
0.00% covered (danger)
0.00%
0 / 1
 authorize
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
650
 rules
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 prepareForValidation
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 getIdsAsArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Requests\v2\Reports;
4
5use App\Http\Models\Admin\CompanyGroup;
6use App\Http\Models\Auth\Role;
7use App\Http\Models\Auth\User;
8use Illuminate\Foundation\Http\FormRequest;
9
10class GetReportRequest extends FormRequest
11{
12    /**
13     * Determine if the user is authorized to make this request.
14     *
15     * @return bool
16     */
17    public function authorize(): bool
18    {
19        $user = $this->user();
20        $roles = $user->roles();
21
22        // 1. VENGRESO_ADMIN can do anything.
23        if (in_array(Role::VENGRESO_ADMIN, $roles)) {
24            return true;
25        }
26
27        $isCmc = $this->input('cmc', false);
28        if ($isCmc && !in_array(Role::VENGRESO_ADMIN, $roles)) {
29            return false;
30        }
31
32        // All other roles must belong to a company.
33        $userCompanyId = $user->company_id;
34        if (empty($userCompanyId)) {
35            return false;
36        }
37
38        // 2. GLOBAL_ADMIN validation
39        if (in_array(Role::GLOBAL_ADMIN, $roles)) {
40            // They can only see data within their own company.
41            $requestedCompanyIds = $this->getIdsAsArray('company_ids');
42
43            // If they request specific companies, all must match their own.
44            if (!empty($requestedCompanyIds)) {
45                $unauthorizedIds = array_diff($requestedCompanyIds, [$userCompanyId]);
46                return empty($unauthorizedIds); // True if no unauthorized IDs were requested.
47            }
48
49            // If no company is specified, it's allowed. Controller will scope.
50            return true;
51        }
52
53        // 3. GROUP_ADMIN or REPORTING_ADMIN validation
54        if (in_array(Role::GROUP_ADMIN, $roles) || in_array(Role::REPORTING_ADMIN, $roles)) {
55            // First, ensure they are not trying to access other companies' data.
56            $requestedCompanyIds = $this->getIdsAsArray('company_ids');
57            if (!empty($requestedCompanyIds)) {
58                $unauthorizedIds = array_diff($requestedCompanyIds, [$userCompanyId]);
59                if (!empty($unauthorizedIds)) {
60                    return false; // Requesting companies they don't belong to.
61                }
62            }
63
64            $requestedGroupIds = $this->getIdsAsArray('group_ids');
65            $requestedSubgroupIds = $this->getIdsAsArray('subgroup_ids');
66            $requestedUserIds = $this->getIdsAsArray('user_ids');
67
68            // If they request specific groups, validate them.
69            if (!empty($requestedGroupIds)) {
70                $groups = CompanyGroup::whereIn('id', $requestedGroupIds)->get();
71                if ($groups->count() !== count($requestedGroupIds)) {
72                    return false; // An invalid group ID was requested.
73                }
74                foreach ($groups as $group) {
75                    if (!in_array($user->id, $group->admins ?? [])) {
76                        return false; // Not an admin of this group.
77                    }
78                }
79            }
80
81            // If they request specific groups, validate them.
82            if (!empty($requestedSubgroupIds)) {
83                $groups = CompanyGroup::whereIn('id', $requestedSubgroupIds)->get();
84                if ($groups->count() !== count($requestedSubgroupIds)) {
85                    return false; // An invalid group ID was requested.
86                }
87                foreach ($groups as $group) {
88                    if (!in_array($user->id, $group->admins ?? [])) {
89                        return false; // Not an admin of this group.
90                    }
91                }
92            }
93
94            // If they request specific users, validate them.
95            if (!empty($requestedUserIds)) {
96                $managedGroupIds = CompanyGroup::where('company_id', $userCompanyId)
97                    ->where('admins', $user->id)
98                    ->pluck('id')
99                    ->all();
100
101                if (empty($managedGroupIds)) {
102                    return false; // This admin manages no groups, so they can't view any users.
103                }
104
105                $usersToValidate = User::whereIn('id', $requestedUserIds)->get();
106                if ($usersToValidate->count() !== count($requestedUserIds)) {
107                    return false; // An invalid user ID was requested.
108                }
109
110                foreach ($usersToValidate as $userToValidate) {
111                    // This check assumes a user belongs to one group via `group_id`.
112                    // If a user can belong to many groups, this check needs to be adapted.
113                    if (!isset($userToValidate->group_id) || !in_array($userToValidate->group_id, $managedGroupIds)) {
114                        return false; // This user is not in a group the admin manages.
115                    }
116                }
117            }
118
119            return true; // All checks passed.
120        }
121
122        // If user has no specific admin role, deny access.
123        return false;
124    }
125
126    /**
127     * Get the validation rules that apply to the request.
128     *
129     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
130     */
131    public function rules(): array
132    {
133        return [
134            'cmc' => 'sometimes|boolean',
135            'from' => 'sometimes|date',
136            'to' => 'sometimes|date|after_or_equal:from',
137            'company_ids' => 'sometimes|string',
138            'group_ids' => 'sometimes|string',
139            'subgroup_ids' => 'sometimes|string',
140            'user_ids' => 'sometimes|string',
141        ];
142    }
143
144    /**
145     * Prepare the data for validation.
146     *
147     * @return void
148     */
149    protected function prepareForValidation()
150    {
151        $user = $this->user();
152
153        // If a non-super-admin makes a request without specifying companyIds,
154        // we automatically scope the request to their own company.
155        if ($user && !in_array(Role::VENGRESO_ADMIN, $user->roles()) && !$this->has('companyIds') && $user->company_id) {
156            $this->merge([
157                'companyIds' => $user->company_id,
158            ]);
159        }
160    }
161
162    /**
163     * Helper method to process comma-separated ID strings from the request.
164     *
165     * @param string $key
166     * @return array
167     */
168    private function getIdsAsArray(string $key): array
169    {
170        return array_values(array_filter(explode(',', $this->input($key, ''))));
171    }
172}