Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 225
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
ClientManagementUsersController
0.00% covered (danger)
0.00%
0 / 225
0.00% covered (danger)
0.00%
0 / 15
1406
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 users
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
30
 usersCategory
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 createUserManually
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 createUserByEmails
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 resendInvitation
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 updateUser
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 resetPassword
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 assignRole
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
210
 moveToInvitedUsers
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
2
 moveToUsers
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 exportUsersCsv
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 deactivateUsers
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 deleteUsers
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 unassignUsers
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Controllers\v1\AdminPortal;
4
5use App\Enums\HttpStatusCode;
6use App\Http\Models\Plans;
7use Illuminate\Http\Request;
8use App\Helpers\FlyMSGLogger;
9use App\Http\Models\Auth\Role;
10use App\Http\Models\Auth\User;
11use App\Events\User\Registered;
12use App\Exceptions\ExpectedException;
13use Illuminate\Validation\Rule;
14use Illuminate\Http\JsonResponse;
15use App\Http\Controllers\Controller;
16use App\Http\Models\Admin\CompanyGroup;
17use App\Http\Models\SalesProTeamManager;
18use App\Http\Requests\AssignRoleRequest;
19use App\Http\Requests\UpdateUserRequest;
20use App\Http\Models\Admin\CompanyLicenses;
21use App\Http\Requests\ResetPasswordRequest;
22use App\Exports\ClientManagementUsersExport;
23use App\Http\Models\Admin\AdminUserInvitation;
24use App\Http\Models\Auth\UserRole;
25use App\Http\Requests\AssignMoveUserToCompanyRequest;
26use App\Http\Requests\ResendInvitationRequest;
27use Illuminate\Validation\ValidationException;
28use App\Http\Requests\CreateUserByEmailRequest;
29use App\Http\Requests\CreateUserManuallyRequest;
30use App\Http\Requests\UsersCategoryFilterRequest;
31use App\Http\Resources\ClientManagementInvitedUserResource;
32use App\Http\Services\ClientManagementUsersService;
33use App\Http\Services\ClientManagementInvitedUserService;
34use App\Http\Resources\ClientManagementUserResource;
35use App\Http\Resources\CMCEditUserResource;
36use App\Http\Services\Admin\Users\AdminUsersService;
37use GPBMetadata\Google\Api\Http;
38use Illuminate\Support\Facades\Cache;
39
40class ClientManagementUsersController extends Controller
41{
42
43    public function __construct(
44        private AdminUsersService $adminUsersService,
45        public ClientManagementUsersService $clientManagementUsersService,
46        public ClientManagementInvitedUserService $clientManagementInvitedUserService
47    ) {}
48
49    public function users(Request $request): JsonResponse
50    {
51        $deactivated = $request->has('deactivated') && $request->deactivated == "true";
52        $perPage = intval(request('perPage', 0));
53        $page = intval(request('page', 1));
54        $filter = request('filter', '');
55        $categories = request('categories', '');
56        $license_types = request('selectedSubscriptionTypes', '');
57        $account_status_list = request('selectedAccountStatus', '');
58        $sortBy = request('sort_by', '');
59        $sortOrder = request('sort_order', '');
60
61        if ($categories) {
62            $categories = explode(',', urldecode($categories));
63        } else {
64            $categories = [];
65        }
66
67        if ($license_types) {
68            $license_types = explode(',', urldecode($license_types));
69        } else {
70            $license_types = [];
71        }
72
73        $account_status = [$account_status_list];
74
75        if (strpos($account_status_list, ',') !== false) {
76            $account_status = explode(",", $account_status_list);
77        }
78
79        $userData = $this->clientManagementUsersService->getUsersPaginated($filter, $deactivated, $perPage, $page, $categories, $sortBy, $sortOrder, $license_types, $account_status);
80
81        return response()->json(
82            data: [
83                'success' => true,
84                'data' => [
85                    'items' => ClientManagementUserResource::collection($userData['users']),
86                    'total' => $userData['total'],
87                    'total_pages' => $userData['total_pages'],
88                    'current_page' => $userData['current_page'],
89                ],
90            ],
91            status: HttpStatusCode::OK->value
92        );
93    }
94
95    public function usersCategory(UsersCategoryFilterRequest $request): JsonResponse
96    {
97        $validatedData = $request->validated();
98
99        $data = $this->clientManagementUsersService->categorizeUsers($validatedData['status'] ?? null);
100
101        return response()->json([
102            'success' => true,
103            'data' => $data
104        ]);
105    }
106
107    public function createUserManually(CreateUserManuallyRequest $request): JsonResponse
108    {
109        $validatedData = $request->validated();
110
111        $user = $this->clientManagementUsersService->createUserManually(auth()->user(), $validatedData);
112
113        return response()->json([
114            'success' => true,
115            'data' => (new ClientManagementUserResource($user))
116        ]);
117    }
118
119    public function createUserByEmails(CreateUserByEmailRequest $request): JsonResponse
120    {
121        $validatedData = $request->validated();
122        $emails = $validatedData['emails'];
123
124        $invitations = $this->clientManagementUsersService->createUserByEmails(auth()->user(), $emails);
125
126        return response()->json([
127            'success' => true,
128            'message' => "Users invited successfully",
129            'data' => ClientManagementUserResource::collection($invitations),
130        ]);
131    }
132
133    public function resendInvitation(ResendInvitationRequest $request): JsonResponse
134    {
135        $validatedData = $request->validated();
136
137        $this->clientManagementUsersService->resendInvitations(auth()->user(), $validatedData['emails']);
138
139        return response()->json([
140            'success' => true,
141            'message' => "Invitation resent",
142        ]);
143    }
144
145    public function updateUser(UpdateUserRequest $request): JsonResponse
146    {
147        $user = User::find($request->user);
148
149        $user->fill($request->validated());
150        $user->save();
151
152        return response()->json([
153            'success' => true,
154            'user' => new ClientManagementUserResource($user)
155        ]);
156    }
157
158    public function resetPassword(ResetPasswordRequest $request): JsonResponse
159    {
160        $validatedData = $request->validated();
161
162        $this->clientManagementUsersService->resetPassword(auth()->user(), $validatedData['user_ids']);
163
164        return response()->json([
165            'success' => true,
166            'message' => "Password reset successfully. User will get the link to update their password.",
167        ]);
168    }
169
170    public function assignRole(AssignRoleRequest $request, User $user): JsonResponse
171    {
172        $validated_data = $request->validated();
173
174        $role = Role::find($validated_data['role_name']);
175        if (!$role) {
176            $role = Role::where("name", $validated_data['role_name'])->first();
177            if (!$role) {
178                throw new ExpectedException("Role not found");
179            }
180        }
181
182        $adminRole = Role::where("name", Role::GLOBAL_ADMIN)->first();
183
184        if ($role->name != Role::GLOBAL_ADMIN) {
185            $isAdmin = UserRole::where("role_id", $adminRole->id)
186                ->where("user_id", $user->id)
187                ->count() > 0;
188
189            if ($isAdmin) {
190                $roleId = $adminRole->id;
191                $companyId = $user->company_id;
192                $currentUserId = $user->id;
193
194                $exists = UserRole::raw(function ($collection) use ($roleId, $companyId, $currentUserId) {
195                    return $collection->aggregate([
196                        [
197                            '$lookup' => [
198                                'from' => 'users',
199                                'let' => ['userId' => ['$toObjectId' => '$user_id']],
200                                'pipeline' => [
201                                    ['$match' => [
202                                        '$expr' => [
203                                            '$eq' => ['$$userId', '$_id']
204                                        ]
205                                    ]],
206                                ],
207                                'as' => 'user'
208                            ]
209                        ],
210                        [
211                            '$match' => [
212                                'role_id' => $roleId,
213                                'user.company_id' => $companyId,
214                                'user_id' => ['$ne' => $currentUserId]
215                            ]
216                        ],
217                        [
218                            '$limit' => 1
219                        ]
220                    ]);
221                });
222
223                $isLastAdmin = empty($exists->toArray());
224
225                if ($isAdmin && $isLastAdmin) {
226                    throw new ExpectedException("Last admin cannot be demoted", 409);
227                }
228            }
229        }
230
231        UserRole::where("user_id", $user->id)->delete();
232
233        UserRole::create([
234            'user_id' => $user->id,
235            'role_id' => $role->id,
236        ]);
237        if ($role->name == Role::GROUP_ADMIN || $role->name = Role::REPORTING_ADMIN) {
238            $group_ids = $validated_data['groups'] ?? [];
239
240            $management_record = $user->sales_pro_team_manager;
241            if (!$management_record) {
242                $management_record = new SalesProTeamManager();
243                $management_record->user_id = $user->id;
244                $management_record->company_id = $user->company_id;
245                $management_record->first_name = $user->first_name;
246                $management_record->last_name = $user->last_name;
247                $management_record->email = $user->email;
248                $management_record->save();
249            }
250
251            if (!empty($group_ids)) {
252                $groups = CompanyGroup::whereIn('_id', $group_ids)->get();
253                if ($groups->isNotEmpty()) {
254                    $management_record->groups()->sync($groups);
255                }
256            }
257
258            $new_group_id = !empty($group_ids) ? $group_ids[0] : null;
259            if ($user->company_group_id !== $new_group_id) {
260                $user->company_group_id = $new_group_id;
261                $user->save();
262            }
263        }
264
265        return response()->json([
266            'success' => true,
267            'message' => "User role updated successfully",
268            'user' => new CMCEditUserResource($user->fresh()),
269        ]);
270    }
271
272    public function moveToInvitedUsers(Request $request): JsonResponse
273    {
274        $validatedData = $request->validate([
275            'company_id' => 'required|exists:companies,_id',
276            'plan_identifier' => ['required', Rule::in([
277                Plans::STARTER_YEARLY_IDENTIFIER,
278                Plans::GROWTH_YEARLY_IDENTIFIER,
279                Plans::PROFESSIONAL_YEARLY_IDENTIFIER,
280                Plans::ProPlanTeamsSMB,
281                Plans::FREEMIUM_IDENTIFIER
282            ])],
283            'role_name' => [
284                'required',
285                'string',
286                Rule::in([
287                    Role::USER,
288                    Role::REPORTING_ADMIN,
289                    Role::GROUP_ADMIN,
290                    Role::GLOBAL_ADMIN,
291                    Role::VENGRESO_ADMIN,
292                ])
293            ],
294            'user_ids' => 'required|array|min:1',
295            'group_id' => 'sometimes|string|exists:company_groups,_id',
296            'subgroup_id' => 'sometimes|string|exists:company_groups,_id',
297        ]);
298
299        $data = $this->clientManagementInvitedUserService->moveToInvitedUsers($validatedData);
300
301        return response()->json([
302            'success' => true,
303            'message' => "Admin Invitation updated successfully",
304            'data' => ClientManagementInvitedUserResource::collection($data),
305        ]);
306    }
307
308    public function moveToUsers(AssignMoveUserToCompanyRequest $request): JsonResponse
309    {
310        $validatedData = $request->validated();
311        $admin = auth()->user();
312
313        $data = $this->clientManagementUsersService->moveToUsers($validatedData, $admin);
314
315        return response()->json([
316            'success' => true,
317            'message' => "Users updated successfully",
318            'data' => CMCEditUserResource::collection($data),
319        ]);
320    }
321
322    public function exportUsersCsv(Request $request)
323    {
324        try {
325            $userIds = $request->users ? explode(',', $request->users) : [];
326            $onlyDeactivatedUsers = $request->deactivated == "true";
327
328            return (new ClientManagementUsersExport($userIds, $onlyDeactivatedUsers))->download('Users.csv');
329        } catch (\Throwable $th) {
330            // Send dev notification
331            FlyMSGLogger::logError(__METHOD__, $th);
332            return response()->json([
333                'success' => false,
334                'message' => $th->getMessage(),
335            ], 500);
336        }
337    }
338
339    public function deactivateUsers(Request $request): JsonResponse
340    {
341        $validatedData = $request->validate([
342            'user_ids' => 'required|array|min:1',
343            'user_ids.*' => ['required', function ($attribute, $value, $fail) {
344                // Disallow deleting user own account
345                if ($value == auth()->user()->id) {
346                    return $fail('You cannot deactivate your own account.');
347                }
348        
349                // Check if user exists in either 'users' or 'admin_user_invitations'
350                $existsInUsers = \DB::table('users')->where('_id', $value)->exists();
351                $existsInInvites = \DB::table('admin_user_invitations')->where('_id', $value)->exists();
352        
353                if (!($existsInUsers || $existsInInvites)) {
354                    return $fail("The user ID {$value} does not exist in users or admin_user_invitations.");
355                }
356            }],
357        ]);
358        
359        $this->adminUsersService->deactivateUserBulk($validatedData['user_ids'], auth()->user()->id, "");
360
361        return response()->json([
362            'success' => true,
363            'message' => "Users deactivated successfully",
364        ]);
365    }
366
367    public function deleteUsers(Request $request): JsonResponse
368    {
369        $validatedData = $request->validate([
370            'users' => 'required',
371        ]);
372
373        $this->adminUsersService->deleteUsers($validatedData['users'], auth()->user(), null);
374
375        return response()->json([
376            'success' => true,
377            'message' => "Users deleted successfully",
378        ]);
379    }
380
381    public function unassignUsers(Request $request): JsonResponse
382    {
383        $validatedData = $request->validate([
384            'users' => 'required',
385        ]);
386
387        $this->adminUsersService->unassignUsers($validatedData['users'], auth()->user(), null);
388
389        return response()->json([
390            'success' => true,
391            'message' => "User unassigned successfully",
392        ]);
393    }
394}