searchBy($search) ->with(['groups' => function ($query) { $query->select(['fs_taggables.id', 'title']); }]) ->paginate(); $agentIds = $agents->pluck('id')->map('intval')->all(); if (!$agentIds) { return $agents; } // One query per kind of data for the whole page, not per agent. $repliesCount = Conversation::whereIn('person_id', $agentIds) ->groupBy('person_id') ->selectRaw('person_id, COUNT(*) AS total') ->pluck('total', 'person_id') ->all(); $interactionsCount = Conversation::whereIn('person_id', $agentIds) ->groupBy('person_id') ->selectRaw('person_id, COUNT(DISTINCT ticket_id) AS total') ->pluck('total', 'person_id') ->all(); $metaDefaults = [ 'telegram_chat_id' => '', 'slack_user_id' => '', 'whatsapp_number' => '', 'agent_restrictions' => [ 'restrictedBusinessBoxes' => [], 'businessBoxRestrictions' => false ], 'agent_signature' => '', 'agent_signature_enabled' => 'no', ]; $metaRows = Meta::where('object_type', 'person_meta') ->whereIn('object_id', $agentIds) ->whereIn('key', array_keys($metaDefaults)) ->orderBy('id', 'ASC') ->get(['object_id', 'key', 'value']); // First row per agent and key wins, as getMeta()'s first() did. $metaValues = []; foreach ($metaRows as $row) { if (!isset($metaValues[$row->object_id][$row->key])) { $metaValues[$row->object_id][$row->key] = Helper::safeUnserialize($row->value); } } // Prime WordPress's user and user meta caches for the permission lookups. $userIds = array_filter(array_map('intval', $agents->pluck('user_id')->all())); if ($userIds) { cache_users($userIds); } foreach ($agents as $agent) { $agent->permissions = PermissionManager::getUserPermissions($agent->user_id); if ($agent->user_id) { $agent->user_profile = admin_url('user-edit.php?user_id=' . $agent->user_id); } $agent->replies_count = (int) Arr::get($repliesCount, $agent->id, 0); $agent->interactions_count = (int) Arr::get($interactionsCount, $agent->id, 0); // Same rule as getMeta(): a missing or empty value falls back to the default. $meta = function ($key) use ($metaValues, $metaDefaults, $agent) { $value = $metaValues[$agent->id][$key] ?? null; return $value ? $value : $metaDefaults[$key]; }; $agent->telegram_chat_id = $meta('telegram_chat_id'); $agent->slack_user_id = $meta('slack_user_id'); $agent->whatsapp_number = $meta('whatsapp_number'); $agent->restrictions = $meta('agent_restrictions'); $agent->agent_signature = $meta('agent_signature'); $agent->agent_signature_enabled = $meta('agent_signature_enabled'); } return $agents; } public function createAgent(array $data) { if (!$user = get_user_by('email', $data['email'])) { throw new \Exception('Sorry, Connected user could not be found with the provided email address'); } $data = $this->setAgentInfo($data, $user); $person = Person::where('email', $data['email'])->first(); if ($person) { throw new \Exception('Sorry, Another agent/person exist with the same email address. Please use a different email address'); } $agent = $this->setAgentMeta($user, $data, static::create($data)); $defaultGroup = AgentGroup::whereNotNull('settings')->get()->first(function ($group) { return !empty($group->settings['is_default']); }); if ($defaultGroup) { TagPivot::create([ 'tag_id' => $defaultGroup->id, 'source_id' => $agent->id, 'source_type' => 'agent_group', ]); } return $agent; } /** * @param array $data * @param object $agent * @return object * @throws Exception */ public function updateAgent(array $data, object $agent) { if (!$user = get_user_by('ID', $agent->user_id)) { throw new \Exception('Sorry, Connected user could not be found with the provided email address'); } PermissionManager::attachPermissions($user, Arr::get($data, 'permissions', [])); $updateData = Arr::only($data, ['first_name', 'last_name', 'title']); $updateData['user_id'] = $user->ID; $updateData['email'] = $user->user_email; static::where('id', $agent->id) ->update($updateData); $agent = $this->setAgentMeta($user, $data, $agent); return $agent; } /** * Delete an agent and move their records to the fallback agent. * * @param int $fallBackAgentId * @param int $agentId * @return void * @throws Exception */ public function deleteAgent($fallBackAgentId, $agentId) { if ($fallBackAgentId == $agentId) { throw new \Exception('Old Agent and New agent is same person'); } $agent = static::findOrFail($agentId); try { $newAgent = static::findOrFail($fallBackAgentId); } catch (\Exception $e) { throw new \Exception('Fallback agent could not be found'); } PermissionManager::detachPermissions($agent->user_id); $this->assignDataToFallbackAgent($agent->id, $newAgent); TagPivot::where('source_id', $agent->id) ->where('source_type', 'agent_group') ->delete(); $agent->deleteAllMeta(); static::where('id', $agentId)->delete(); } /** * @param int $agentId * @param object $newAgent * @return void */ private function assignDataToFallbackAgent($agentId, $newAgent) { Attachment::where('person_id', $agentId)->update([ 'person_id' => $newAgent->id ]); Conversation::where('person_id', $agentId)->update([ 'person_id' => $newAgent->id ]); Product::where('created_by', $agentId)->update([ 'created_by' => $newAgent->id ]); Ticket::where('agent_id', $agentId)->update([ 'agent_id' => $newAgent->id ]); } public function getAgentStat($stats, $with, $agentId) { if (PermissionManager::currentUserCan('fst_manage_unassigned_tickets')) { $stats['unassigned_tickets'] = [ 'title' => __('Unassigned Tickets', 'fluent-support'), 'count' => Ticket::whereNull('agent_id')->where('status', '!=', 'closed')->count() ]; } $data = [ 'stats' => $stats ]; return $this->agentDashboardWidgets($data, $with, $agentId); } private function agentDashboardWidgets($data, $with, $agentId) { if (in_array('suggested_tickets', $with)) { $data['suggested_tickets'] = TicketHelper::getSuggestedTickets($agentId); } if (defined('FLUENTSUPPORTPRO') && in_array('ticket_to_watch', $with)) { $data['ticket_to_watch'] = TicketHelper::getTicketsToWatch(); } if (in_array('overall_stats', $with)) { $data['overall_stats'] = (new Reporting())->getActiveStats(); } if (in_array('individual_stat', $with)) { $data['individual_stat'] = (new Reporting())->getActiveStatByAgent($agentId); } if (in_array('my_overall_stats', $with)) { $data['my_overall_stats'] = StatModule::getAgentOverallStats($agentId); } if (in_array('tickets_by_products', $with)) { $data['tickets_by_product'] = StatModule::getActiveTicketsByProductStats(); } return $data; } /** * @param array $data * @param $user * @return array */ private function setAgentInfo(array $data, $user) { $data['user_id'] = $user->ID; if (empty($data['first_name'])) { $data['first_name'] = $user->first_name; } if (empty($data['last_name'])) { $data['last_name'] = $user->last_name; } return $data; } /** * Save permissions and agent settings meta. * * @param $user * @param array $data * @param object $agent * @return object */ private function setAgentMeta($user, $data, $agent) { PermissionManager::attachPermissions($user, Arr::get($data, 'permissions', [])); if (isset($data['telegram_chat_id'])) { $chatId = sanitize_text_field($data['telegram_chat_id']); $agent->updateMeta('telegram_chat_id', $chatId); $agent->telegram_chat_id = $chatId; } if (isset($data['slack_user_id'])) { $chatId = sanitize_text_field($data['slack_user_id']); $agent->updateMeta('slack_user_id', $chatId); $agent->slack_user_id = $chatId; } if (isset($data['whatsapp_number'])) { $whatsappNumber = sanitize_text_field($data['whatsapp_number']); $agent->updateMeta('whatsapp_number', $whatsappNumber); $agent->whatsapp_number = $whatsappNumber; } if (isset($data['restrictions'])) { $restrictedBusinessBoxes = $data['restrictions']['restrictedBusinessBoxes'] ?? []; $businessBoxRestrictions = filter_var($data['restrictions']['businessBoxRestrictions'] ?? false, FILTER_VALIDATE_BOOLEAN); $restrictions = [ 'restrictedBusinessBoxes' => is_array($restrictedBusinessBoxes) ? array_map('intval', $restrictedBusinessBoxes) : [], 'businessBoxRestrictions' => $businessBoxRestrictions ]; $agent->updateMeta('agent_restrictions', $restrictions); AgentTicketAccess::resetCache(); $agent->restrictions = $restrictions; } if (isset($data['agent_signature'])) { $agent->updateMeta('agent_signature', $data['agent_signature']); $agent->agent_signature = $data['agent_signature']; } if (isset($data['agent_signature_enabled'])) { $agent->updateMeta('agent_signature_enabled', $data['agent_signature_enabled']); $agent->agent_signature_enabled = $data['agent_signature_enabled']; } return $agent; } public function agentInsights($search) { $agents = static::latest() ->select('id', 'first_name', 'last_name', 'email', 'user_id') ->searchBy($search) ->get(); foreach ($agents as $agent) { $agent->permissions = PermissionManager::getUserPermissions($agent->user_id); if ($agent->user_id) { $agent->user_profile = admin_url('user-edit.php?user_id=' . $agent->user_id); } $agent->restrictions = $agent->getMeta('agent_restrictions', [ 'restrictedBusinessBoxes' => [], 'businessBoxRestrictions' => false ]); } return $agents; } }