| @@ -2,34 +2,254 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace FluentSupport\App\Http\Policies; |
| 4 | 4 | |
| 5 | 5 | use FluentSupport\App\Modules\PermissionManager; |
| 6 | -use FluentSupport\Framework\Request\Request; | |
| 6 | +use FluentSupport\Framework\Http\Request\Request; | |
| 7 | 7 | use FluentSupport\Framework\Foundation\Policy; |
| 8 | 8 | |
| 9 | 9 | class AgentTicketPolicy extends Policy |
| 10 | 10 | { |
| 11 | 11 | /** |
| 12 | - * Check user permission for any method | |
| 13 | - * @param \FluentSupport\Framework\Request\Request $request | |
| 12 | + * Reads need view permission, writes need manage permission. | |
| 13 | + * | |
| 14 | + * Use getMethod(), not method(). method() returns the raw REQUEST_METHOD, but | |
| 15 | + * WordPress dispatches on the _method / X-HTTP-Method-Override value, so a | |
| 16 | + * write could pass as a GET. | |
| 17 | + * | |
| 18 | + * @param \FluentSupport\Framework\Http\Request\Request $request | |
| 14 | 19 | * @return Boolean |
| 15 | 20 | */ |
| 16 | 21 | public function verifyRequest(Request $request) |
| 17 | 22 | { |
| 18 | - $permissions = PermissionManager::currentUserPermissions(); | |
| 19 | - $acceptedPermissions = ['fst_manage_own_tickets', 'fst_manage_unassigned_tickets', 'fst_manage_other_tickets', 'fst_merge_tickets','fst_draft_reply']; | |
| 20 | - $status = !!array_intersect($permissions, $acceptedPermissions); | |
| 23 | + // @phpstan-ignore-next-line -- proxied to WP_REST_Request by Request::__call() | |
| 24 | + if ($request->getMethod() === 'GET') { | |
| 25 | + $status = PermissionManager::userCan([ | |
| 26 | + 'fst_view_tickets', | |
| 27 | + 'fst_draft_reply', | |
| 28 | + 'fst_manage_own_tickets', | |
| 29 | + 'fst_manage_unassigned_tickets', | |
| 30 | + 'fst_manage_other_tickets' | |
| 31 | + ]); | |
| 32 | + } else { | |
| 33 | + // Unknown verbs land here too. Writes open to draft/view-only agents | |
| 34 | + // have their own policy methods below. | |
| 35 | + $status = PermissionManager::canManageTickets(); | |
| 36 | + } | |
| 21 | 37 | |
| 22 | 38 | return apply_filters('fluent_support/agent_has_access', $status, $request); |
| 23 | 39 | } |
| 24 | 40 | |
| 41 | + /** | |
| 42 | + * Backs the Add Ticket flow. | |
| 43 | + */ | |
| 44 | + public function searchContact(Request $request) | |
| 45 | + { | |
| 46 | + return PermissionManager::canManageTickets(); | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Same gates as the single-ticket routes. Both assign actions write agent_id, | |
| 51 | + * so both need fst_assign_agents. | |
| 52 | + */ | |
| 25 | 53 | public function doBulkActions(Request $request) |
| 26 | 54 | { |
| 27 | - $action = $request->get('bulk_action'); | |
| 55 | + $action = $request->getSafe('bulk_action', 'sanitize_text_field'); | |
| 28 | 56 | |
| 29 | - if ($action == 'delete_tickets') { | |
| 30 | - return PermissionManager::currentUserCan('fst_delete_tickets'); | |
| 57 | + if ($action === 'delete_tickets') { | |
| 58 | + return PermissionManager::currentUserCan('fst_delete_tickets') | |
| 59 | + && PermissionManager::canManageTickets(); | |
| 31 | 60 | } |
| 32 | 61 | |
| 33 | - return $this->verifyRequest($request); | |
| 62 | + if ($action === 'assign_agent' || $action === 'assign_agent_group') { | |
| 63 | + return PermissionManager::currentUserCan('fst_assign_agents') | |
| 64 | + && PermissionManager::canManageTickets(); | |
| 65 | + } | |
| 66 | + | |
| 67 | + return PermissionManager::canManageTickets(); | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * View-only and draft agents see every ticket, so fst_delete_tickets alone | |
| 72 | + * would let them delete any of them. | |
| 73 | + */ | |
| 74 | + public function deleteTicket(Request $request) | |
| 75 | + { | |
| 76 | + return PermissionManager::currentUserCan('fst_delete_tickets') | |
| 77 | + && PermissionManager::canManageTickets(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Same gate as deleteTicket. The controller checks per-ticket access. | |
| 82 | + */ | |
| 83 | + public function deleteResponse(Request $request) | |
| 84 | + { | |
| 85 | + return PermissionManager::currentUserCan('fst_delete_tickets') | |
| 86 | + && PermissionManager::canManageTickets(); | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Author, type and per-ticket access are checked in the controller. | |
| 91 | + */ | |
| 92 | + public function updateResponse(Request $request) | |
| 93 | + { | |
| 94 | + return PermissionManager::canManageTickets(); | |
| 95 | + } | |
| 96 | + | |
| 97 | + public function createResponse(Request $request) | |
| 98 | + { | |
| 99 | + return PermissionManager::canManageTickets() | |
| 100 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 101 | + } | |
| 102 | + | |
| 103 | + public function createOrUpdatDraft(Request $request) | |
| 104 | + { | |
| 105 | + return PermissionManager::canManageTickets() | |
| 106 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Saved label searches are personal, so any agent with ticket access may write them. | |
| 111 | + */ | |
| 112 | + public function storeOrUpdateLabelSearch(Request $request) | |
| 113 | + { | |
| 114 | + return PermissionManager::canAccessTicketRoutes(); | |
| 115 | + } | |
| 116 | + | |
| 117 | + public function deleteLabelSearch(Request $request) | |
| 118 | + { | |
| 119 | + return PermissionManager::canAccessTicketRoutes(); | |
| 120 | + } | |
| 121 | + | |
| 122 | + public function removeLiveActivity(Request $request) | |
| 123 | + { | |
| 124 | + return PermissionManager::canAccessTicketRoutes(); | |
| 125 | + } | |
| 126 | + | |
| 127 | + public function updateTicketProperty(Request $request) | |
| 128 | + { | |
| 129 | + return PermissionManager::canManageTickets(); | |
| 130 | + } | |
| 131 | + | |
| 132 | + public function addTicketWatchers(Request $request) | |
| 133 | + { | |
| 134 | + return PermissionManager::canManageTickets(); | |
| 135 | + } | |
| 136 | + | |
| 137 | + public function syncTicketWatchers(Request $request) | |
| 138 | + { | |
| 139 | + return PermissionManager::canManageTickets(); | |
| 140 | + } | |
| 141 | + | |
| 142 | + public function updateEstimatedTime(Request $request) | |
| 143 | + { | |
| 144 | + return PermissionManager::canManageTickets(); | |
| 145 | + } | |
| 146 | + | |
| 147 | + public function manualCommitTrack(Request $request) | |
| 148 | + { | |
| 149 | + return PermissionManager::canManageTickets(); | |
| 150 | + } | |
| 151 | + | |
| 152 | + public function approveDraftResponse(Request $request) | |
| 153 | + { | |
| 154 | + return PermissionManager::currentUserCan('fst_approve_draft_reply') | |
| 155 | + && PermissionManager::canAccessTicketRoutes(); | |
| 156 | + } | |
| 157 | + | |
| 158 | + public function deleteDraft(Request $request) | |
| 159 | + { | |
| 160 | + return PermissionManager::canManageTickets() | |
| 161 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 162 | + } | |
| 163 | + | |
| 164 | + // FluentBot AI-assist actions. | |
| 165 | + public function generateResponse(Request $request) | |
| 166 | + { | |
| 167 | + return PermissionManager::canAccessTicketRoutes(); | |
| 168 | + } | |
| 169 | + | |
| 170 | + public function getRuntimeConfig(Request $request) | |
| 171 | + { | |
| 172 | + return PermissionManager::canAccessTicketRoutes(); | |
| 173 | + } | |
| 174 | + | |
| 175 | + public function generateStreamResponse(Request $request) | |
| 176 | + { | |
| 177 | + return PermissionManager::canAccessTicketRoutes(); | |
| 178 | + } | |
| 179 | + | |
| 180 | + public function getTicketSummary(Request $request) | |
| 181 | + { | |
| 182 | + return PermissionManager::canAccessTicketRoutes(); | |
| 183 | + } | |
| 184 | + | |
| 185 | + public function getTicketTone(Request $request) | |
| 186 | + { | |
| 187 | + return PermissionManager::canAccessTicketRoutes(); | |
| 188 | + } | |
| 189 | + | |
| 190 | + public function markRead(Request $request) | |
| 191 | + { | |
| 192 | + return PermissionManager::canAccessTicketRoutes(); | |
| 193 | + } | |
| 194 | + | |
| 195 | + public function markAllRead(Request $request) | |
| 196 | + { | |
| 197 | + return PermissionManager::canAccessTicketRoutes(); | |
| 198 | + } | |
| 199 | + | |
| 200 | + public function getChatId(Request $request) | |
| 201 | + { | |
| 202 | + return PermissionManager::canAccessTicketRoutes(); | |
| 203 | + } | |
| 204 | + | |
| 205 | + public function getChatMessages(Request $request) | |
| 206 | + { | |
| 207 | + return PermissionManager::canAccessTicketRoutes(); | |
| 208 | + } | |
| 209 | + | |
| 210 | + public function getContextSelection(Request $request) | |
| 211 | + { | |
| 212 | + return PermissionManager::canAccessTicketRoutes(); | |
| 213 | + } | |
| 214 | + | |
| 215 | + public function getConversations(Request $request) | |
| 216 | + { | |
| 217 | + return PermissionManager::canAccessTicketRoutes(); | |
| 218 | + } | |
| 219 | + | |
| 220 | + public function saveChatId(Request $request) | |
| 221 | + { | |
| 222 | + return PermissionManager::canManageTickets() | |
| 223 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 224 | + } | |
| 225 | + | |
| 226 | + public function deleteChatId(Request $request) | |
| 227 | + { | |
| 228 | + return PermissionManager::canManageTickets() | |
| 229 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 230 | + } | |
| 231 | + | |
| 232 | + public function saveContextSelection(Request $request) | |
| 233 | + { | |
| 234 | + return PermissionManager::canManageTickets() | |
| 235 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 236 | + } | |
| 237 | + | |
| 238 | + public function switchConversation(Request $request) | |
| 239 | + { | |
| 240 | + return PermissionManager::canManageTickets() | |
| 241 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 242 | + } | |
| 243 | + | |
| 244 | + public function createFeedback(Request $request) | |
| 245 | + { | |
| 246 | + return PermissionManager::canManageTickets() | |
| 247 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 248 | + } | |
| 249 | + | |
| 250 | + public function deleteFeedback(Request $request) | |
| 251 | + { | |
| 252 | + return PermissionManager::canManageTickets() | |
| 253 | + || PermissionManager::currentUserCan('fst_draft_reply'); | |
| 34 | 254 | } |
| 35 | 255 | } |