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
fluent-support / app / Modules / MCP / Support / AbilityGuard.php

AbilityGuard.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.5, at app/Modules/MCP/Support/AbilityGuard.php

111 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Modules\MCP\Support;
4
5 use FluentSupport\App\Modules\PermissionManager;
6
7 class AbilityGuard
8 {
9 const MANAGE_TICKET_CAPS = [
10 'fst_manage_own_tickets',
11 'fst_manage_unassigned_tickets',
12 'fst_manage_other_tickets',
13 ];
14
15 /**
16 * Per-ability caps. any_of needs one of the caps, all_of needs every cap.
17 * When both are set, both must pass.
18 */
19 private static function capabilities()
20 {
21 return [
22 'fluent-support/list-tickets' => ['any_of' => ['fst_view_tickets']],
23 'fluent-support/get-ticket' => ['any_of' => ['fst_view_tickets']],
24 'fluent-support/create-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS],
25 // Draft-only agents may call it; ResponseTools forces draft mode for them.
26 'fluent-support/reply-to-ticket' => ['any_of' => array_merge(self::MANAGE_TICKET_CAPS, ['fst_draft_reply'])],
27 'fluent-support/close-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS],
28 'fluent-support/update-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS],
29 'fluent-support/delete-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS, 'all_of' => ['fst_delete_tickets']],
30 'fluent-support/get-ticket-activity' => ['any_of' => ['fst_view_tickets']],
31 'fluent-support/merge-tickets' => ['any_of' => ['fst_merge_tickets']],
32 'fluent-support/add-internal-note' => ['any_of' => self::MANAGE_TICKET_CAPS],
33 // Own drafts and notes only (row gate in ResponseTools).
34 'fluent-support/update-response' => ['any_of' => array_merge(self::MANAGE_TICKET_CAPS, ['fst_draft_reply'])],
35 'fluent-support/delete-response' => ['any_of' => array_merge(self::MANAGE_TICKET_CAPS, ['fst_draft_reply'])],
36 // Approvers publish any draft; managers their own (checked in the tool).
37 'fluent-support/publish-draft-reply' => ['any_of' => array_merge(self::MANAGE_TICKET_CAPS, ['fst_approve_draft_reply'])],
38 'fluent-support/tag-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS],
39 'fluent-support/get-customer-tickets' => ['any_of' => ['fst_sensitive_data']],
40 'fluent-support/get-support-context' => ['any_of' => ['fst_view_tickets']],
41 'fluent-support/list-saved-replies' => ['any_of' => ['fst_manage_saved_replies']],
42 'fluent-support/get-support-insights' => ['any_of' => ['fst_view_all_reports']],
43 'fluent-support/search-customers' => ['any_of' => ['fst_sensitive_data']],
44 'fluent-support/get-mentions' => ['any_of' => ['fst_view_tickets']],
45 'fluent-support/update-customer' => ['any_of' => ['fst_sensitive_data']],
46 // Same as the admin route: a ticket manager who also holds Split Ticket.
47 'fluent-support/split-ticket' => ['any_of' => self::MANAGE_TICKET_CAPS, 'all_of' => ['fst_split_ticket']],
48 // Prompts: they only return instructions; the tools they name check their own caps.
49 'fluent-support/triage-queue' => ['any_of' => ['fst_view_tickets']],
50 'fluent-support/draft-reply' => ['any_of' => ['fst_view_tickets']],
51 'fluent-support/summarize-ticket' => ['any_of' => ['fst_view_tickets']],
52 'fluent-support/support-report' => ['any_of' => ['fst_view_all_reports']],
53 'fluent-support/bulk-action' => ['any_of' => self::MANAGE_TICKET_CAPS],
54 ];
55 }
56
57 /**
58 * permission_callback for an ability. Only checks login and fails closed for
59 * unknown abilities. Caps are checked in AbilitiesRegistrar::wrapExecuteCallback()
60 * so denials come back as structured errors, not the adapter's "Permission denied".
61 */
62 public static function callbackFor($abilityName)
63 {
64 return function () use ($abilityName) {
65 if (!array_key_exists($abilityName, self::capabilities())) {
66 return false;
67 }
68 return is_user_logged_in();
69 };
70 }
71
72 public static function check($abilityName)
73 {
74 $caps = self::capabilities()[$abilityName] ?? null;
75
76 if ($caps === null) {
77 return false;
78 }
79
80 return self::checkCaps($caps);
81 }
82
83 /**
84 * Whether the current user has these caps: any_of needs one, all_of needs every
85 * one. Pro's tools pass their own caps here so both plugins check the same way.
86 *
87 * @param array{any_of?: string[], all_of?: string[]} $caps
88 * @return bool
89 */
90 public static function checkCaps(array $caps)
91 {
92 if (empty($caps['any_of']) && empty($caps['all_of'])) {
93 return false;
94 }
95
96 if (!empty($caps['any_of']) && !PermissionManager::userCan($caps['any_of'])) {
97 return false;
98 }
99
100 if (!empty($caps['all_of'])) {
101 foreach ($caps['all_of'] as $cap) {
102 if (!PermissionManager::currentUserCan($cap)) {
103 return false;
104 }
105 }
106 }
107
108 return true;
109 }
110 }
111