Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 1718 |
|
0.00% |
0 / 82 |
CRAP | |
0.00% |
0 / 1 |
AdminAccountCenterDashboardController | |
0.00% |
0 / 1718 |
|
0.00% |
0 / 82 |
99540 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
_buildUsersResponse | |
0.00% |
0 / 53 |
|
0.00% |
0 / 1 |
210 | |||
_make_line_chart_data | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
12 | |||
_make_line_chart_data_for_counts | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
12 | |||
_make_line_chart_data_extension | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
20 | |||
_assign_plan | |
0.00% |
0 / 57 |
|
0.00% |
0 / 1 |
552 | |||
filterUsersByAdmin | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
filterUsersByGroupIds | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
users | |
0.00% |
0 / 82 |
|
0.00% |
0 / 1 |
812 | |||
groups | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
30 | |||
search_users | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
6 | |||
update_user | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
update_invite | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
create_user_manually | |
0.00% |
0 / 117 |
|
0.00% |
0 / 1 |
182 | |||
resend_temporary_password | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
6 | |||
create_user_by_csv | |
0.00% |
0 / 64 |
|
0.00% |
0 / 1 |
30 | |||
deactivate_user | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
deactivate_invited_user | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
20 | |||
delete_user | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
reset_password | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
reset_invitation_password | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
resend_user_invitation | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
6 | |||
resend_invitations | |
0.00% |
0 / 63 |
|
0.00% |
0 / 1 |
42 | |||
move_group | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
move_group_invite | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
assign_role | |
0.00% |
0 / 78 |
|
0.00% |
0 / 1 |
210 | |||
deactivate_user_bulk | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
_reactive_users | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 | |||
_assign_plans_to_users | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
reactivate_user_bulk | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
delete_user_bulk | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
56 | |||
reset_password_bulk | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
20 | |||
resend_user_invitation_bulk | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
30 | |||
move_group_bulk | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
group_exists | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 | |||
create_group | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
update_group | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
delete_group | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
56 | |||
add_users_to_group | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
add_subgroup_to_group | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
export_csv | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
import_csv | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
reporting_licenses | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
20 | |||
reporting_roi_spotlight | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_productivity_spotlight | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_total_characters_typed_spotlight | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_total_fly_grammar_spotlight | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_total_fly_cuts_spotlight | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flymsg_coach_level | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flycuts_created | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flycuts_created_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_flyplates_added | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flyplates_added_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_sentence_rewrite_ai | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
20 | |||
reporting_sentence_rewrite_ai_used_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_paragraph_rewrite_ai | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
20 | |||
reporting_paragraph_rewrite_ai_used_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_flyengage_ai | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flyengage_ai_used_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_flypost_ai | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
20 | |||
reporting_flypost_ai_used_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getTop5 | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
30 | |||
reporting_characters_typed_saving_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_fly_grammar_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_fly_cuts_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_fly_grammar_accepted_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_fly_grammar_autocorrect_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_fly_grammar_autocomplete_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_time_saving_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_cost_saving_top_users | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
reporting_active_users | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
20 | |||
reporting_extension_usage | |
0.00% |
0 / 68 |
|
0.00% |
0 / 1 |
156 | |||
reporting_user_details | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
30 | |||
reporting_get_columns | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
6 | |||
reporting_save_columns | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
56 | |||
export_user_details_csv | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
6 | |||
reset_invited_user_password | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
30 | |||
export_csv_report | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
export_csv_report_overview | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
export_csv_report_usage | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
remove_users_from_group | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
user_info | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace App\Http\Controllers\v1\AdminPortal; |
4 | |
5 | use App\Actions\AccountCenter\Reporting\FmsCoachLevelSpotlightAction; |
6 | use App\Actions\AccountCenter\Reporting\ProductivitySpotlightAction; |
7 | use App\Actions\AccountCenter\Reporting\RoiSpotlightAction; |
8 | use App\Actions\AccountCenter\Reporting\TotalCharactersTypedSpotlightAction; |
9 | use App\Actions\AccountCenter\Reporting\TotalFlyCutsSpotlightAction; |
10 | use App\Actions\AccountCenter\Reporting\TotalFlyGrammarSpotlightAction; |
11 | use App\Actions\Users\SendUserInvitationAction; |
12 | use App\Actions\Users\UpdateUserAction; |
13 | use App\DTO\AccountCenter\Reporting\ReportingRequestDTO; |
14 | use App\DTO\User\SendUserInvitationDTO; |
15 | use App\DTO\User\UpdateUserDTO; |
16 | use App\Events\User\Registered; |
17 | use App\Exceptions\ExpectedException; |
18 | use App\Exports\UsersExport; |
19 | use App\Exports\UsersReportExport; |
20 | use App\Exports\UsersReportOverviewExport; |
21 | use App\Exports\UsersReportUsageExport; |
22 | use App\Helpers\Constants; |
23 | use App\Helpers\FlyMSGLogger; |
24 | use App\Http\Controllers\Controller; |
25 | use App\Http\Models\Admin\AdminUserInvitation; |
26 | use App\Http\Models\Admin\Company; |
27 | use App\Http\Models\Admin\CompanyGroup; |
28 | use App\Http\Models\Admin\CompanyLicenses; |
29 | use App\Http\Models\Admin\UserDetailsColumnSetting; |
30 | use App\Http\Models\Auth\Role; |
31 | use App\Http\Models\Auth\User; |
32 | use App\Http\Models\Auth\UserRole; |
33 | use App\Http\Models\HubspotProperties; |
34 | use App\Http\Models\Plans; |
35 | use App\Http\Models\SalesProTeamManager; |
36 | use App\Http\Resources\AdminCenterCompanyGroupResource; |
37 | use App\Http\Resources\AdminCenterUserResource; |
38 | use App\Http\Resources\UserDetailsReportingResource; |
39 | use App\Http\Resources\UserDetailsReportResource; |
40 | use App\Http\Services\Admin\Groups\AdminGroupsService; |
41 | use App\Http\Services\Admin\Reports\AccountCenterReportingService; |
42 | use App\Http\Services\Admin\Reports\FindUsersOverviewFilter; |
43 | use App\Http\Services\Admin\Users\AdminUsersService; |
44 | use App\Http\Services\InstancyServiceV2; |
45 | use App\Imports\UsersImport; |
46 | use App\Jobs\Emails\AddNewUserReminder; |
47 | use App\Mail\AdminCenterAddExistingUser; |
48 | use App\Mail\AdminCenterAddNewUser; |
49 | use App\Mail\AdminCenterAddNewUserByEmail; |
50 | use App\Mail\InvitationToJoinFlymsgEmail; |
51 | use App\Mail\SendResetPasswordRequestedEmail; |
52 | use App\Traits\AccountCenter\Reporting\ChartTrait; |
53 | use Carbon\Carbon; |
54 | use Illuminate\Foundation\Auth\SendsPasswordResetEmails; |
55 | use Illuminate\Http\JsonResponse; |
56 | use Illuminate\Http\Request; |
57 | use Illuminate\Support\Facades\Hash; |
58 | use Illuminate\Support\Facades\Password; |
59 | use Illuminate\Support\Str; |
60 | use Illuminate\Validation\Rule; |
61 | use MongoDB\BSON\UTCDateTime; |
62 | use App\Jobs\Emails\ReactivateUserNotification; |
63 | use App\Jobs\Emails\AddNewUserNotification; |
64 | use App\Events\DeleteInstancyGroup; |
65 | use App\Services\Email\EmailService; |
66 | |
67 | class AdminAccountCenterDashboardController extends Controller |
68 | { |
69 | use SendsPasswordResetEmails; |
70 | use ChartTrait; |
71 | |
72 | public function __construct( |
73 | private AdminUsersService $adminUsersService, |
74 | private AdminGroupsService $adminGroupsService, |
75 | private AccountCenterReportingService $accountCenterReportingService, |
76 | private EmailService $emailService |
77 | ) {} |
78 | |
79 | private function _buildUsersResponse($model, $group_name, $subgroup_name, $is_invite, $company) |
80 | { |
81 | $identifier = "freemium"; |
82 | if ($model->subscription("main") && $model->subscription("main")->valid() && $model->subscription("main")->plan) { |
83 | $identifier = $model->subscription("main")->plan->identifier; |
84 | } elseif ($model->subscription("invitation")) { |
85 | $identifier = $model->subscription("invitation")->identifier; |
86 | } elseif ($model->status == "Invited") { |
87 | $invitation = AdminUserInvitation::where("email", $model->email)->first(); |
88 | if (filled($invitation?->plan_id)) { |
89 | $plan = Plans::find($invitation->plan_id); |
90 | $identifier = $plan?->identifier ?? "freemium"; |
91 | } |
92 | } |
93 | |
94 | $plan_name = $this->parseSubscriptionPlanName($identifier); |
95 | |
96 | $statusDate = match (true) { |
97 | !is_null($model->deactivated_at) |
98 | ? ($model->deactivated_at instanceof \Carbon\Carbon |
99 | ? $model->deactivated_at->toFormattedDateString() |
100 | : \Carbon\Carbon::parse($model->deactivated_at)->toFormattedDateString()) |
101 | : null, |
102 | !is_null($model->activation_date) => Carbon::parse($model->activation_date)->toFormattedDateString(), |
103 | !is_null($model->created_at) => $model->created_at->toFormattedDateString(), |
104 | default => null, |
105 | }; |
106 | |
107 | $status = $model->status ?? "Active"; |
108 | |
109 | $user_properties = [ |
110 | 'id' => $model->id, |
111 | 'avatar' => $model->avatar, |
112 | 'first_name' => $model->first_name, |
113 | 'last_name' => $model->last_name, |
114 | 'email' => $model->email, |
115 | 'role' => role($model->role), |
116 | 'group' => $group_name, |
117 | 'sub_group' => $subgroup_name, |
118 | 'group_subgroup' => $subgroup_name != "Not Assigned" ? $subgroup_name : $group_name, |
119 | "licenseType" => $plan_name, |
120 | "status" => $status, |
121 | "invitation_link" => $model->getInvitationLinkForAdminPortal(), |
122 | "created_at" => $model->created_at ?? $model->updated_at, |
123 | "user_id" => $model->id, |
124 | "group_id" => $model->company_group_id, |
125 | "group_subgroup_id" => $model->company_group_id, |
126 | "statusDate" => $statusDate, |
127 | "is_invite" => $is_invite, |
128 | "company_slug" => $company->slug, |
129 | ]; |
130 | |
131 | if ($user_properties["status"] == "Invited") { |
132 | $user_properties["invitation_link"] = $model->getInvitationLinkForAdminPortal(); |
133 | $invitation = AdminUserInvitation::where("email", $model->email)->first(); |
134 | if ($invitation) { |
135 | $user_properties["statusDate"] = $invitation?->updated_at?->toFormattedDateString(); |
136 | |
137 | if (filled($invitation->role_name)) { |
138 | $user_properties["role"] = $invitation->role_name; |
139 | } |
140 | } |
141 | } |
142 | |
143 | if ($model->sales_pro_team_manager) { |
144 | $user_properties["groups_admin"] = $model->sales_pro_team_manager?->company_group_ids; |
145 | } |
146 | |
147 | return $user_properties; |
148 | } |
149 | |
150 | private function _make_line_chart_data($flycut_usages, $months) |
151 | { |
152 | // Initialize the line chart data array |
153 | $line_chart_data = []; |
154 | $current_date = Carbon::now(); |
155 | for ($i = 0; $i < $months; $i++) { |
156 | $month_year = $current_date->subMonth()->format('M Y'); |
157 | $line_chart_data[$month_year] = [ |
158 | 'month_year' => $month_year, |
159 | 'flycuts_used' => 0, |
160 | 'characters_typed' => round(0, 2), |
161 | 'time_saved' => round(0, 2), |
162 | 'cost_saved' => round(0, 2), |
163 | ]; |
164 | } |
165 | |
166 | // Aggregate the data by month |
167 | $aggregated_data = $flycut_usages->groupBy(function ($date) { |
168 | return Carbon::parse($date->created_at)->format('M Y'); |
169 | }); |
170 | |
171 | // Process the aggregated data |
172 | foreach ($aggregated_data as $month_year => $usages) { |
173 | $month = Carbon::parse($usages->first()->created_at)->format('M Y'); |
174 | |
175 | $flycuts_used = $usages->count(); |
176 | $characters_typed = $usages->sum('characters_typed'); |
177 | $time_saved = $usages->sum('time_saved'); |
178 | $cost_saved = $usages->sum('cost_saved'); |
179 | |
180 | $line_chart_data[$month] = [ |
181 | 'month_year' => $month_year, |
182 | 'flycuts_used' => $flycuts_used, |
183 | 'characters_typed' => round($characters_typed, 2), |
184 | 'time_saved' => round($time_saved, 2), |
185 | 'cost_saved' => round($cost_saved, 2), |
186 | ]; |
187 | } |
188 | |
189 | // Convert month-year strings to DateTime objects and sort by date |
190 | uksort($line_chart_data, function ($a, $b) { |
191 | return strtotime($a) - strtotime($b); |
192 | }); |
193 | |
194 | return $line_chart_data; |
195 | } |
196 | |
197 | private function _make_line_chart_data_for_counts($flycuts, $months) |
198 | { |
199 | // Initialize an array with 12 months set to 0 |
200 | $line_chart_data = []; |
201 | $current_date = Carbon::now(); |
202 | for ($i = 0; $i < $months; $i++) { |
203 | $month_year = $current_date->subMonth()->format('M Y'); |
204 | $line_chart_data[$month_year] = ['count' => 0]; |
205 | } |
206 | |
207 | // Reset the current date to now |
208 | $current_date = Carbon::now(); |
209 | |
210 | // Aggregate the data by month |
211 | $aggregated_data = $flycuts->groupBy(function ($date) { |
212 | return Carbon::parse($date->created_at)->format('Y-m'); |
213 | }); |
214 | |
215 | // Process the aggregated data and populate the line chart data array |
216 | foreach ($aggregated_data as $month_year => $usages) { |
217 | $month = Carbon::parse($usages->first()->created_at)->format('M Y'); |
218 | $flycuts_used = $usages->count(); |
219 | $line_chart_data[$month] = ['count' => $flycuts_used]; |
220 | } |
221 | |
222 | // Ensure the data is sorted by date keys |
223 | uksort($line_chart_data, function ($a, $b) { |
224 | return strtotime($a) - strtotime($b); |
225 | }); |
226 | |
227 | return $line_chart_data; |
228 | } |
229 | |
230 | private function _make_line_chart_data_extension($extensions_data, $months, $start_date) |
231 | { |
232 | $line_chart_data = []; |
233 | for ($i = 0; $i <= $months; $i++) { |
234 | $month_year = $start_date->copy()->addMonths($i)->format('M Y'); |
235 | $line_chart_data[$month_year] = [ |
236 | 'edge_installed' => 0, |
237 | 'chrome_installed' => 0, |
238 | 'uninstalls' => 0, |
239 | ]; |
240 | } |
241 | |
242 | $aggregated_data = $extensions_data->groupBy(function ($data) { |
243 | return Carbon::parse($data->created_at)->format('M Y'); |
244 | }); |
245 | |
246 | foreach ($aggregated_data as $month_year => $usages) { |
247 | $edge_count = $usages->where('flymsg_edge_extension_installed', 'Yes')->count(); |
248 | $chrome_count = $usages->where('flymsg_chrome_extension_installed', 'Yes')->count(); |
249 | $uninstall_count = $usages->where('flymsg_chrome_extension_uninstalled', 'Yes')->count() + $usages->where('flymsg_edge_extension_uninstalled', 'Yes')->count(); |
250 | |
251 | if (isset($line_chart_data[$month_year])) { |
252 | $line_chart_data[$month_year]['edge_installed'] += $edge_count; |
253 | $line_chart_data[$month_year]['chrome_installed'] += $chrome_count; |
254 | $line_chart_data[$month_year]['uninstalls'] += $uninstall_count; |
255 | } |
256 | } |
257 | |
258 | uksort($line_chart_data, function ($a, $b) { |
259 | return strtotime($a) - strtotime($b); |
260 | }); |
261 | |
262 | return $line_chart_data; |
263 | } |
264 | |
265 | private function _assign_plan($user, $plan, $selected_plan, $email, $is_reactivate = false) |
266 | { |
267 | if ($plan) { |
268 | $company_license = CompanyLicenses::where('company_id', $user->company_id) |
269 | ->active() |
270 | ->first(); |
271 | if (!$company_license) { |
272 | throw new ExpectedException("Failed to assign $selected_plan. The company doesn't have any active license."); |
273 | } |
274 | |
275 | switch ($selected_plan) { |
276 | case 'Starter': |
277 | case 'Starter Yearly': |
278 | if ($company_license->total_starter_license_remaining < 1) { |
279 | // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable"); |
280 | } |
281 | $company_license->decrement('total_starter_license_remaining'); |
282 | break; |
283 | case 'Growth': |
284 | case 'Growth Yearly': |
285 | if ($company_license->total_growth_license_remaining < 1) { |
286 | // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable"); |
287 | } |
288 | $company_license->decrement('total_growth_license_remaining'); |
289 | break; |
290 | case 'Sales Pro': |
291 | case 'FlyMSG.io Sales Pro - YR Plan': |
292 | if ($company_license->total_sales_pro_license_remaining < 1) { |
293 | // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable"); |
294 | } |
295 | $company_license->decrement('total_sales_pro_license_remaining'); |
296 | break; |
297 | case 'Sales Pro Teams': |
298 | case 'Pro Plan Teams - ENT': |
299 | if ($company_license->total_sales_pro_teams_license_remaining < 1) { |
300 | // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable"); |
301 | } |
302 | $company_license->decrement('total_sales_pro_teams_license_remaining'); |
303 | break; |
304 | } |
305 | |
306 | if ($user instanceof User) { |
307 | if ($user->subscribed('main')) { |
308 | if ($is_reactivate) { |
309 | $user->subscription('main')->markAsCancelledOnlyInDB(); |
310 | } else { |
311 | $user->subscription('main')->cancel(); |
312 | } |
313 | } else { |
314 | $subscription = $user->subscriptions()->latest()->first(); |
315 | if ($subscription) { |
316 | $subscription->update([ |
317 | 'stripe_status' => 'canceled', |
318 | 'ends_at' => Carbon::now()->toDateTimeString(), |
319 | ]); |
320 | } |
321 | } |
322 | |
323 | $end_date = $company_license->contract_end_date; |
324 | |
325 | $user->subscriptions()->create([ |
326 | 'name' => 'main', |
327 | 'stripe_status' => 'active', |
328 | 'stripe_plan' => $plan->stripe_id, |
329 | 'quantity' => "1", |
330 | 'ends_at' => $end_date, |
331 | 'starts_at' => Carbon::now()->toDateTimeString(), |
332 | ]); |
333 | |
334 | if (in_array($selected_plan, ["Sales Pro", "Sales Pro Teams"])) { |
335 | try { |
336 | $group = CompanyGroup::find($user->company_group_id); |
337 | $company = Company::find($user->company_id); |
338 | |
339 | $groupId = false; |
340 | if ($company) { |
341 | $groupId = $company->instancy_id; |
342 | } elseif ($group) { |
343 | $groupId = $group->instancy_id; |
344 | } |
345 | |
346 | (new InstancyServiceV2)->createInstancyUser($email, $groupId); |
347 | } catch (\Throwable $th) { |
348 | FlyMSGLogger::logError(__METHOD__, $th); |
349 | } |
350 | } |
351 | } |
352 | } |
353 | } |
354 | |
355 | private function filterUsersByAdmin($query, $role, $company_id, $admin_group_ids) |
356 | { |
357 | return match ($role) { |
358 | Role::GLOBAL_ADMIN, Role::VENGRESO_ADMIN => $query->where("company_id", "=", $company_id), |
359 | default => $query->whereIn("company_group_id", $admin_group_ids), |
360 | }; |
361 | } |
362 | |
363 | private function filterUsersByGroupIds($query, $role, $group_ids, $company_id, $admin_group_ids) |
364 | { |
365 | if ($role == Role::GLOBAL_ADMIN || $role == Role::VENGRESO_ADMIN) { |
366 | return $query->where("company_id", "=", $company_id); |
367 | } elseif (count($group_ids) == 0) { |
368 | return $query->whereIn("company_group_id", $admin_group_ids); |
369 | } |
370 | |
371 | return $query; |
372 | } |
373 | |
374 | public function users(Request $request) |
375 | { |
376 | // Deactivated users are soft deleted users |
377 | $only_deactivated = $request->has('deactivated') && $request->deactivated == "true"; |
378 | |
379 | $admin = auth()->user(); |
380 | $roles = $admin->role; |
381 | $role = role($roles); |
382 | $company_id = $request->company_id; |
383 | $admin_group_ids = $request->admin_group_ids; |
384 | |
385 | $company = Company::find($company_id); |
386 | |
387 | $users = User::select([ |
388 | "id", |
389 | "avatar", |
390 | "first_name", |
391 | "last_name", |
392 | "email", |
393 | "role", |
394 | "company_id", |
395 | "company_group_id", |
396 | "sales_pro_team_manager_id", |
397 | "status", |
398 | "created_at", |
399 | 'updated_at', |
400 | "deleted_at", |
401 | 'activation_date', |
402 | "deactivated_at", |
403 | ]); |
404 | |
405 | $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids); |
406 | |
407 | if ($only_deactivated) { |
408 | $users = $users->whereNotNull('deactivated_at'); |
409 | } else { |
410 | $users = $users->whereNull('deactivated_at'); |
411 | } |
412 | |
413 | $users = $users->latest(); |
414 | $users = $users->get(); |
415 | |
416 | // TODO MA. Please find a better way to do this and |
417 | // avoid this loop. |
418 | $response_builder = []; |
419 | foreach ($users as $user) { |
420 | $group_name = $user->company_group ? $user->company_group->name : "Not Assigned"; |
421 | $subgroup_name = $user->company_group ? $user->company_group->name : "Not Assigned"; |
422 | |
423 | if ($user->company_group && $user->company_group->parent_id) { |
424 | $group_name = $user->company_group->parent ? $user->company_group->parent->name : "Not Assigned"; |
425 | } |
426 | |
427 | if ($user->company_group && !$user->company_group->parent_id) { |
428 | $subgroup_name = "Not Assigned"; |
429 | } |
430 | |
431 | $user_properties = $this->_buildUsersResponse($user, $group_name, $subgroup_name, false, $company); |
432 | |
433 | $response_builder[] = $user_properties; |
434 | } |
435 | |
436 | |
437 | |
438 | if (!$only_deactivated) { |
439 | $invitations = $this->filterUsersByAdmin( |
440 | AdminUserInvitation::where("company_id", $company_id) |
441 | ->whereNull('deactivated_at') |
442 | ->whereNotIn("email", $users->pluck("email")), |
443 | $role, |
444 | $company_id, |
445 | $admin_group_ids |
446 | )->get(); |
447 | |
448 | foreach ($invitations as $invitation) { |
449 | $group_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned"; |
450 | $subgroup_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned"; |
451 | |
452 | if ($invitation->company_group && $invitation->company_group->parent_id) { |
453 | $group_name = $invitation->company_group->parent ? $invitation->company_group->parent->name : "Not Assigned"; |
454 | } |
455 | |
456 | if ($invitation->company_group && !$invitation->company_group->parent_id) { |
457 | $subgroup_name = "Not Assigned"; |
458 | } |
459 | |
460 | $user_properties = $this->_buildUsersResponse($invitation, $group_name, $subgroup_name, true, $company); |
461 | |
462 | $response_builder[] = $user_properties; |
463 | } |
464 | } else { |
465 | |
466 | $invitations = $this->filterUsersByAdmin( |
467 | AdminUserInvitation::where("company_id", $company_id) |
468 | ->whereNotNull('deactivated_at') |
469 | ->whereNotIn("email", $users->pluck("email")), |
470 | $role, |
471 | $company_id, |
472 | $admin_group_ids |
473 | )->get(); |
474 | |
475 | foreach ($invitations as $invitation) { |
476 | $group_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned"; |
477 | $subgroup_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned"; |
478 | |
479 | if ($invitation->company_group && $invitation->company_group->parent_id) { |
480 | $group_name = $invitation->company_group->parent ? $invitation->company_group->parent->name : "Not Assigned"; |
481 | } |
482 | |
483 | if ($invitation->company_group && !$invitation->company_group->parent_id) { |
484 | $subgroup_name = "Not Assigned"; |
485 | } |
486 | |
487 | $user_properties = $this->_buildUsersResponse($invitation, $group_name, $subgroup_name, true, $company); |
488 | |
489 | $response_builder[] = $user_properties; |
490 | } |
491 | } |
492 | |
493 | return response()->json( |
494 | data: [ |
495 | 'success' => true, |
496 | 'users' => $response_builder, |
497 | ], |
498 | status: 200 |
499 | ); |
500 | } |
501 | |
502 | public function groups(Request $request) |
503 | { |
504 | $user = auth()->user(); |
505 | $roles = $user->role; |
506 | $role = role($roles); |
507 | $show_not_assigned = $request->show_not_assigned === "true"; |
508 | $company_id = $request->company_id; |
509 | $admin_group_ids = $request->admin_group_ids; |
510 | |
511 | $groups = CompanyGroup::select(["id", "name", "company_id", "parent_id"]) |
512 | ->whereNull("parent_id") |
513 | ->where("company_id", $company_id) |
514 | ->with(["users", "subgroups"]); |
515 | |
516 | if ($role == Role::GLOBAL_ADMIN || $role == Role::VENGRESO_ADMIN) { |
517 | $groups = $groups->get(); |
518 | } else { |
519 | $sales_pro_manager = SalesProTeamManager::where("email", $user->email)->first(); |
520 | if (!$sales_pro_manager) { |
521 | throw new ExpectedException("User role is not setup to handle [GroupAdmin/ReportingAdmin] roles well. We have been notified about it!"); |
522 | } |
523 | $groups = $groups->whereIn("_id", $admin_group_ids)->get(); |
524 | } |
525 | |
526 | if ($show_not_assigned) { |
527 | $notAssignedGroup = new CompanyGroup(); |
528 | $notAssignedGroup->name = "Not Assigned"; |
529 | $notAssignedGroup->slug = "not-assigned"; |
530 | $notAssignedGroup->id = -1; |
531 | $groups->push($notAssignedGroup); |
532 | } |
533 | |
534 | $transformer = AdminCenterCompanyGroupResource::collection($groups); |
535 | |
536 | return response()->json(data: [ |
537 | 'success' => true, |
538 | 'groups' => $transformer->toArray($request), |
539 | ], status: 200); |
540 | } |
541 | |
542 | public function search_users(Request $request) |
543 | { |
544 | $user = auth()->user(); |
545 | $roles = $user->role; |
546 | $role = role($roles); |
547 | $search_term = $request->search_term; |
548 | $company_id = $request->company_id; |
549 | $admin_group_ids = $request->admin_group_ids; |
550 | |
551 | $users = User::select([ |
552 | "id", |
553 | "first_name", |
554 | "last_name", |
555 | "email", |
556 | "role", |
557 | "company_id", |
558 | "company_group_id", |
559 | "sales_pro_team_manager_id", |
560 | "deactivated_at", |
561 | "status", |
562 | "created_at", |
563 | "avatar" |
564 | ]); |
565 | |
566 | if ($search_term) { |
567 | $users = $users->where("email", "like", "%$search_term%") |
568 | ->orWhere("first_name", "like", "%$search_term%") |
569 | ->orWhere("last_name", "like", "%$search_term%"); |
570 | } |
571 | |
572 | $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids); |
573 | |
574 | $users = $users->get(); |
575 | |
576 | $users_response = AdminCenterUserResource::collection($users); |
577 | return response()->json(data: [ |
578 | 'success' => true, |
579 | 'users' => $users_response->toArray($request), |
580 | ], status: 200); |
581 | } |
582 | |
583 | public function update_user(Request $request, $slug, User $user, UpdateUserAction $updateUserAction) |
584 | { |
585 | $userDTO = new UpdateUserDTO( |
586 | email: strtolower($request->email), |
587 | firstName: $request->first_name, |
588 | lastName: $request->last_name, |
589 | ); |
590 | |
591 | $updateUserAction->execute($user, $userDTO); |
592 | |
593 | return response()->json(data: [ |
594 | 'success' => true, |
595 | 'user' => new AdminCenterUserResource($user) |
596 | ], status: 200); |
597 | } |
598 | |
599 | public function update_invite(Request $request, $slug, AdminUserInvitation $invite) |
600 | { |
601 | $inputData = $request->all(); |
602 | $newEmail = strtolower($inputData['email']); |
603 | $sendEmail = strtolower($invite->email) !== $newEmail; |
604 | $inputData['email'] = $newEmail; |
605 | |
606 | if (!$invite->update($inputData)) { |
607 | throw new ExpectedException("Failed to update the users data. Please try again later."); |
608 | } |
609 | |
610 | if ($sendEmail) { |
611 | $this->emailService->send( |
612 | $invite->email, |
613 | new AdminCenterAddNewUserByEmail( |
614 | email: $invite->email |
615 | ), |
616 | 'cac_add_user_by_email' |
617 | ); |
618 | } |
619 | |
620 | return response()->json(data: [ |
621 | 'success' => true, |
622 | 'user' => new AdminCenterUserResource($invite) |
623 | ], status: 200); |
624 | } |
625 | |
626 | public function create_user_manually(Request $request) |
627 | { |
628 | $existing_user = false; |
629 | |
630 | $validated_data = $request->validate([ |
631 | "first_name" => "required|string", |
632 | "last_name" => "required|string", |
633 | "email" => "required|email|max:255", |
634 | "selected_plan" => ["required", "string", Rule::in(["Starter", "Growth", "Sales Pro", "Sales Pro Teams"])] |
635 | ]); |
636 | |
637 | $admin = auth()->user(); |
638 | $company_id = $request->company_id; |
639 | |
640 | $email = strtolower($request->email); |
641 | $password = Str::password(16); |
642 | $hashed_password = bcrypt($password); |
643 | $selected_plan = $request->selected_plan; |
644 | |
645 | $user = User::where("email", $email) |
646 | ->where("company_id", $company_id) |
647 | ->first(); |
648 | if ($user) { |
649 | throw new ExpectedException("The user with email {$email} already exists in your Organization."); |
650 | } |
651 | |
652 | $planTitle = ""; |
653 | if ($selected_plan == "Sales Pro") { |
654 | $planTitle = "FlyMSG.io Sales Pro - YR Plan"; |
655 | } else if ($selected_plan == "Growth") { |
656 | $planTitle = "Growth Yearly"; |
657 | } else if ($selected_plan == "Starter") { |
658 | $planTitle = "Starter Yearly"; |
659 | } else if ($selected_plan == "Sales Pro Teams") { |
660 | $planTitle = "Pro Plan Teams - ENT"; |
661 | } |
662 | |
663 | $plan = Plans::firstWhere("title", $planTitle); |
664 | |
665 | $password_expiry = Carbon::now()->addDays(7); |
666 | |
667 | $user = User::where("email", $email) |
668 | ->first(); |
669 | if ($user) { |
670 | $existing_user = true; |
671 | |
672 | $user->company_id = $company_id; |
673 | $user->invited_to_company = true; |
674 | $user->invited_to_company_by_admin = $admin->email; |
675 | $user->status = "Invited"; |
676 | $user->save(); |
677 | |
678 | $this->emailService->send( |
679 | $email, |
680 | new AdminCenterAddExistingUser( |
681 | admin_email: $admin->email, |
682 | email: $user->email, |
683 | company: $admin->company->name, |
684 | ), |
685 | 'cac_add_existent_user' |
686 | ); |
687 | } else { |
688 | $existing_user = false; |
689 | |
690 | $user = new User(); |
691 | $user->fill($validated_data); |
692 | $user->status = "Invited"; |
693 | $user->email = $email; |
694 | $user->password = $hashed_password; |
695 | $user->company_id = $company_id; |
696 | $user->temp_password_expiry = $password_expiry->toDateTimeString(); |
697 | $user->temp_password = $hashed_password; |
698 | $user->email_verified_at = new UTCDateTime(now()->getTimestamp() * 1000); |
699 | $user->onboardingv2_presented = true; |
700 | |
701 | $user->save(); |
702 | } |
703 | |
704 | $password_expiry = $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A"); |
705 | |
706 | $data = [ |
707 | "email" => $email, |
708 | "company_id" => $company_id, |
709 | "company_group_id" => $request->group_id, |
710 | "company_subgroup_id" => $request->subgroup_id, |
711 | "temp_password_expiry" => $user->temp_password_expiry, |
712 | "temp_password" => $hashed_password, |
713 | "password" => $hashed_password, |
714 | "admin_email" => $admin->email |
715 | ]; |
716 | |
717 | $invitation = AdminUserInvitation::updateOrCreate(['email' => $email], $data); |
718 | |
719 | // if there is plan, assign it |
720 | // if there is a plan, reduce the count after assignement in the company license |
721 | if ($plan) { |
722 | $invitation->plan = $plan; |
723 | $invitation->plan_id = $plan->id; |
724 | $invitation->save(); |
725 | if (!$existing_user) { |
726 | $this->_assign_plan($user, $plan, $selected_plan, $email); |
727 | } |
728 | } |
729 | |
730 | $data = [ |
731 | "email" => $user->email, |
732 | "first_name" => $user->first_name, |
733 | "last_name" => $user->last_name, |
734 | ]; |
735 | |
736 | if (!$existing_user) { |
737 | Registered::dispatch($user, $data); |
738 | |
739 | $this->emailService->send( |
740 | $email, |
741 | new AdminCenterAddNewUser( |
742 | email: $email, |
743 | password: $password, |
744 | inviter: $admin->email, |
745 | password_expiry: $password_expiry, |
746 | ), |
747 | 'cac_add_new_user_manually' |
748 | ); |
749 | |
750 | $companyName = $admin->company->name; |
751 | $companyEmail = $admin->email; |
752 | |
753 | if ($company_id) { |
754 | $company = Company::find($user->company_id); |
755 | $companyLicense = CompanyLicenses::where('company_id', $company->id)->first(); |
756 | $community = $companyLicense->business_pro_enterprise_plus ?? []; |
757 | $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community); |
758 | |
759 | if ($isPro) { |
760 | AddNewUserNotification::dispatch($data['email'], $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2)); |
761 | } |
762 | } |
763 | |
764 | $addnewUserEmailJob = (new AddNewUserReminder( |
765 | $email, |
766 | $password, |
767 | $admin->email, |
768 | $password_expiry, |
769 | $this->emailService |
770 | ))->delay(now()->addHours(48)); |
771 | |
772 | $job = app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addnewUserEmailJob); |
773 | |
774 | $invitation->reminder_job_id = $job; |
775 | $invitation->save(); |
776 | } |
777 | |
778 | return response()->json(data: [ |
779 | 'success' => true, |
780 | 'user' => (new AdminCenterUserResource($user))->setPlan($plan), |
781 | ], status: 200); |
782 | } |
783 | |
784 | public function resend_temporary_password(Request $request) |
785 | { |
786 | $validated_data = $request->validate([ |
787 | "email" => "required|email|max:255", |
788 | ]); |
789 | |
790 | $email = strtolower($validated_data["email"]); |
791 | |
792 | $user = User::where("email", $email) |
793 | ->first(); |
794 | |
795 | $invitation = AdminUserInvitation::where("email", $email) |
796 | ->first(); |
797 | |
798 | // if ($user && $invitation) { |
799 | // throw new ExpectedException("The user with email {$email} already exists in your company."); |
800 | // } |
801 | |
802 | $password = Str::password(15); |
803 | $hashed_password = bcrypt($password); |
804 | |
805 | $password_expiry = Carbon::now()->addDays(7); |
806 | |
807 | $data = [ |
808 | "email" => $email, |
809 | "temp_password_expiry" => $password_expiry->toDateTimeString(), |
810 | "temp_password" => $hashed_password, |
811 | "password" => $hashed_password, |
812 | ]; |
813 | |
814 | if ($user) { |
815 | $user->password = $hashed_password; |
816 | $user->temp_password = $hashed_password; |
817 | $user->temp_password_expiry = $password_expiry->toDateTimeString(); |
818 | $user->save(); |
819 | } |
820 | |
821 | AdminUserInvitation::updateOrCreate(['email' => $email], $data); |
822 | |
823 | $this->emailService->send( |
824 | $email, |
825 | new AdminCenterAddNewUser( |
826 | email: $email, |
827 | password: $password, |
828 | inviter: $invitation->admin_email, |
829 | password_expiry: $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A"), |
830 | emailSubject: "New Invitation. Welcome to FlyMSG! 🧡" |
831 | ), |
832 | 'cac_add_user' |
833 | ); |
834 | |
835 | return response()->json( |
836 | data: [ |
837 | 'success' => true, |
838 | 'message' => "Temporary password reset sent successfully", |
839 | ], |
840 | status: 200 |
841 | ); |
842 | } |
843 | |
844 | public function create_user_by_csv(Request $request) |
845 | { |
846 | $validated_data = $request->validate([ |
847 | "file" => "required", |
848 | ]); |
849 | |
850 | $file = $request->file('file'); |
851 | |
852 | $admin = auth()->user(); |
853 | $company_id = $request->company_id; |
854 | |
855 | // TODO MA |
856 | // Prcess csv read it into array |
857 | $users_in_file = []; |
858 | |
859 | $invitation_sent_count = 0; |
860 | |
861 | foreach ($users_in_file as $user_object) { |
862 | $email = strtolower($user_object["email"]); |
863 | $plan_name = $user_object["plan"]; |
864 | |
865 | $existing_user = false; |
866 | |
867 | $plan = match ($plan_name) { |
868 | "Sales Pro" => Plans::whereTitle("FlyMSG.io Sales Pro - YR Plan")->first(), |
869 | "Starter" => Plans::whereTitle("Starter Yearly")->first(), |
870 | "Growth" => Plans::whereTitle("Growth Yearly")->first(), |
871 | "Sales Pro Teams" => Plans::whereTitle("Pro Plan Teams - ENT")->first(), |
872 | default => null, |
873 | }; |
874 | |
875 | if (!$plan) { |
876 | throw new ExpectedException("The selected plan for {$email} was not found."); |
877 | } |
878 | |
879 | $user = User::where("email", $email) |
880 | ->first(); |
881 | if ($user) { |
882 | $existing_user = true; |
883 | |
884 | $user->company_id = $company_id; |
885 | $user->invited_to_company = true; |
886 | $user->invited_to_company_by_admin = $admin->email; |
887 | $user->status = "Invited"; |
888 | $user->save(); |
889 | |
890 | $this->emailService->send( |
891 | $email, |
892 | new AdminCenterAddExistingUser( |
893 | admin_email: $admin->email, |
894 | email: $user->email, |
895 | company: $admin->company->name, |
896 | ), |
897 | 'cac_add_existent_user' |
898 | ); |
899 | } else { |
900 | $existing_user = false; |
901 | $invitation_sent_count++; |
902 | } |
903 | |
904 | $invitation = new AdminUserInvitation(); |
905 | $invitation->email = $email; |
906 | $invitation->plan_id = $plan->id; |
907 | $invitation->plan = $plan; |
908 | $invitation->company_id = $company_id; |
909 | $invitation->admin_email = $user->email; |
910 | $invitation->save(); |
911 | |
912 | if (!$existing_user) { |
913 | $this->emailService->send( |
914 | $invitation->email, |
915 | new InvitationToJoinFlymsgEmail( |
916 | email: $invitation->email, |
917 | password: "" |
918 | ), |
919 | 'cac_invitation_to_join' |
920 | ); |
921 | } |
922 | } |
923 | |
924 | return response()->json( |
925 | data: [ |
926 | 'success' => true, |
927 | 'message' => "{$invitation_sent_count} users invited successfully", |
928 | ], |
929 | status: 200 |
930 | ); |
931 | } |
932 | |
933 | public function deactivate_user(Request $request, $slug, User $user) |
934 | { |
935 | $admin = auth()->user(); |
936 | $company_id = $request->company_id; |
937 | |
938 | $this->adminUsersService->deactivateUser($user, $admin->id, $company_id); |
939 | |
940 | return response()->json(data: [ |
941 | 'success' => true, |
942 | 'message' => "User deactivated successfully", |
943 | ], status: 200); |
944 | } |
945 | |
946 | public function deactivate_invited_user(Request $request, $slug, $user_id) |
947 | { |
948 | $admin = auth()->user(); |
949 | try { |
950 | $invitation = AdminUserInvitation::find($user_id); |
951 | |
952 | if (!$invitation) { |
953 | $user_detail = User::find($user_id); |
954 | |
955 | $invitation = AdminUserInvitation::where('email', $user_detail->email)->first(); |
956 | } |
957 | |
958 | if (!empty($user_detail)) { |
959 | $this->adminUsersService->rejectUserInvitation($user_detail, $admin); |
960 | } |
961 | |
962 | $this->adminUsersService->deleteInvitedUser($invitation); |
963 | |
964 | return response()->json(data: [ |
965 | 'success' => true, |
966 | 'message' => "User deactivated successfully", |
967 | ], status: 200); |
968 | } catch (\Exception $th) { |
969 | return response()->json(data: [ |
970 | 'success' => false, |
971 | 'message' => "Something went wrong, please try again", |
972 | ], status: 404); |
973 | } |
974 | } |
975 | |
976 | /** |
977 | * Hard delete a user fro, the database. This action cannot |
978 | * be undone. |
979 | * |
980 | * @param Request $request |
981 | * @param User $user |
982 | * |
983 | * @return JsonResponse |
984 | */ |
985 | public function delete_user(Request $request, $slug, User $user) |
986 | { |
987 | $name = $user->first_name . " " . $user->last_name; |
988 | $admin = auth()->user(); |
989 | |
990 | $this->adminUsersService->deleteUser($user, $admin); |
991 | |
992 | return response()->json(data: [ |
993 | 'success' => true, |
994 | 'message' => "$name deleted successfully", |
995 | ], status: 200); |
996 | } |
997 | |
998 | public function reset_password(Request $request, $slug, User $user) |
999 | { |
1000 | if ($user->status == "Invited") { |
1001 | throw new ExpectedException("This user has not signed up yet. Please try again later."); |
1002 | } |
1003 | |
1004 | $request = $request->merge(["email" => $user->email]); |
1005 | $response = $this->broker()->sendResetLink($this->credentials($request)); |
1006 | |
1007 | if ($response != Password::RESET_LINK_SENT) { |
1008 | throw new ExpectedException("Failed to send password reset link. Please try again later"); |
1009 | } |
1010 | |
1011 | return response()->json(data: [ |
1012 | 'success' => true, |
1013 | 'message' => "Password reset successfully. User will get the link to update their password.", |
1014 | ], status: 200); |
1015 | } |
1016 | |
1017 | public function reset_invitation_password(Request $request, $slug, AdminUserInvitation $invite) |
1018 | { |
1019 | if ($invite->status == "Invited") { |
1020 | throw new ExpectedException("This invite has not signed up yet. Please try again later."); |
1021 | } |
1022 | |
1023 | $request = $request->merge(["email" => $invite->email]); |
1024 | $response = $this->broker()->sendResetLink($this->credentials($request)); |
1025 | |
1026 | if ($response != Password::RESET_LINK_SENT) { |
1027 | throw new ExpectedException("Failed to send password reset link. Please try again later"); |
1028 | } |
1029 | |
1030 | return response()->json(data: [ |
1031 | 'success' => true, |
1032 | 'message' => "Password reset successfully. User will get the link to update their password.", |
1033 | ], status: 200); |
1034 | } |
1035 | |
1036 | public function resend_user_invitation(Request $request, SendUserInvitationAction $sendUserInvitationAction) |
1037 | { |
1038 | $admin = auth()->user(); |
1039 | $validated_data = $request->validate([ |
1040 | 'email' => 'required', |
1041 | ]); |
1042 | |
1043 | $email = $validated_data['email']; |
1044 | |
1045 | $invitation = AdminUserInvitation::where('email', $email)->first(); |
1046 | |
1047 | $email = strtolower($email); |
1048 | |
1049 | if (!$invitation) { |
1050 | throw new ExpectedException("Previous invitation not found"); |
1051 | } |
1052 | |
1053 | $user = User::where('email', $email) |
1054 | ->whereStatus("Invited") |
1055 | ->first(); |
1056 | |
1057 | $sendInvitationDTO = new SendUserInvitationDTO( |
1058 | user: $user ?? $invitation, |
1059 | invitation: $invitation, |
1060 | newEmail: $email, |
1061 | adminEmail: $admin->email, |
1062 | companyName: $admin->company->name, |
1063 | ); |
1064 | |
1065 | $sendUserInvitationAction->execute($sendInvitationDTO); |
1066 | |
1067 | return response()->json(data: [ |
1068 | 'success' => true, |
1069 | 'message' => "User profile updated successfully", |
1070 | ], status: 200); |
1071 | } |
1072 | |
1073 | public function resend_invitations(Request $request) |
1074 | { |
1075 | $admin = auth()->user(); |
1076 | $role = $request->current_role; |
1077 | $company_id = $request->company_id; |
1078 | $admin_group_ids = $request->admin_group_ids; |
1079 | |
1080 | $users = User::select([ |
1081 | "id", |
1082 | "first_name", |
1083 | "last_name", |
1084 | "email", |
1085 | "role", |
1086 | "company_id", |
1087 | "company_group_id", |
1088 | "sales_pro_team_manager_id", |
1089 | "status", |
1090 | "created_at", |
1091 | "deleted_at", |
1092 | "deactivated_at", |
1093 | "avatar" |
1094 | ])->where("status", "Invited"); |
1095 | |
1096 | $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids); |
1097 | $users = $users->latest()->get(); |
1098 | |
1099 | foreach ($users as $user) { |
1100 | $userEmail = $user->email; |
1101 | $invitation = AdminUserInvitation::where('email', $userEmail)->first(); |
1102 | $userEmail = strtolower($user->email); |
1103 | |
1104 | if (!$invitation) { |
1105 | continue; |
1106 | } |
1107 | |
1108 | if ($user && $user->created_at->diffInMinutes($invitation?->updated_at) > 5) { |
1109 | $this->emailService->send( |
1110 | $userEmail, |
1111 | new AdminCenterAddExistingUser( |
1112 | admin_email: $admin->email, |
1113 | email: $userEmail, |
1114 | company: $admin->company->name, |
1115 | ), |
1116 | 'cac_add_existent_user' |
1117 | ); |
1118 | } else { |
1119 | $password = Str::random(16); |
1120 | $encrypted_password = bcrypt($password); |
1121 | $temp_password_expiry = Carbon::parse($invitation->temp_password_expiry); |
1122 | |
1123 | $invitation->password = $encrypted_password; |
1124 | $invitation->temp_password = $encrypted_password; |
1125 | $invitation->admin_email = $admin->email; |
1126 | $invitation->email = $userEmail; |
1127 | $invitation->save(); |
1128 | |
1129 | if ($user) { |
1130 | $user->password = $encrypted_password; |
1131 | $user->temp_password = $encrypted_password; |
1132 | $user->save(); |
1133 | } |
1134 | |
1135 | $this->emailService->send( |
1136 | $userEmail, |
1137 | new AdminCenterAddNewUser( |
1138 | email: $userEmail, |
1139 | password: $password, |
1140 | inviter: $admin->email, |
1141 | password_expiry: $temp_password_expiry->format("m/d/Y") . " at " . $temp_password_expiry->format("h:i A"), |
1142 | ), |
1143 | 'cac_resend_invitation' |
1144 | ); |
1145 | } |
1146 | } |
1147 | |
1148 | return response()->json(data: [ |
1149 | 'success' => true, |
1150 | 'message' => "Invites resent successfully", |
1151 | ], status: 200); |
1152 | } |
1153 | |
1154 | public function move_group(Request $request, $slug, User $user) |
1155 | { |
1156 | $validated_data = $request->validate([ |
1157 | 'to_group_id' => 'required', |
1158 | ]); |
1159 | |
1160 | $group = $this->adminGroupsService->getGroup($validated_data['to_group_id']); |
1161 | |
1162 | $user = $this->adminUsersService->moveUserToGroup($user, $group); |
1163 | |
1164 | return response()->json(data: [ |
1165 | 'success' => true, |
1166 | 'message' => "User profile updated successfully", |
1167 | 'user' => new AdminCenterUserResource($user->fresh()), |
1168 | ], status: 200); |
1169 | } |
1170 | |
1171 | public function move_group_invite(Request $request, $slug, AdminUserInvitation $invite) |
1172 | { |
1173 | $validated_data = $request->validate([ |
1174 | 'to_group_id' => 'required', |
1175 | ]); |
1176 | $invite->company_group_id = $validated_data['to_group_id']; |
1177 | $invite->save(); |
1178 | |
1179 | return response()->json(data: [ |
1180 | 'success' => true, |
1181 | 'message' => "User invitation updated successfully", |
1182 | 'user' => new AdminCenterUserResource($invite->fresh()), |
1183 | ], status: 200); |
1184 | } |
1185 | |
1186 | public function assign_role(Request $request, $slug, User $user) |
1187 | { |
1188 | $validated_data = $request->validate([ |
1189 | 'role_name' => 'required', |
1190 | 'groups' => 'sometimes', |
1191 | ]); |
1192 | |
1193 | $role = Role::find($validated_data['role_name']); |
1194 | if (!$role) { |
1195 | $role = Role::where("name", $validated_data['role_name'])->first(); |
1196 | if (!$role) { |
1197 | throw new ExpectedException("Role not found"); |
1198 | } |
1199 | } |
1200 | |
1201 | $adminRole = Role::where("name", Role::GLOBAL_ADMIN)->first(); |
1202 | |
1203 | if ($role->name != Role::GLOBAL_ADMIN) { |
1204 | $isAdmin = UserRole::where("role_id", $adminRole->id) |
1205 | ->where("user_id", $user->id) |
1206 | ->count() > 0; |
1207 | |
1208 | if ($isAdmin) { |
1209 | $roleId = $adminRole->id; |
1210 | $companyId = $request->company_id; |
1211 | $currentUserId = $user->id; |
1212 | |
1213 | $exists = UserRole::raw(function ($collection) use ($roleId, $companyId, $currentUserId) { |
1214 | return $collection->aggregate([ |
1215 | [ |
1216 | '$lookup' => [ |
1217 | 'from' => 'users', |
1218 | 'let' => ['userId' => ['$toObjectId' => '$user_id']], |
1219 | 'pipeline' => [ |
1220 | ['$match' => [ |
1221 | '$expr' => [ |
1222 | '$eq' => ['$$userId', '$_id'] |
1223 | ] |
1224 | ]], |
1225 | ], |
1226 | 'as' => 'user' |
1227 | ] |
1228 | ], |
1229 | [ |
1230 | '$match' => [ |
1231 | 'role_id' => $roleId, |
1232 | 'user.company_id' => $companyId, |
1233 | 'user_id' => ['$ne' => $currentUserId] |
1234 | ] |
1235 | ], |
1236 | [ |
1237 | '$limit' => 1 |
1238 | ] |
1239 | ]); |
1240 | }); |
1241 | |
1242 | $isLastAdmin = empty($exists->toArray()); |
1243 | |
1244 | if ($isAdmin && $isLastAdmin) { |
1245 | throw new ExpectedException("Last admin cannot be demoted", 409); |
1246 | } |
1247 | } |
1248 | } |
1249 | |
1250 | UserRole::where("user_id", $user->id)->delete(); |
1251 | |
1252 | UserRole::create([ |
1253 | 'user_id' => $user->id, |
1254 | 'role_id' => $role->id, |
1255 | ]); |
1256 | if ($role->name == Role::GROUP_ADMIN || $role->name = Role::REPORTING_ADMIN) { |
1257 | $group_ids = $validated_data['groups'] ?? []; |
1258 | |
1259 | $management_record = $user->sales_pro_team_manager; |
1260 | if (!$management_record) { |
1261 | $management_record = new SalesProTeamManager(); |
1262 | $management_record->user_id = $user->id; |
1263 | $management_record->company_id = $user->company_id; |
1264 | $management_record->first_name = $user->first_name; |
1265 | $management_record->last_name = $user->last_name; |
1266 | $management_record->email = $user->email; |
1267 | $management_record->save(); |
1268 | } |
1269 | |
1270 | if (!empty($group_ids)) { |
1271 | $groups = CompanyGroup::whereIn('_id', $group_ids)->get(); |
1272 | if ($groups->isNotEmpty()) { |
1273 | $management_record->groups()->sync($groups); |
1274 | } |
1275 | } |
1276 | |
1277 | $new_group_id = !empty($group_ids) ? $group_ids[0] : null; |
1278 | if ($user->company_group_id !== $new_group_id) { |
1279 | $user->company_group_id = $new_group_id; |
1280 | $user->save(); |
1281 | } |
1282 | } |
1283 | |
1284 | return response()->json(data: [ |
1285 | 'success' => true, |
1286 | 'message' => "User profile updated successfully", |
1287 | 'user' => new AdminCenterUserResource($user->fresh()), |
1288 | ], status: 200); |
1289 | } |
1290 | |
1291 | public function deactivate_user_bulk(Request $request) |
1292 | { |
1293 | $validated_data = $request->validate([ |
1294 | 'users' => 'required', |
1295 | ]); |
1296 | $admin = auth()->user(); |
1297 | $company_id = $request->company_id; |
1298 | |
1299 | $this->adminUsersService->deactivateUserBulk($validated_data['users'], $admin->id, $company_id); |
1300 | |
1301 | return response()->json(data: [ |
1302 | 'success' => true, |
1303 | 'message' => "Users deactivated successfully", |
1304 | ], status: 200); |
1305 | } |
1306 | |
1307 | private function _reactive_users(array $userIds) |
1308 | { |
1309 | $users = User::withTrashed()->whereIn('_id', $userIds)->get(); |
1310 | $admin = auth()->user(); |
1311 | |
1312 | foreach ($users as $user) { |
1313 | $user->restore(); |
1314 | |
1315 | $company_id = $user->company_id; |
1316 | if ($company_id) { |
1317 | $company = Company::find($user->company_id); |
1318 | $companyLicense = CompanyLicenses::where('company_id', $company->id)->first(); |
1319 | $community = $companyLicense->business_pro_enterprise_plus ?? []; |
1320 | $companyName = $company->name; |
1321 | $companyEmail = $admin->email; |
1322 | $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community); |
1323 | |
1324 | if ($isPro) { |
1325 | ReactivateUserNotification::dispatch($user->email, $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2)); |
1326 | } |
1327 | } |
1328 | } |
1329 | } |
1330 | |
1331 | private function _assign_plans_to_users(array $usersWithPlan) |
1332 | { |
1333 | foreach ($usersWithPlan as $userPlan) { |
1334 | $userId = $userPlan['user_id']; |
1335 | $planTitle = match ($userPlan['plan']) { |
1336 | "Sales Pro" => "FlyMSG.io Sales Pro - YR Plan", |
1337 | "Growth" => "Growth Yearly", |
1338 | "Starter" => "Starter Yearly", |
1339 | "Sales Pro Teams" => "Pro Plan Teams - ENT", |
1340 | default => $userPlan['plan'], |
1341 | }; |
1342 | |
1343 | $plan = Plans::where("title", $planTitle)->first(); |
1344 | |
1345 | if ($plan) { |
1346 | $user = User::withTrashed()->find($userId); |
1347 | if ($user) { |
1348 | $this->_assign_plan($user, $plan, $planTitle, $user->email, true); |
1349 | } |
1350 | } |
1351 | } |
1352 | } |
1353 | |
1354 | public function reactivate_user_bulk(Request $request) |
1355 | { |
1356 | $validated_data = $request->validate([ |
1357 | 'users' => 'required', |
1358 | 'usersWithPlan' => 'sometimes|array', |
1359 | ]); |
1360 | $admin = auth()->user(); |
1361 | if (isset($validated_data['users']) && in_array($admin->id, $validated_data['users'])) { |
1362 | throw new ExpectedException("You cannot reactivate your own account."); |
1363 | } |
1364 | |
1365 | $this->_reactive_users($validated_data['users']); |
1366 | |
1367 | if (!empty($validated_data['usersWithPlan'])) { |
1368 | $this->_assign_plans_to_users($validated_data['usersWithPlan']); |
1369 | } |
1370 | |
1371 | return response()->json(data: [ |
1372 | 'success' => true, |
1373 | 'message' => "Users reactivated successfully", |
1374 | ], status: 200); |
1375 | } |
1376 | |
1377 | public function delete_user_bulk(Request $request) |
1378 | { |
1379 | $validated_data = $request->validate([ |
1380 | 'users' => 'required', |
1381 | ]); |
1382 | |
1383 | $admin = auth()->user(); |
1384 | $company_id = $request->company_id; |
1385 | if (isset($validated_data['users']) && in_array($admin->id, $validated_data['users'])) { |
1386 | throw new ExpectedException("You cannot delete your own account."); |
1387 | } |
1388 | |
1389 | $users = User::whereIn('_id', $validated_data['users'])->get(); |
1390 | foreach ($users as $user) { |
1391 | // Get the users current plan and cancel it. |
1392 | $user_sub = $user->subscription("main"); |
1393 | if ($user_sub) { |
1394 | $plan = $user_sub->plan; |
1395 | if ($plan->identifier != "freemium") { |
1396 | $user_sub->markAsCancelledOnlyInDB(); |
1397 | } |
1398 | // Deternming the plan and increase the availability in company licenses |
1399 | $company_license = CompanyLicenses::where('company_id', $company_id) |
1400 | ->active() |
1401 | ->first(); |
1402 | if ($company_license) { |
1403 | $company_license->restoreLicenseCountForDeletedUsers($plan); |
1404 | } |
1405 | } |
1406 | $user->forceDelete(); |
1407 | } |
1408 | |
1409 | return response()->json(data: [ |
1410 | 'success' => true, |
1411 | 'message' => "Users deleted successfully", |
1412 | ], status: 200); |
1413 | } |
1414 | |
1415 | public function reset_password_bulk(Request $request) |
1416 | { |
1417 | $validated_data = $request->validate([ |
1418 | 'users' => 'required', |
1419 | ]); |
1420 | $admin = auth()->user(); |
1421 | $users = $validated_data['users']; |
1422 | foreach ($users as $email) { |
1423 | $email = strtolower($email); |
1424 | $user = User::where('email', $email)->first(); |
1425 | if (!$user) { |
1426 | // throw new ExpectedException("User not found"); |
1427 | continue; |
1428 | } |
1429 | |
1430 | $request = $request->merge(["email" => $email]); |
1431 | $token = $this->broker()->sendResetLink($this->credentials($request), function ($user, $token) { |
1432 | return $token; |
1433 | }); |
1434 | |
1435 | if (in_array($token, [Password::INVALID_USER, Password::RESET_THROTTLED])) { |
1436 | continue; |
1437 | } |
1438 | |
1439 | $this->emailService->send( |
1440 | $user->email, |
1441 | new SendResetPasswordRequestedEmail( |
1442 | name: $user->first_name . " " . $user->last_name, |
1443 | admin_email: $admin->email, |
1444 | email: $email, |
1445 | token: $token |
1446 | ), |
1447 | 'cac_send_password_requested' |
1448 | ); |
1449 | } |
1450 | return response()->json(data: [ |
1451 | 'success' => true, |
1452 | 'message' => "Password reset successfully. User will get the link to update their password.", |
1453 | ], status: 200); |
1454 | } |
1455 | |
1456 | public function resend_user_invitation_bulk(Request $request) |
1457 | { |
1458 | $admin = auth()->user(); |
1459 | $validated_data = $request->validate([ |
1460 | 'users' => 'required', |
1461 | ]); |
1462 | $users = $validated_data['users']; |
1463 | foreach ($users as $email) { |
1464 | $user = User::where('email', strtolower($email))->first(); |
1465 | |
1466 | $invitation = AdminUserInvitation::where('email', $email)->first(); |
1467 | $email = strtolower($email); |
1468 | if (!$invitation) { |
1469 | // throw new ExpectedException("Previous invitation not found"); |
1470 | continue; |
1471 | } |
1472 | |
1473 | if ($user && $user->created_at->diffInMinutes($invitation?->updated_at) > 5) { |
1474 | $this->emailService->send( |
1475 | $email, |
1476 | new AdminCenterAddExistingUser( |
1477 | admin_email: $admin->email, |
1478 | email: $email, |
1479 | company: $admin->company->name, |
1480 | ), |
1481 | 'cac_add_existent_user' |
1482 | ); |
1483 | } else { |
1484 | $password = Str::random(16); |
1485 | $encrypted_password = bcrypt($password); |
1486 | $password_expiry = Carbon::now()->addDays(7); |
1487 | |
1488 | $invitation->password = $encrypted_password; |
1489 | $invitation->temp_password = $encrypted_password; |
1490 | $invitation->temp_password_expiry = $password_expiry->toDateTimeString(); |
1491 | $invitation->admin_email = $request->user()->email; |
1492 | $invitation->email = $email; |
1493 | $invitation->save(); |
1494 | |
1495 | $this->emailService->send( |
1496 | $email, |
1497 | new InvitationToJoinFlymsgEmail( |
1498 | email: $email, |
1499 | password: $password |
1500 | ), |
1501 | 'cac_invitation_to_join' |
1502 | ); |
1503 | } |
1504 | } |
1505 | |
1506 | return response()->json(data: [ |
1507 | 'success' => true, |
1508 | 'message' => "User profile updated successfully", |
1509 | ], status: 200); |
1510 | } |
1511 | |
1512 | public function move_group_bulk(Request $request) |
1513 | { |
1514 | $validated_data = $request->validate([ |
1515 | 'users' => 'required', |
1516 | 'to_group_id' => 'required', |
1517 | ]); |
1518 | |
1519 | $group = $this->adminGroupsService->getGroup($validated_data['to_group_id']); |
1520 | |
1521 | $users = $this->adminUsersService->moveUsersToGroup($validated_data['users'], $group); |
1522 | |
1523 | return response()->json(data: [ |
1524 | 'success' => true, |
1525 | 'message' => "User profile updated successfully", |
1526 | 'users' => AdminCenterUserResource::collection($users), |
1527 | ], status: 200); |
1528 | } |
1529 | |
1530 | /** |
1531 | * Checks if a group/subgroup is unique in a company |
1532 | * |
1533 | * @param Request $request {name:string} |
1534 | * |
1535 | * @return JsonResponse |
1536 | */ |
1537 | public function group_exists(Request $request) |
1538 | { |
1539 | $validated_data = $request->validate([ |
1540 | 'name' => 'required|string' |
1541 | ]); |
1542 | $name = $validated_data["name"]; |
1543 | $company_id = $request->company_id; |
1544 | |
1545 | $exists = CompanyGroup::where([ |
1546 | ["name", $name], |
1547 | ["company_id", $company_id] |
1548 | ])->exists(); |
1549 | |
1550 | return response()->json([ |
1551 | 'success' => true, |
1552 | 'exists' => $exists ? true : false, |
1553 | 'message' => $exists ? "The name: $name has already been taken." : "The name $name is available.", |
1554 | ], 200); |
1555 | } |
1556 | |
1557 | /** |
1558 | * Creates a new group. You can assign members of the |
1559 | * group too if you like. |
1560 | * |
1561 | * @param Request $request {name:string, users:[array if user IDs]} |
1562 | * |
1563 | * @return JsonResponse |
1564 | */ |
1565 | public function create_group(Request $request) |
1566 | { |
1567 | $company_id = $request->company_id; |
1568 | $validated_data = $request->validate([ |
1569 | 'name' => 'required', |
1570 | 'users' => 'sometimes', |
1571 | ]); |
1572 | |
1573 | $group = $this->adminGroupsService->createGroup($validated_data["name"], $company_id); |
1574 | |
1575 | $this->adminUsersService->moveUsersToGroup($validated_data['users'] ?? [], $group); |
1576 | |
1577 | return response()->json(data: [ |
1578 | 'success' => true, |
1579 | 'message' => "New group $group->name added", |
1580 | 'group' => new AdminCenterCompanyGroupResource($group->load('users')), |
1581 | ], status: 200); |
1582 | } |
1583 | |
1584 | public function update_group(Request $request, $slug, CompanyGroup $group) |
1585 | { |
1586 | $validated_data = $request->validate([ |
1587 | 'name' => 'required', |
1588 | ]); |
1589 | |
1590 | $result = $this->adminGroupsService->updateGroup($group, $validated_data["name"], $request->company_id); |
1591 | |
1592 | return response()->json(data: $result, status: 200); |
1593 | } |
1594 | |
1595 | public function delete_group(Request $request, $slug, CompanyGroup $group) |
1596 | { |
1597 | // get group instancy id |
1598 | $groupInstancyId = isset($group->instancy_id) ? $group->instancy_id : ''; |
1599 | |
1600 | if ($group->users()->count() > 0) { |
1601 | $group->users()->update(['company_group_id' => null]); |
1602 | $user_ids = $group->users()->pluck('_id')->toArray(); |
1603 | $this->adminUsersService->moveUsersToGroup($user_ids, null); |
1604 | } |
1605 | |
1606 | // Of a top parent group is being deleted, delete subgroups too? |
1607 | if ($group->subgroups()->count() > 0) { |
1608 | foreach ($group->subgroups as $subgroup) { |
1609 | $subgroup->users()->update(['company_group_id' => null]); |
1610 | |
1611 | $user_ids = $subgroup->users()->pluck('_id')->toArray(); |
1612 | $this->adminUsersService->moveUsersToGroup($user_ids, null); |
1613 | |
1614 | $subgroup->delete(); |
1615 | } |
1616 | } |
1617 | $group->delete(); |
1618 | |
1619 | // after above delete the group on instancy |
1620 | if ($groupInstancyId) { |
1621 | $job = DeleteInstancyGroup::dispatch($groupInstancyId); |
1622 | if ($job) { |
1623 | $job->delay(now()->addMinutes(5)); |
1624 | } |
1625 | } |
1626 | |
1627 | return response()->json(data: [ |
1628 | 'success' => true, |
1629 | 'message' => "Group deleted successfully", |
1630 | ], status: 200); |
1631 | } |
1632 | |
1633 | public function add_users_to_group(Request $request, $slug, CompanyGroup $group) |
1634 | { |
1635 | $validated_data = $request->validate([ |
1636 | 'users' => 'required', |
1637 | ]); |
1638 | |
1639 | $this->adminUsersService->moveUsersToGroup($validated_data['users'], $group); |
1640 | |
1641 | return response()->json(data: [ |
1642 | 'success' => true, |
1643 | 'message' => "Updated group users successfully", |
1644 | ], status: 200); |
1645 | } |
1646 | |
1647 | public function add_subgroup_to_group(Request $request, $slug, CompanyGroup $group) |
1648 | { |
1649 | $company_id = $request->company_id; |
1650 | |
1651 | $validated_data = $request->validate([ |
1652 | 'name' => 'required', |
1653 | 'users' => 'sometimes', |
1654 | ]); |
1655 | |
1656 | $subgroup = $this->adminGroupsService->createGroup($validated_data["name"], $company_id, $group); |
1657 | |
1658 | $this->adminUsersService->moveUsersToGroup($validated_data['users'] ?? [], $subgroup); |
1659 | |
1660 | return response()->json(data: [ |
1661 | 'success' => true, |
1662 | 'message' => "New subgroup added", |
1663 | 'group' => $subgroup->load('users'), |
1664 | ], status: 200); |
1665 | } |
1666 | |
1667 | public function export_csv(Request $request) |
1668 | { |
1669 | $users = $request->users ? explode(',', $request->users) : []; |
1670 | $only_deactivated_users = $request->deactivated == "true" ? true : false; |
1671 | return (new UsersExport($only_deactivated_users, $users))->download('users.csv'); |
1672 | } |
1673 | |
1674 | public function import_csv(Request $request) |
1675 | { |
1676 | $request->validate([ |
1677 | 'csv_file' => 'required', |
1678 | ]); |
1679 | |
1680 | $file = $request->file('csv_file'); |
1681 | |
1682 | (new UsersImport)->import($file); |
1683 | |
1684 | return response()->json([ |
1685 | 'success' => true, |
1686 | 'message' => 'CSV imported successfully and file deleted.', |
1687 | ], 200); |
1688 | } |
1689 | |
1690 | public function reporting_licenses(Request $request) |
1691 | { |
1692 | $filters = new FindUsersOverviewFilter( |
1693 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
1694 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
1695 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
1696 | return $value !== ""; |
1697 | }), |
1698 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
1699 | return $value !== ""; |
1700 | }), |
1701 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
1702 | return $value !== ""; |
1703 | }), |
1704 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
1705 | currentRole: $request->current_role, |
1706 | companyId: $request->company_id, |
1707 | adminGroupIds: $request->admin_group_ids, |
1708 | monthPeriod: 12, |
1709 | ); |
1710 | |
1711 | $data = $this->accountCenterReportingService->findLicenseOverview($filters); |
1712 | |
1713 | return response()->json(data: [ |
1714 | 'success' => true, |
1715 | 'licenses' => $data, |
1716 | ], status: 200); |
1717 | } |
1718 | |
1719 | public function reporting_roi_spotlight(Request $request, RoiSpotlightAction $roiSpotlightAction) |
1720 | { |
1721 | $filters = new ReportingRequestDTO( |
1722 | fromDate: $request->fromDate, |
1723 | toDate: $request->toDate, |
1724 | companyId: $request->company_id, |
1725 | adminGroupIds: $request->admin_group_ids, |
1726 | userIds: $request->user_ids ? $request->user_ids : null, |
1727 | groupIds: $request->group_ids ? $request->group_ids : null, |
1728 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1729 | role: $request->current_role, |
1730 | ); |
1731 | |
1732 | $data = $roiSpotlightAction->execute($filters); |
1733 | |
1734 | return response()->json(data: [ |
1735 | 'success' => true, |
1736 | 'data' => $data, |
1737 | ], status: 200); |
1738 | } |
1739 | |
1740 | public function reporting_productivity_spotlight(Request $request, ProductivitySpotlightAction $productivitySpotlightAction) |
1741 | { |
1742 | $filters = new ReportingRequestDTO( |
1743 | fromDate: $request->fromDate, |
1744 | toDate: $request->toDate, |
1745 | companyId: $request->company_id, |
1746 | adminGroupIds: $request->admin_group_ids, |
1747 | userIds: $request->user_ids ? $request->user_ids : null, |
1748 | groupIds: $request->group_ids ? $request->group_ids : null, |
1749 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1750 | role: $request->current_role, |
1751 | ); |
1752 | |
1753 | $data = $productivitySpotlightAction->execute($filters); |
1754 | |
1755 | return response()->json(data: [ |
1756 | 'success' => true, |
1757 | 'data' => $data, |
1758 | ], status: 200); |
1759 | } |
1760 | |
1761 | public function reporting_total_characters_typed_spotlight(Request $request, TotalCharactersTypedSpotlightAction $totalCharactersTypedSpotlightAction) |
1762 | { |
1763 | $filters = new ReportingRequestDTO( |
1764 | fromDate: $request->fromDate, |
1765 | toDate: $request->toDate, |
1766 | companyId: $request->company_id, |
1767 | adminGroupIds: $request->admin_group_ids, |
1768 | userIds: $request->user_ids ? $request->user_ids : null, |
1769 | groupIds: $request->group_ids ? $request->group_ids : null, |
1770 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1771 | role: $request->current_role, |
1772 | ); |
1773 | |
1774 | $data = $totalCharactersTypedSpotlightAction->execute($filters); |
1775 | |
1776 | return response()->json(data: [ |
1777 | 'success' => true, |
1778 | 'data' => $data, |
1779 | ], status: 200); |
1780 | } |
1781 | |
1782 | public function reporting_total_fly_grammar_spotlight(Request $request, TotalFlyGrammarSpotlightAction $totalFlyGrammarSpotlightAction) |
1783 | { |
1784 | $filters = new ReportingRequestDTO( |
1785 | fromDate: $request->fromDate, |
1786 | toDate: $request->toDate, |
1787 | companyId: $request->company_id, |
1788 | adminGroupIds: $request->admin_group_ids, |
1789 | userIds: $request->user_ids ? $request->user_ids : null, |
1790 | groupIds: $request->group_ids ? $request->group_ids : null, |
1791 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1792 | role: $request->current_role, |
1793 | ); |
1794 | |
1795 | $data = $totalFlyGrammarSpotlightAction->execute($filters); |
1796 | |
1797 | return response()->json(data: [ |
1798 | 'success' => true, |
1799 | 'data' => $data, |
1800 | ], status: 200); |
1801 | } |
1802 | |
1803 | public function reporting_total_fly_cuts_spotlight(Request $request, TotalFlyCutsSpotlightAction $totalFlyCutsSpotlightAction) |
1804 | { |
1805 | $filters = new ReportingRequestDTO( |
1806 | fromDate: $request->fromDate, |
1807 | toDate: $request->toDate, |
1808 | companyId: $request->company_id, |
1809 | adminGroupIds: $request->admin_group_ids, |
1810 | userIds: $request->user_ids ? $request->user_ids : null, |
1811 | groupIds: $request->group_ids ? $request->group_ids : null, |
1812 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1813 | role: $request->current_role, |
1814 | ); |
1815 | |
1816 | $data = $totalFlyCutsSpotlightAction->execute($filters); |
1817 | |
1818 | return response()->json(data: [ |
1819 | 'success' => true, |
1820 | 'data' => $data, |
1821 | ], status: 200); |
1822 | } |
1823 | |
1824 | public function reporting_flymsg_coach_level(Request $request, FmsCoachLevelSpotlightAction $fmsCoachLevelSpotlightAction) |
1825 | { |
1826 | $filters = new ReportingRequestDTO( |
1827 | fromDate: $request->fromDate, |
1828 | toDate: $request->toDate, |
1829 | companyId: $request->company_id, |
1830 | adminGroupIds: $request->admin_group_ids, |
1831 | userIds: $request->user_ids ? $request->user_ids : null, |
1832 | groupIds: $request->group_ids ? $request->group_ids : null, |
1833 | subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null, |
1834 | role: $request->current_role, |
1835 | ); |
1836 | |
1837 | $data = $fmsCoachLevelSpotlightAction->execute($filters); |
1838 | |
1839 | return response()->json([ |
1840 | 'success' => true, |
1841 | 'data' => $data, |
1842 | ], 200); |
1843 | } |
1844 | |
1845 | public function reporting_flycuts_created(Request $request) |
1846 | { |
1847 | $filters = new FindUsersOverviewFilter( |
1848 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
1849 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
1850 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
1851 | return $value !== ""; |
1852 | }), |
1853 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
1854 | return $value !== ""; |
1855 | }), |
1856 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
1857 | return $value !== ""; |
1858 | }), |
1859 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
1860 | currentRole: $request->current_role, |
1861 | companyId: $request->company_id, |
1862 | adminGroupIds: $request->admin_group_ids, |
1863 | monthPeriod: 12, |
1864 | userDefined: true, |
1865 | ); |
1866 | |
1867 | $shortcuts = $this->accountCenterReportingService->findShortcut($filters); |
1868 | |
1869 | $data = [ |
1870 | "chart" => $shortcuts['chart'], |
1871 | "total_flycuts_created" => number_format($shortcuts['total_shortcut_created'], 0, ".", ","), |
1872 | "average_flycuts_per_active_user" => number_format(round($shortcuts['average_shortcut_per_active_user'], 2), 2, ".", ","), |
1873 | ]; |
1874 | |
1875 | return response()->json(data: [ |
1876 | 'success' => true, |
1877 | 'data' => $data, |
1878 | ], status: 200); |
1879 | } |
1880 | |
1881 | public function reporting_flycuts_created_top_users(Request $request) |
1882 | { |
1883 | return response()->json(data: [ |
1884 | 'success' => true, |
1885 | 'users' => $this->getTop5($request, 'flycuts_created'), |
1886 | ]); |
1887 | } |
1888 | |
1889 | public function reporting_flyplates_added(Request $request) |
1890 | { |
1891 | |
1892 | $filters = new FindUsersOverviewFilter( |
1893 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
1894 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
1895 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
1896 | return $value !== ""; |
1897 | }), |
1898 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
1899 | return $value !== ""; |
1900 | }), |
1901 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
1902 | return $value !== ""; |
1903 | }), |
1904 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
1905 | currentRole: $request->current_role, |
1906 | companyId: $request->company_id, |
1907 | adminGroupIds: $request->admin_group_ids, |
1908 | monthPeriod: 12, |
1909 | userDefined: false, |
1910 | ); |
1911 | |
1912 | $shortcuts = $this->accountCenterReportingService->findShortcut($filters); |
1913 | |
1914 | $data = [ |
1915 | "chart" => $shortcuts['chart'], |
1916 | "total_flyplate_created" => number_format($shortcuts['total_shortcut_created'], 0, ".", ","), |
1917 | "average_flyplate_per_active_user" => number_format(round($shortcuts['average_shortcut_per_active_user'], 2), 2, ".", ","), |
1918 | ]; |
1919 | |
1920 | return response()->json(data: [ |
1921 | 'success' => true, |
1922 | 'data' => $data, |
1923 | ], status: 200); |
1924 | } |
1925 | |
1926 | public function reporting_flyplates_added_top_users(Request $request) |
1927 | { |
1928 | return response()->json(data: [ |
1929 | 'success' => true, |
1930 | 'users' => $this->getTop5($request, 'flyplates_added'), |
1931 | ]); |
1932 | } |
1933 | |
1934 | public function reporting_sentence_rewrite_ai(Request $request) |
1935 | { |
1936 | |
1937 | $filters = new FindUsersOverviewFilter( |
1938 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
1939 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
1940 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
1941 | return $value !== ""; |
1942 | }), |
1943 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
1944 | return $value !== ""; |
1945 | }), |
1946 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
1947 | return $value !== ""; |
1948 | }), |
1949 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
1950 | currentRole: $request->current_role, |
1951 | companyId: $request->company_id, |
1952 | adminGroupIds: $request->admin_group_ids, |
1953 | monthPeriod: 12, |
1954 | userDefined: false, |
1955 | feature: "sentence_rewrite", |
1956 | ); |
1957 | |
1958 | $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters); |
1959 | |
1960 | $data = [ |
1961 | "chart" => $flyMsgAI['chart'], |
1962 | "total_sentence_rewrite_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","), |
1963 | "average_sentence_rewrite_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","), |
1964 | ]; |
1965 | |
1966 | return response()->json(data: [ |
1967 | 'success' => true, |
1968 | 'data' => $data, |
1969 | ], status: 200); |
1970 | } |
1971 | |
1972 | public function reporting_sentence_rewrite_ai_used_top_users(Request $request) |
1973 | { |
1974 | return response()->json(data: [ |
1975 | 'success' => true, |
1976 | 'users' => $this->getTop5($request, 'sentence_rewrite_count'), |
1977 | ]); |
1978 | } |
1979 | |
1980 | public function reporting_paragraph_rewrite_ai(Request $request) |
1981 | { |
1982 | |
1983 | $filters = new FindUsersOverviewFilter( |
1984 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
1985 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
1986 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
1987 | return $value !== ""; |
1988 | }), |
1989 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
1990 | return $value !== ""; |
1991 | }), |
1992 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
1993 | return $value !== ""; |
1994 | }), |
1995 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
1996 | currentRole: $request->current_role, |
1997 | companyId: $request->company_id, |
1998 | adminGroupIds: $request->admin_group_ids, |
1999 | monthPeriod: 12, |
2000 | userDefined: false, |
2001 | feature: "paragraph_rewrite", |
2002 | ); |
2003 | |
2004 | $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters); |
2005 | |
2006 | $data = [ |
2007 | "chart" => $flyMsgAI['chart'], |
2008 | "total_paragraph_rewrite_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","), |
2009 | "average_paragraph_rewrite_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","), |
2010 | ]; |
2011 | |
2012 | return response()->json(data: [ |
2013 | 'success' => true, |
2014 | 'data' => $data, |
2015 | ], status: 200); |
2016 | } |
2017 | |
2018 | public function reporting_paragraph_rewrite_ai_used_top_users(Request $request) |
2019 | { |
2020 | return response()->json(data: [ |
2021 | 'success' => true, |
2022 | 'users' => $this->getTop5($request, 'paragraph_rewrite_count'), |
2023 | ]); |
2024 | } |
2025 | |
2026 | public function reporting_flyengage_ai(Request $request) |
2027 | { |
2028 | |
2029 | $filters = new FindUsersOverviewFilter( |
2030 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
2031 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
2032 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
2033 | return $value !== ""; |
2034 | }), |
2035 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
2036 | return $value !== ""; |
2037 | }), |
2038 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
2039 | return $value !== ""; |
2040 | }), |
2041 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
2042 | currentRole: $request->current_role, |
2043 | companyId: $request->company_id, |
2044 | adminGroupIds: $request->admin_group_ids, |
2045 | monthPeriod: 12, |
2046 | userDefined: false, |
2047 | feature: "flyengage", |
2048 | ); |
2049 | |
2050 | $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters); |
2051 | |
2052 | $data = [ |
2053 | "chart" => $flyMsgAI['chart'], |
2054 | "total_flyengage_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","), |
2055 | "average_flyengage_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","), |
2056 | ]; |
2057 | |
2058 | return response()->json(data: [ |
2059 | 'success' => true, |
2060 | 'data' => $data, |
2061 | ], status: 200); |
2062 | } |
2063 | |
2064 | public function reporting_flyengage_ai_used_top_users(Request $request) |
2065 | { |
2066 | return response()->json(data: [ |
2067 | 'success' => true, |
2068 | 'users' => $this->getTop5($request, 'flyengage_count'), |
2069 | ]); |
2070 | } |
2071 | |
2072 | public function reporting_flypost_ai(Request $request) |
2073 | { |
2074 | $filters = new FindUsersOverviewFilter( |
2075 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
2076 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
2077 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
2078 | return $value !== ""; |
2079 | }), |
2080 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
2081 | return $value !== ""; |
2082 | }), |
2083 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
2084 | return $value !== ""; |
2085 | }), |
2086 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
2087 | currentRole: $request->current_role, |
2088 | companyId: $request->company_id, |
2089 | adminGroupIds: $request->admin_group_ids, |
2090 | monthPeriod: 12, |
2091 | userDefined: false, |
2092 | feature: "flypost", |
2093 | ); |
2094 | |
2095 | $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters); |
2096 | |
2097 | $data = [ |
2098 | "chart" => $flyMsgAI['chart'], |
2099 | "total_flypost_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","), |
2100 | "average_flypost_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","), |
2101 | ]; |
2102 | |
2103 | return response()->json(data: [ |
2104 | 'success' => true, |
2105 | 'data' => $data, |
2106 | ], status: 200); |
2107 | } |
2108 | |
2109 | public function reporting_flypost_ai_used_top_users(Request $request) |
2110 | { |
2111 | return response()->json(data: [ |
2112 | 'success' => true, |
2113 | 'users' => $this->getTop5($request, 'flypost_count'), |
2114 | ]); |
2115 | } |
2116 | |
2117 | private function getTop5(Request $request, string $property) |
2118 | { |
2119 | $filter = new ReportingRequestDTO( |
2120 | fromDate: !empty($request->fromDate) ? Carbon::parse($request->fromDate)->startOfDay() : null, |
2121 | toDate: !empty($request->toDate) ? Carbon::parse($request->toDate)->endOfDay() : null, |
2122 | companyId: $request->company_id, |
2123 | adminGroupIds: $request->admin_group_ids, |
2124 | userIds: $request->user_ids, |
2125 | groupIds: $request->group_ids, |
2126 | subgroupIds: $request->subgroup_ids, |
2127 | role: $request->current_role, |
2128 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
2129 | ); |
2130 | |
2131 | $top5 = $this->accountCenterReportingService->getTop5Users($filter, $property); |
2132 | |
2133 | // Get the top 5 users |
2134 | $top_5_users = $top5->map(function ($top) use ($property) { |
2135 | $user = User::firstWhere('_id', $top['user_id']); |
2136 | |
2137 | if ($user) { |
2138 | $full_name = $user->first_name . ' ' . $user->last_name; |
2139 | |
2140 | return ['name' => $full_name, 'count' => number_format($top[$property], 0, ".", ","), 'image' => $user->avatar]; |
2141 | } |
2142 | }); |
2143 | |
2144 | return $top_5_users; |
2145 | } |
2146 | |
2147 | public function reporting_characters_typed_saving_top_users(Request $request) |
2148 | { |
2149 | return response()->json(data: [ |
2150 | 'success' => true, |
2151 | 'users' => $this->getTop5($request, 'characters_typed'), |
2152 | ]); |
2153 | } |
2154 | |
2155 | public function reporting_fly_grammar_top_users(Request $request) |
2156 | { |
2157 | return response()->json(data: [ |
2158 | 'success' => true, |
2159 | 'users' => $this->getTop5($request, 'fly_grammar_actions'), |
2160 | ]); |
2161 | } |
2162 | |
2163 | public function reporting_fly_cuts_top_users(Request $request) |
2164 | { |
2165 | return response()->json(data: [ |
2166 | 'success' => true, |
2167 | 'users' => $this->getTop5($request, 'flycut_count'), |
2168 | ]); |
2169 | } |
2170 | |
2171 | public function reporting_fly_grammar_accepted_top_users(Request $request) |
2172 | { |
2173 | return response()->json(data: [ |
2174 | 'success' => true, |
2175 | 'users' => $this->getTop5($request, 'fly_grammar_accepted'), |
2176 | ]); |
2177 | } |
2178 | |
2179 | public function reporting_fly_grammar_autocorrect_top_users(Request $request) |
2180 | { |
2181 | return response()->json(data: [ |
2182 | 'success' => true, |
2183 | 'users' => $this->getTop5($request, 'fly_grammar_autocorrect'), |
2184 | ]); |
2185 | } |
2186 | |
2187 | public function reporting_fly_grammar_autocomplete_top_users(Request $request) |
2188 | { |
2189 | return response()->json(data: [ |
2190 | 'success' => true, |
2191 | 'users' => $this->getTop5($request, 'fly_grammar_autocomplete'), |
2192 | ]); |
2193 | } |
2194 | |
2195 | public function reporting_time_saving_top_users(Request $request) |
2196 | { |
2197 | return response()->json(data: [ |
2198 | 'success' => true, |
2199 | 'users' => $this->getTop5($request, 'time_saved'), |
2200 | ]); |
2201 | } |
2202 | |
2203 | public function reporting_cost_saving_top_users(Request $request) |
2204 | { |
2205 | return response()->json(data: [ |
2206 | 'success' => true, |
2207 | 'users' => $this->getTop5($request, 'cost_savings'), |
2208 | ]); |
2209 | } |
2210 | |
2211 | public function reporting_active_users(Request $request) |
2212 | { |
2213 | $filters = new FindUsersOverviewFilter( |
2214 | fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null, |
2215 | toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null, |
2216 | userIds: array_filter(explode(",", $request->user_ids), function ($value) { |
2217 | return $value !== ""; |
2218 | }), |
2219 | groupIds: array_filter(explode(",", $request->group_ids), function ($value) { |
2220 | return $value !== ""; |
2221 | }), |
2222 | subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) { |
2223 | return $value !== ""; |
2224 | }), |
2225 | companyIds: $request->company_ids ? explode(",", $request->company_ids) : null, |
2226 | currentRole: $request->current_role, |
2227 | companyId: $request->company_id, |
2228 | adminGroupIds: $request->admin_group_ids, |
2229 | monthPeriod: 12, |
2230 | ); |
2231 | |
2232 | $data = $this->accountCenterReportingService->findUsersOverview($filters); |
2233 | |
2234 | return response()->json(data: [ |
2235 | 'success' => true, |
2236 | 'data' => $data, |
2237 | ], status: 200); |
2238 | } |
2239 | |
2240 | public function reporting_extension_usage(Request $request) |
2241 | { |
2242 | $admin = auth()->user(); |
2243 | $roles = $admin->role; |
2244 | $role = role($roles); |
2245 | $company_id = $request->company_id; |
2246 | $admin_group_ids = $request->admin_group_ids; |
2247 | |
2248 | $users = User::select([ |
2249 | "id", |
2250 | "first_name", |
2251 | "last_name", |
2252 | "company_group_id", |
2253 | "company_id", |
2254 | "deleted_at", |
2255 | "avatar" |
2256 | ]); |
2257 | |
2258 | $start_date = $request->fromDate; |
2259 | $end_date = $request->toDate; |
2260 | |
2261 | if ($start_date && $end_date) { |
2262 | $start_date = Carbon::parse($start_date)->startOfDay(); |
2263 | $end_date = Carbon::parse($end_date)->endOfDay(); |
2264 | } |
2265 | |
2266 | $user_ids = explode(",", $request->user_ids); |
2267 | $user_ids = array_filter($user_ids, function ($value) { |
2268 | return $value !== ""; |
2269 | }); |
2270 | if (count($user_ids) > 0) { |
2271 | $users = $users->whereIn("_id", $user_ids); |
2272 | } |
2273 | |
2274 | $hasNotAssignedGroup = in_array("-1", explode(",", $request->group_ids)); |
2275 | |
2276 | if ($hasNotAssignedGroup) { |
2277 | $users = $users->whereNull("company_group_id"); |
2278 | } |
2279 | |
2280 | $group_ids = explode(",", $request->group_ids); |
2281 | $group_ids = array_filter($group_ids, function ($value) { |
2282 | return $value !== "" && $value !== "-1"; |
2283 | }); |
2284 | |
2285 | if (count($group_ids) > 0) { |
2286 | $users = $users->whereIn("company_group_id", $group_ids); |
2287 | } |
2288 | |
2289 | $subgroup_ids = explode(",", $request->subgroup_ids); |
2290 | $subgroup_ids = array_filter($subgroup_ids, function ($value) { |
2291 | return $value !== ""; |
2292 | }); |
2293 | if (count($subgroup_ids) > 0) { |
2294 | $users = $users->whereIn("company_group_id", $subgroup_ids); |
2295 | } |
2296 | |
2297 | $users = $this->filterUsersByGroupIds($users, $role, $group_ids, $company_id, $admin_group_ids); |
2298 | |
2299 | $users = $users->whereStatus("Active"); |
2300 | |
2301 | $users = $users->get(); |
2302 | $ids = $users->pluck("id")->toArray(); |
2303 | |
2304 | $extensions_data = HubspotProperties::whereIn("flymsg_id", $ids); |
2305 | |
2306 | if ($start_date && $end_date) { |
2307 | $extensions_data = $extensions_data->whereBetween("created_at", [ |
2308 | new UTCDateTime($start_date->getTimestamp() * 1000), |
2309 | new UTCDateTime($end_date->getTimestamp() * 1000), |
2310 | ]); |
2311 | } |
2312 | |
2313 | $extensions_data = $extensions_data->orderBy('created_at', 'desc') |
2314 | ->get() |
2315 | ->unique('flymsg_id'); |
2316 | |
2317 | $firstDate = $start_date; |
2318 | $lastDate = $end_date; |
2319 | |
2320 | if (!$firstDate) { |
2321 | $firstDate = $extensions_data->min("created_at"); |
2322 | } |
2323 | |
2324 | if (!$lastDate) { |
2325 | $lastDate = $extensions_data->max("created_at"); |
2326 | } |
2327 | |
2328 | $months = $lastDate->diffInMonths($firstDate); |
2329 | $chart = $this->_make_line_chart_data_extension($extensions_data, $months, $firstDate); |
2330 | |
2331 | $data = [ |
2332 | "chart" => $chart, |
2333 | ]; |
2334 | |
2335 | return response()->json([ |
2336 | 'success' => true, |
2337 | 'data' => $data, |
2338 | ], 200); |
2339 | } |
2340 | |
2341 | public function reporting_user_details(Request $request) |
2342 | { |
2343 | $admin = auth()->user(); |
2344 | $roles = $admin->role; |
2345 | $role = role($roles); |
2346 | $company_id = $request->company_id; |
2347 | $admin_group_ids = $request->admin_group_ids; |
2348 | |
2349 | $start_date = $request->fromDate; |
2350 | $end_date = $request->toDate; |
2351 | |
2352 | $users = User::withTrashed() |
2353 | ->select([ |
2354 | "id", |
2355 | "first_name", |
2356 | "last_name", |
2357 | "company_group_id", |
2358 | "company_id", |
2359 | "deleted_at", |
2360 | ]); |
2361 | |
2362 | if ($start_date && $end_date) { |
2363 | $start_date = Carbon::parse($start_date); |
2364 | $end_date = Carbon::parse($end_date); |
2365 | |
2366 | $start_date = Carbon::now()->subMonths(12)->startOfMonth(); |
2367 | $end_date = Carbon::now()->endOfMonth(); |
2368 | |
2369 | $users = $users->whereBetween("created_at", [ |
2370 | new UTCDateTime($start_date->getTimestamp() * 1000), |
2371 | new UTCDateTime($end_date->getTimestamp() * 1000), |
2372 | ]); |
2373 | } |
2374 | |
2375 | $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids); |
2376 | |
2377 | $users = $users->get(); |
2378 | $ids = $users->pluck("id")->toArray(); |
2379 | |
2380 | // TODO MA filter this data by the dates too? |
2381 | // - Total # of Characters Typed by FlyMSG by User |
2382 | // - Total Time Saved by FlyMSG by User |
2383 | // - Total Cost Savings by FlyMSG by User |
2384 | |
2385 | $properties = HubspotProperties::whereIn("flymsg_id", $ids); |
2386 | |
2387 | if ($start_date && $end_date) { |
2388 | $properties = $properties->whereBetween("created_at", [ |
2389 | new UTCDateTime($start_date->getTimestamp() * 1000), |
2390 | new UTCDateTime($end_date->getTimestamp() * 1000), |
2391 | ]); |
2392 | } |
2393 | |
2394 | $properties = $properties->get(); |
2395 | |
2396 | $properties = UserDetailsReportResource::collection($properties); |
2397 | |
2398 | return response()->json([ |
2399 | 'success' => true, |
2400 | 'users' => $properties, |
2401 | ], 200); |
2402 | } |
2403 | |
2404 | public function reporting_get_columns(Request $request) |
2405 | { |
2406 | $admin = auth()->user(); |
2407 | $company_id = $request->company_id; |
2408 | |
2409 | $default_columns = collect(); |
2410 | |
2411 | $default_columns = $default_columns->push([ |
2412 | "key" => "first_name", |
2413 | "value" => "First Name", |
2414 | "checked" => true, |
2415 | ]); |
2416 | $default_columns = $default_columns->push([ |
2417 | "key" => "last_name", |
2418 | "value" => "Last Name", |
2419 | "checked" => true, |
2420 | ]); |
2421 | $default_columns = $default_columns->push([ |
2422 | "key" => "email", |
2423 | "value" => "Email", |
2424 | "checked" => true, |
2425 | ]); |
2426 | |
2427 | $columns = UserDetailsColumnSetting::where("user_id", $admin->id) |
2428 | ->where("company_id", $company_id) |
2429 | ->get(); |
2430 | |
2431 | if (count($columns) == 0) { |
2432 | $columns = collect(Constants::ADMIN_CENTER_USERS_TABLE_REPORTING_TABLE_HEADERS); |
2433 | } else { |
2434 | $columns = UserDetailsReportingResource::collection($columns); |
2435 | $columns = array_merge($default_columns->toArray(), $columns->toArray($request)); |
2436 | } |
2437 | |
2438 | return response()->json([ |
2439 | 'success' => true, |
2440 | 'columns' => $columns, |
2441 | ], 200); |
2442 | } |
2443 | |
2444 | public function reporting_save_columns(Request $request) |
2445 | { |
2446 | $validated_data = $request->validate([ |
2447 | "columns" => "required", |
2448 | ]); |
2449 | |
2450 | $admin = auth()->user(); |
2451 | $roles = $admin->role; |
2452 | $role = role($roles); |
2453 | $company_id = $request->company_id; |
2454 | $admin_group_ids = $request->admin_group_ids; |
2455 | |
2456 | $columns = $validated_data["columns"]; |
2457 | |
2458 | foreach ($columns as $column) { |
2459 | $users_column = UserDetailsColumnSetting::where("user_id", $admin->id) |
2460 | ->where("key", $column["key"]) |
2461 | ->first(); |
2462 | |
2463 | if ($users_column) { |
2464 | if ($users_column->column == "first_name" || $users_column->column == "last_name" || $users_column->column == "email") { |
2465 | continue; |
2466 | } |
2467 | } |
2468 | |
2469 | $data = [ |
2470 | "company_id" => $company_id, |
2471 | "user_id" => $admin->id, |
2472 | "key" => $column["key"], |
2473 | "value" => $column["value"], |
2474 | "checked" => $column["checked"], |
2475 | ]; |
2476 | |
2477 | if ($users_column) { |
2478 | $users_column->update($data); |
2479 | } else { |
2480 | UserDetailsColumnSetting::create($data); |
2481 | } |
2482 | } |
2483 | |
2484 | $users = User::select([ |
2485 | "id", |
2486 | "first_name", |
2487 | "last_name", |
2488 | "company_group_id", |
2489 | "company_id", |
2490 | "deleted_at", |
2491 | "avatar" |
2492 | ]); |
2493 | |
2494 | $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids); |
2495 | |
2496 | $ids = $users->pluck("id")->toArray(); |
2497 | |
2498 | $columns = UserDetailsColumnSetting::whereIn("user_id", $ids) |
2499 | ->where("company_id", $company_id) |
2500 | ->get(); |
2501 | |
2502 | return response()->json([ |
2503 | 'success' => true, |
2504 | 'column' => $columns, |
2505 | ], 200); |
2506 | } |
2507 | |
2508 | public function export_user_details_csv(Request $request) |
2509 | { |
2510 | $validated_data = $request->validate([ |
2511 | "columns" => "required", |
2512 | ]); |
2513 | |
2514 | $admin = auth()->user(); |
2515 | $company_id = $request->company_id; |
2516 | |
2517 | $columns = UserDetailsColumnSetting::whereIn("user_id", $admin->id) |
2518 | ->where("company_id", $company_id) |
2519 | ->get(); |
2520 | |
2521 | if (count($columns) == 0) { |
2522 | $columns = collect(Constants::ADMIN_CENTER_USERS_TABLE_REPORTING_TABLE_HEADERS); |
2523 | } |
2524 | |
2525 | return response()->json([ |
2526 | 'success' => true, |
2527 | 'columns' => $columns, |
2528 | ], 200); |
2529 | } |
2530 | |
2531 | public function reset_invited_user_password(Request $request) |
2532 | { |
2533 | $validated_data = $request->validate([ |
2534 | "password" => "required|confirmed|min:8|max:25", |
2535 | ]); |
2536 | |
2537 | $user = $request->user(); |
2538 | |
2539 | $user->password = Hash::make($validated_data['password']); |
2540 | |
2541 | if ($request->first_name) { |
2542 | $user->first_name = $request->first_name; |
2543 | } |
2544 | |
2545 | if ($request->last_name) { |
2546 | $user->last_name = $request->last_name; |
2547 | } |
2548 | |
2549 | // If user is invited then update status and delete invitation |
2550 | $userEmail = strtolower($user->email); |
2551 | $invitation = AdminUserInvitation::firstWhere('email', $userEmail); |
2552 | if ($invitation) { |
2553 | $user->status = "Active"; |
2554 | $user->activation_date = Carbon::now()->toDateTimeString(); |
2555 | $user->company_id = $invitation->company_id; |
2556 | $user->company_group_id = $invitation->company_group_id ?? $invitation->company_subgroup_id; |
2557 | $user->unset('invited_to_company'); |
2558 | $user->unset('invited_to_company_by_admin'); |
2559 | } |
2560 | |
2561 | $user->save(); |
2562 | User::where('_id', $user->id) |
2563 | ->update([ |
2564 | '$unset' => [ |
2565 | 'temp_password' => 1, |
2566 | 'temp_password_expiry' => 1 |
2567 | ] |
2568 | ]); |
2569 | if ($invitation) { |
2570 | $invitation->email = $userEmail; |
2571 | $invitation->delete(); |
2572 | } |
2573 | |
2574 | $data = [ |
2575 | "first_name" => $user->first_name, |
2576 | "last_name" => $user->last_name, |
2577 | "email" => $userEmail, |
2578 | "do_not_send_welcome_notification" => true, |
2579 | ]; |
2580 | |
2581 | Registered::dispatch($user, $data); |
2582 | |
2583 | return response()->json([ |
2584 | 'success' => true, |
2585 | 'message' => "Your password has been changed successfully.", |
2586 | ], 200); |
2587 | } |
2588 | |
2589 | public function export_csv_report(Request $request) |
2590 | { |
2591 | $filters = $request->filters; |
2592 | $users_ids = $request->users ? explode(',', $request->users) : []; |
2593 | return (new UsersReportExport($filters, $users_ids))->download('reporting-details-export.csv'); |
2594 | } |
2595 | |
2596 | public function export_csv_report_overview(Request $request) |
2597 | { |
2598 | $company_id = $request->company_id; |
2599 | return (new UsersReportOverviewExport($company_id))->download('reporting-overview-export.csv'); |
2600 | } |
2601 | |
2602 | public function export_csv_report_usage(Request $request) |
2603 | { |
2604 | // $admin = auth()->user(); |
2605 | // $from_date = $request->fromDate; |
2606 | // $to_date = $request->toDate; |
2607 | // $user_ids = $request->user_ids ? explode(',', $request->user_ids) : []; |
2608 | // $group_ids = $request->group_ids ? explode(',', $request->group_ids) : []; |
2609 | // $subgroup_ids = $request->subgroup_ids ? explode(',', $request->subgroup_ids) : []; |
2610 | |
2611 | // return (new AllUsersReportUsageExport($admin, $from_date, $to_date, $user_ids, $group_ids, $subgroup_ids))->download('reporting-usage-export.csv'); |
2612 | |
2613 | $company_id = $request->company_id; |
2614 | $from_date = $request->fromDate; |
2615 | $to_date = $request->toDate; |
2616 | $users_ids = $request->users_ids ? explode(',', $request->user_ids) : []; |
2617 | $group_ids = $request->group_ids ? explode(',', $request->group_ids) : []; |
2618 | $subgroup_ids = $request->subgroup_ids ? explode(',', $request->users) : []; |
2619 | return (new UsersReportUsageExport($company_id, $from_date, $to_date, $users_ids, $group_ids, $subgroup_ids))->download('reporting-usage-export.csv'); |
2620 | } |
2621 | |
2622 | public function remove_users_from_group(Request $request, $slug, CompanyGroup $company_group) |
2623 | { |
2624 | $user_ids = $request->users; |
2625 | if (!is_array($user_ids)) { |
2626 | throw new ExpectedException("You need to provide user ids in an array"); |
2627 | } |
2628 | |
2629 | $group = CompanyGroup::find($request->company_group_id); |
2630 | $this->adminUsersService->moveUsersToGroup($user_ids, $group); |
2631 | |
2632 | return response()->json([ |
2633 | 'success' => true, |
2634 | 'message' => "Users have been removed successfully from {$company_group->name}", |
2635 | 'users' => $user_ids |
2636 | ], 200); |
2637 | } |
2638 | |
2639 | public function user_info(Request $request) |
2640 | { |
2641 | $user = User::where('email', $request->email)->first(); |
2642 | $subscription = $user->subscription('main'); |
2643 | $plan = $subscription->plan; |
2644 | |
2645 | return response()->json([ |
2646 | 'flymsg_id' => $user->id, |
2647 | 'name' => $user->first_name . ' ' . $user->last_name, |
2648 | 'plan' => $plan->title, |
2649 | 'identifier' => $plan->identifier, |
2650 | 'email' => $request->email, |
2651 | 'status' => $subscription->stripe_status, |
2652 | 'ends_at' => $subscription->ends_at, |
2653 | 'is_trial' => $subscription->onTrial(), |
2654 | ], 200); |
2655 | } |
2656 | } |