PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.9
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.9
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Manager / ManagerService.php

ManagerService.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.9, at app/Services/Manager/ManagerService.php

231 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\Manager;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\App\Modules\Acl\Acl;
7 use FluentForm\Framework\Support\Arr;
8 use FluentForm\Framework\Validator\ValidationException;
9 use FluentForm\Framework\Validator\Validator;
10
11 class ManagerService
12 {
13 public function getManagers($attributes = [])
14 {
15 $limit = Arr::get($attributes, 'per_page', 10);
16 $page = Arr::get($attributes, 'page', 1);
17 $offset = 1 == $page ? 0 : ($page - 1) * $limit;
18
19 $query = new \WP_User_Query([
20 'meta_key' => '_fluent_forms_has_role',
21 'meta_value' => 1,
22 'meta_compare' => '=',
23 'number' => $limit,
24 'offset' => $offset,
25 ]);
26
27 $managers = [];
28
29 foreach ($query->get_results() as $user) {
30 $allowedForms = FormManagerService::getUserAllowedFormsScope($user->ID);
31 $hasSpecificFormsPermission = false !== $allowedForms;
32 $managers[] = [
33 'id' => $user->ID,
34 'first_name' => $user->first_name,
35 'last_name' => $user->last_name,
36 'email' => $user->user_email,
37 'permissions' => Acl::getUserPermissions($user),
38 'forms' => false !== $allowedForms ? array_values($allowedForms) : false,
39 'roles' => $this->getUserRoles($user->roles),
40 'has_specific_forms_permission'=> $hasSpecificFormsPermission ? 'yes' : 'no',
41 ];
42 }
43
44 $total = $query->get_total();
45
46 $forms = Helper::getForms();
47 if ($forms) {
48 Arr::forget($forms, 0);
49 }
50
51 return ([
52 'managers' => $managers,
53 'total' => $total,
54 'permissions' => Acl::getReadablePermissions(),
55 'forms' => $forms,
56 ]);
57 }
58
59 public function addManager($attributes = [])
60 {
61 $manager = Arr::get($attributes, 'manager');
62
63 $this->validate($manager);
64
65 $permissions = Arr::get($manager, 'permissions', []);
66
67 // Defense in depth: only a full WordPress administrator may grant the
68 // crown-jewel `fluentform_full_access` permission. A holder of that ACL
69 // permission is not necessarily a WP admin (managers can be delegated),
70 // so without this a compromised full-access session — e.g. a script
71 // running via XSS in a privileged session — could mint new full-access
72 // managers and escalate. Lesser permission grants are unaffected.
73 if (in_array('fluentform_full_access', (array) $permissions, true) && !current_user_can('manage_options')) {
74 $permissions = array_values(array_filter((array) $permissions, function ($permission) {
75 return 'fluentform_full_access' !== $permission;
76 }));
77 }
78
79 $user = get_user_by('email', $manager['email']);
80
81 if (!$user) {
82 throw new ValidationException('', 0, null, ['message' => 'Please Provide Valid Email']);
83 }
84
85 Acl::attachPermissions($user, $permissions);
86
87 update_user_meta($user->ID, '_fluent_forms_has_role', 1);
88
89 $hasSpecificFormsPermission = 'yes' === Arr::get($manager, 'has_specific_forms_permission');
90 $allowedForms = array_values(array_filter(array_map('intval', (array) Arr::get($manager, 'forms', []))));
91
92 // Keep an empty selection unrestricted so the manager UI's
93 // "leave blank for all forms" behavior matches the saved ACL state.
94 if ($hasSpecificFormsPermission && $allowedForms) {
95 FormManagerService::updateHasSpecificFormsPermission($user->ID, 'yes');
96 FormManagerService::addUserAllowedForms($allowedForms, $user->ID);
97 } else {
98 FormManagerService::updateHasSpecificFormsPermission($user->ID, 'no');
99 FormManagerService::deleteUserAllowedForms($user->ID);
100 }
101
102 $updatedUser = [
103 'id' => $user->ID,
104 'first_name' => $user->first_name,
105 'last_name' => $user->last_name,
106 'email' => $user->user_email,
107 'permissions' => Acl::getUserPermissions($user),
108 ];
109
110 return ([
111 'message' => __('Manager has been saved.', 'fluentform'),
112 'manager' => $updatedUser,
113 ]);
114 }
115
116 public function removeManager($attributes = [])
117 {
118 $userID = intval(Arr::get($attributes, 'id'));
119 $user = get_user_by('ID', $userID);
120
121 if (!$user) {
122 return ([
123 'message' => __('Associate user could not be found', 'fluentform'),
124 ]);
125 }
126
127 Acl::attachPermissions($user, []);
128
129 delete_user_meta($user->ID, '_fluent_forms_has_role');
130
131 $deletedUser = [
132 'id' => $user->ID,
133 'first_name' => $user->first_name,
134 'last_name' => $user->last_name,
135 'email' => $user->user_email,
136 'permissions' => Acl::getUserPermissions($user),
137 ];
138
139 return ([
140 'message' => __('Manager has been removed.', 'fluentform'),
141 'manager' => $deletedUser,
142 ]);
143 }
144
145 private function validate($manager)
146 {
147 $rules = [
148 'permissions' => 'required',
149 'email' => 'required|email',
150 ];
151
152 $validatorInstance = new Validator();
153 $validator = $validatorInstance->make($manager, $rules);
154
155 $errors = null;
156
157 if ($validator->validate()->fails()) {
158 $errors = $validator->errors();
159 }
160
161 if (!isset($errors['email'])) {
162 $user = get_user_by('email', $manager['email']);
163
164 if (!$user) {
165 $errors['email'] = [
166 'no_user' => __('We could not found any user with this email.', 'fluentform'),
167 ];
168 }
169 }
170
171 if (!isset($errors['permissions'])) {
172 $message = $this->dependencyValidate($manager['permissions']);
173
174 if ($message) {
175 $errors['permissions'] = [
176 'dependency' => $message,
177 ];
178 }
179 }
180
181 if ($errors) {
182 // Escape all error messages before throwing
183 $escapedErrors = array_map(function ($errorMessages) {
184 if (is_array($errorMessages)) {
185 return array_map('esc_html', $errorMessages);
186 }
187 return esc_html($errorMessages);
188 }, $errors);
189
190 throw new ValidationException('', 0, null, [
191 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Error messages are escaped above
192 'errors' => $escapedErrors,
193 ]);
194 }
195 }
196
197 private function dependencyValidate($permissions)
198 {
199 $allPermissions = Acl::getReadablePermissions();
200
201 foreach ($permissions as $permission) {
202 $depends = Arr::get($allPermissions, $permission . '.depends', []);
203
204 if ($depends && $more = array_values(array_diff($depends, $permissions))) {
205 $message = $allPermissions[$permission]['title'] . ' requires permission: ';
206
207 foreach ($more as $i => $p) {
208 $joiner = $i ? ', ' : '';
209 $message = $message . $joiner . $allPermissions[$p]['title'];
210 }
211
212 return $message;
213 }
214 }
215 }
216
217 private function getUserRoles($roles)
218 {
219 $roleStr = '';
220 if (count($roles) > 1) {
221 foreach ($roles as $role) {
222 $roleStr .= $role . ', ';
223 }
224 } else {
225 $roleStr = Arr::get($roles, '0');
226 }
227
228 return $roleStr;
229 }
230 }
231