PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
← All changes | app/Http/Controllers/AgentController.php +184 -165 1.5.2 → 2.4.5 View file →
@@ -2,237 +2,256 @@
2 2
3 3 namespace FluentSupport\App\Http\Controllers;
4 4
5 5 use FluentSupport\App\Models\Agent;
6 -use FluentSupport\App\Models\Attachment;
7 -use FluentSupport\App\Models\Person;
8 -use FluentSupport\App\Models\Product;
9 -use FluentSupport\App\Models\Conversation;
10 -use FluentSupport\App\Models\Ticket;
11 -use FluentSupport\App\Modules\Reporting\Reporting;
12 6 use FluentSupport\App\Modules\StatModule;
7 +use FluentSupport\App\Services\AvatarUploder;
13 8 use FluentSupport\App\Services\Helper;
14 -use FluentSupport\App\Services\TicketHelper;
15 -use FluentSupport\Framework\Request\Request;
9 +use FluentSupport\Framework\Http\Request\Request;
16 10 use FluentSupport\App\Modules\PermissionManager;
17 -use FluentSupport\Framework\Support\Arr;
11 +use FluentSupport\App\Http\Requests\AgentCreateRequest;
18 12
13 +/**
14 + * Support staff (agent) endpoints.
15 + */
19 16 class AgentController extends Controller
20 17 {
21 - public function index(Request $request)
18 + public function index(Request $request, Agent $agent)
22 19 {
23 - $agents = Agent::orderBy('id', 'DESC')
24 - //->whereNotNull('user_id')
25 - ->searchBy($request->get('search'))
26 - ->paginate();
27 -
28 - foreach ($agents as $agent) {
29 - $agent->permissions = PermissionManager::getUserPermissions($agent->user_id);
30 - if ($agent->user_id) {
31 - $agent->user_profile = admin_url('user-edit.php?user_id=' . $agent->user_id);
32 - }
33 - $agent->replies_count = Conversation::where('person_id', $agent->id)->count();
34 - $agent->interactions_count = Conversation::where('person_id', $agent->id)->groupBy('ticket_id')->get()->count();
35 - $agent->telegram_chat_id = $agent->getMeta('telegram_chat_id');
36 - $agent->slack_user_id = $agent->getMeta('slack_user_id');
37 - }
38 -
39 20 return [
40 - 'agents' => $agents,
41 - 'permissions' => PermissionManager::getReadablePermissionGroups()
21 + 'agents' => $agent->getAgents($request->getSafe('search', 'sanitize_text_field')),
22 + 'permissions' => PermissionManager::getReadablePermissionGroups(),
23 + 'businessBoxes' => PermissionManager::getMailboxesForRestriction(),
42 24 ];
43 25 }
44 26
45 - public function addAgent(Request $request)
27 + /**
28 + * @param AgentCreateRequest $request
29 + * @return \WP_REST_Response | array
30 + * @throws \FluentSupport\Framework\Validator\ValidationException
31 + */
32 + public function addAgent(AgentCreateRequest $request, Agent $agent)
46 33 {
47 - $data = $request->all();
48 - $this->validate($data, [
49 - 'email' => 'required|email'
50 - ]);
34 + $data = $this->sanitizeAgentPayload($request, true);
51 35
52 - $email = $data['email'];
53 -
54 - $user = get_user_by('email', $email);
55 -
56 - if (!$user || is_wp_error($user)) {
36 + try {
37 + return [
38 + 'message' => __('Support Staff has been added', 'fluent-support'),
39 + 'agent' => $agent->createAgent($data)
40 + ];
41 + } catch (\Exception $e) {
57 42 return $this->sendError([
58 - 'message' => __('Sorry, Connected user could not be found with the provided email address', 'fluent-support')
43 + 'message' => Helper::getSafeErrorMessage($e)
59 44 ]);
60 45 }
46 + }
61 47
62 - if (empty($data['first_name'])) {
63 - $data['first_name'] = $user->first_name;
64 - }
48 + /**
49 + * @param AgentCreateRequest $request
50 + * @param Agent $agent
51 + * @param int $agent_id
52 + * @return \WP_REST_Response | array
53 + * @throws \FluentSupport\Framework\Validator\ValidationException
54 + */
55 + public function updateAgent(AgentCreateRequest $request, Agent $agent, $agent_id)
56 + {
57 + $agent = $agent::findOrFail($agent_id);
58 + $data = $this->sanitizeAgentPayload($request);
65 59
66 - if (empty($data['last_name'])) {
67 - $data['last_name'] = $user->last_name;
60 + if (!$agent->user_id && ($user = get_user_by('email', $agent->email))) {
61 + $agent->user_id = $user->ID;
68 62 }
69 63
70 - // check if another agent has same email address
71 - $exist = Person::where('email', $email)->first();
72 - if ($exist) {
64 + try {
65 + return [
66 + 'message' => __('Support Staff has been updated', 'fluent-support'),
67 + 'agent' => $agent->updateAgent($data, $agent)
68 + ];
69 + } catch (\Exception $e) {
73 70 return $this->sendError([
74 - 'message' => __('Sorry, Another agent/person exist with the same email address. Please use a different email address', 'fluent-support')
71 + 'message' => Helper::getSafeErrorMessage($e)
75 72 ]);
76 73 }
77 -
78 - $data['user_id'] = $user->ID;
79 - $agent = Agent::create($data);
80 - PermissionManager::attachPermissions($user, Arr::get($data, 'permissions', []));
81 -
82 - if(!empty($data['telegram_chat_id'])) {
83 - $chatId = sanitize_text_field($data['telegram_chat_id']);
84 - $agent->updateMeta('telegram_chat_id', $chatId);
85 - $agent->telegram_chat_id = $chatId;
86 - }
87 -
88 - if(!empty($data['slack_user_id'])) {
89 - $chatId = sanitize_text_field($data['slack_user_id']);
90 - $agent->updateMeta('slack_user_id', $chatId);
91 - $agent->slack_user_id = $chatId;
92 - }
93 -
94 - return [
95 - 'message' => __('Support Staff has been added', 'fluent-support'),
96 - 'agent' => $agent
97 - ];
98 74 }
99 75
100 - public function updateAgent(Request $request, $agentId)
76 + /**
77 + * The agent's tickets and data move to fallback_agent_id.
78 + *
79 + * @param Request $request
80 + * @param Agent $agent
81 + * @param int $agent_id
82 + * @return \WP_REST_Response | array
83 + * @throws \FluentSupport\Framework\Validator\ValidationException
84 + */
85 + public function deleteAgent(Request $request, Agent $agent, $agent_id)
101 86 {
102 - $agent = Agent::findOrFail($agentId);
103 - $data = $request->all();
104 - $this->validate($data, [
105 - 'email' => 'required|email',
106 - 'first_name' => 'required',
107 - 'last_name' => 'required',
108 - ]);
87 + try {
88 + $agent->deleteAgent($request->getSafe('fallback_agent_id', 'intval'), $agent_id);
109 89
110 - $user = get_user_by('ID', $agent->user_id);
111 -
112 - if (!$user || is_wp_error($user)) {
90 + return [
91 + 'message' => __('Support Staff has been deleted', 'fluent-support')
92 + ];
93 + } catch (\Exception $e) {
113 94 return $this->sendError([
114 - 'message' => __('Sorry, Connected user could not be found with the provided email address', 'fluent-support')
95 + 'message' => Helper::getSafeErrorMessage($e)
115 96 ]);
116 97 }
98 + }
117 99
118 - PermissionManager::attachPermissions($user, Arr::get($data, 'permissions', []));
100 + /**
101 + * @param Request $request
102 + * @return \WP_REST_Response | array
103 + */
104 + public function myStats(Request $request)
105 + {
106 + $agent = Helper::getAgentByUserId();
119 107
120 - $updateData = Arr::only($data, ['first_name', 'last_name', 'title']);
121 - $updateData['email'] = $user->user_email;
108 + try {
109 + $stats = StatModule::getAgentStat($agent->id);
110 + $with = $request->get('with', []);
111 + $with = is_array($with) ? map_deep($with, 'sanitize_text_field') : [];
122 112
123 - Agent::where('id', $agent->id)
124 - ->update($updateData);
113 + $response = (new Agent())->getAgentStat($stats, $with, $agent->id);
125 114
126 - PermissionManager::attachPermissions($user, Arr::get($data, 'permissions', []));
115 + if (defined('FLUENTSUPPORTPRO')) {
116 + $response['dashboard_notice'] = apply_filters('fluent_support/dashboard_notice', '', $agent);
117 + }
127 118
128 - $agent = Agent::findOrFail($agentId);
119 + return $response;
120 + } catch (\Exception $e) {
121 + return $this->sendError([
122 + 'message' => Helper::getSafeErrorMessage($e)
123 + ]);
124 + }
125 + }
129 126
130 - if(isset($data['telegram_chat_id'])) {
131 - $chatId = sanitize_text_field($data['telegram_chat_id']);
132 - $agent->updateMeta('telegram_chat_id', $chatId);
133 - $agent->telegram_chat_id = $chatId;
134 - }
127 + public function agentPerformance()
128 + {
129 + try {
130 + if (PermissionManager::currentUserCan('fst_agent_today_performance')) {
131 + $agentTodayStats = StatModule::getAgentTodayStats();
135 132
136 - if(isset($data['slack_user_id'])) {
137 - $chatId = sanitize_text_field($data['slack_user_id']);
138 - $agent->updateMeta('slack_user_id', $chatId);
139 - $agent->slack_user_id = $chatId;
133 + return ['agent_today_stats' => $agentTodayStats];
134 + }
135 + } catch (\Exception $e) {
136 + return $this->sendError([
137 + 'message' => Helper::getSafeErrorMessage($e)
138 + ]);
140 139 }
141 140
142 - return [
143 - 'message' => __('Support Staff has been updated', 'fluent-support'),
144 - 'agent' => $agent
145 - ];
141 + return [];
146 142 }
147 143
148 - public function deleteAgent(Request $request, $agentId)
144 + /**
145 + * @param Request $request
146 + * @param AvatarUploder $avatarUploder
147 + * @return \WP_REST_Response | array
148 + */
149 + public function addOrUpdateProfileImage(Request $request, AvatarUploder $avatarUploder)
149 150 {
150 - $fallBackAgentId = $request->get('fallback_agent_id');
151 -
152 - if ($fallBackAgentId == $agentId) {
151 + try {
152 + return $avatarUploder->addOrUpdateProfileImage($request->files(), $request->getSafe('agent_id', 'intval'), 'agent');
153 + } catch (\Exception $e) {
153 154 return $this->sendError([
154 - 'message' => __('Old Agent and New agent is same person', 'fluent-support')
155 + 'message' => Helper::getSafeErrorMessage($e)
155 156 ]);
156 157 }
158 + }
157 159
158 - $agent = Agent::findOrFail($agentId);
160 + /**
161 + * No Agent type-hint: route-model binding runs before the policy, which would
162 + * let unauthenticated callers probe agent IDs. Resolve after auth.
163 + *
164 + * @param int|string $agent
165 + * @return array
166 + */
167 + public function resetAvatar($agent)
168 + {
169 + try {
170 + $agent = Agent::findOrFail((int) $agent);
171 + $agent->restoreAvatar();
159 172
160 - PermissionManager::attachPermissions($agent->user_id, []);
173 + return [
174 + 'message' => __('Support Staff avatar reset to gravatar default', 'fluent-support')
175 + ];
176 + } catch (\Exception $e) {
177 + return $this->sendError([
178 + 'message' => Helper::getSafeErrorMessage($e)
179 + ]);
180 + }
181 + }
161 182
162 - $newAgent = Agent::findOrFail($fallBackAgentId);
183 + public function getAgentInsights(Request $request, Agent $agent)
184 + {
185 + return [
186 + 'agents' => $agent->agentInsights($request->getSafe('search', 'sanitize_text_field')),
187 + ];
188 + }
163 189
164 - Attachment::where('person_id', $agentId)->update([
165 - 'person_id' => $newAgent->id
166 - ]);
167 -
168 - Conversation::where('person_id', $agentId)->update([
169 - 'person_id' => $newAgent->id
170 - ]);
171 -
172 - Product::where('created_by', $agentId)->update([
173 - 'created_by' => $newAgent->id
174 - ]);
175 -
176 - Ticket::where('agent_id', $agentId)->update([
177 - 'agent_id' => $newAgent->id
178 - ]);
179 -
180 - $agent->deleteAllMeta();
181 -
182 - Agent::where('id', $agentId)->delete();
183 -
190 + public function ping(Request $request)
191 + {
184 192 return [
185 - 'message' => __('Selected support staff has been deleted', 'fluent-support')
193 + 'ping' => 'pong',
186 194 ];
187 -
188 195 }
189 196
190 - public function myStats(Request $request)
197 + /**
198 + * @param AgentCreateRequest $request
199 + * @param bool $includeEmail
200 + * @return array
201 + */
202 + private function sanitizeAgentPayload(AgentCreateRequest $request, $includeEmail = false)
191 203 {
192 - $agent = Helper::getAgentByUserId();
193 - $response = $this->getAgentStat($request, $agent->id);
204 + $data = [
205 + 'first_name' => $request->getSafe('first_name', 'sanitize_text_field'),
206 + 'last_name' => $request->getSafe('last_name', 'sanitize_text_field'),
207 + 'title' => $request->getSafe('title', 'sanitize_text_field'),
208 + 'permissions' => is_array($request->get('permissions')) ? array_map('sanitize_key', $request->get('permissions')) : [],
209 + 'telegram_chat_id' => $request->getSafe('telegram_chat_id', 'sanitize_text_field'),
210 + 'slack_user_id' => $request->getSafe('slack_user_id', 'sanitize_text_field'),
211 + 'whatsapp_number' => $request->getSafe('whatsapp_number', 'sanitize_text_field'),
212 + 'restrictions' => $this->sanitizeRestrictions($request->get('restrictions')),
213 + ];
194 214
195 - if(defined('FLUENTSUPPORTPRO')) {
196 - $response['dashboard_notice'] = apply_filters('fluent_support/dashboard_notice', '', $agent);
215 + if ($request->has('agent_signature')) {
216 + // Already unslashed by the request. Don't unslash again or literal backslashes are lost.
217 + $data['agent_signature'] = wp_kses_post($request->get('agent_signature', ''));
197 218 }
198 219
199 - return $response;
220 + if ($request->has('agent_signature_enabled')) {
221 + $data['agent_signature_enabled'] = $request->get('agent_signature_enabled') === 'yes' ? 'yes' : 'no';
222 + }
200 223
224 + if ($includeEmail) {
225 + $data['email'] = $request->getSafe('email', 'sanitize_email');
226 + }
227 +
228 + return $data;
201 229 }
202 230
203 - public function getAgentStat(Request $request, $agentId)
231 + /**
232 + * @param mixed $restrictions
233 + * @return array
234 + */
235 + private function sanitizeRestrictions($restrictions)
204 236 {
205 - $agent = Agent::findOrFail($agentId);
206 - $stats = StatModule::getAgentStat($agentId);
207 -
208 - if (PermissionManager::currentUserCan('fst_manage_unassigned_tickets')) {
209 - $stats['unassigned_tickets'] = [
210 - 'title' => __('Unassigned Tickets', 'fluent-support'),
211 - 'count' => Ticket::whereNull('agent_id')->where('status', '!=', 'closed')->count()
237 + if (!is_array($restrictions)) {
238 + return [
239 + 'restrictedBusinessBoxes' => [],
240 + 'businessBoxRestrictions' => false,
212 241 ];
213 242 }
214 243
215 - $data = [
216 - 'stats' => $stats
217 - ];
244 + $restrictedBusinessBoxes = isset($restrictions['restrictedBusinessBoxes']) && is_array($restrictions['restrictedBusinessBoxes'])
245 + ? array_map('absint', $restrictions['restrictedBusinessBoxes'])
246 + : [];
218 247
219 - $with = $request->get('with', []);
248 + $businessBoxRestrictions = isset($restrictions['businessBoxRestrictions'])
249 + ? rest_sanitize_boolean($restrictions['businessBoxRestrictions'])
250 + : false;
220 251
221 - if (in_array('suggested_tickets', $with)) {
222 - $data['suggested_tickets'] = TicketHelper::getSuggestedTickets($agent->id);
223 - }
224 -
225 - if(in_array('overall_stats', $with)) {
226 - $data['overall_stats'] = (new Reporting())->getActiveStats();
227 - }
228 -
229 - if(in_array('individual_stat', $with)) {
230 - $data['individual_stat'] = (new Reporting())->getActiveStatByAgent($agent->id);
231 - }
232 - if(in_array('my_overall_stats', $with)){
233 - $data['my_overall_stats'] = StatModule::getAgentOverallStats($agent->id);
234 - }
235 -
236 - return $data;
252 + return [
253 + 'restrictedBusinessBoxes' => $restrictedBusinessBoxes,
254 + 'businessBoxRestrictions' => $businessBoxRestrictions,
255 + ];
237 256 }
238 257 }