PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Controllers/ToggleController.php +111 -33 10.0.1 → 11.1.0 View file →
@@ -1,17 +1,19 @@
1 1 <?php
2 2
3 3 namespace AcyMailing\Controllers;
4 4
5 +use AcyMailing\Classes\ListClass;
6 +use AcyMailing\Classes\MailClass;
5 7 use AcyMailing\Classes\UserClass;
6 8 use AcyMailing\Core\AcymController;
7 9
8 10 class ToggleController extends AcymController
9 11 {
10 - var $toggleableColumns = [];
11 - var $icons = [];
12 - var $tooltips = [];
13 - var $deletableRows = [];
12 + protected array $toggleableColumns = [];
13 + protected array $icons = [];
14 + protected array $tooltips = [];
15 + private array $deletableRows = [];
14 16
15 17 public function __construct()
16 18 {
17 19 parent::__construct();
@@ -19,13 +21,15 @@
19 21 $this->defaulttask = 'toggle';
20 22
21 23 $this->defineToggles();
22 24
25 + // Avoid caching issue in Internet Explorer
23 26 acym_noCache();
24 27 }
25 28
26 - protected function defineToggles()
29 + protected function defineToggles(): void
27 30 {
31 + // $this->toggleableColumns[TABLE NAME WITHOUT PREFIX] = array(COLUMN NAME => PRIMARY KEY);
28 32 $this->toggleableColumns['automation'] = ['active' => 'id'];
29 33 $this->toggleableColumns['field'] = [
30 34 'active' => 'id',
31 35 'required' => 'id',
@@ -44,8 +48,9 @@
44 48 $this->toggleableColumns['mail_override'] = ['active' => 'id'];
45 49 $this->toggleableColumns['mailbox_action'] = ['active' => 'id'];
46 50 $this->toggleableColumns['scenario'] = ['active' => 'id'];
47 51
52 + // $this->icons[TABLE NAME WITHOUT PREFIX][COLUMN NAME][VALUE] = ICON CLASS;
48 53 $this->icons['automation']['active'][1] = 'acymicon-check-circle acym__color__green';
49 54 $this->icons['automation']['active'][0] = 'acymicon-times-circle acym__color__red';
50 55 $this->icons['field']['active'][1] = 'acymicon-check-circle acym__color__green';
51 56 $this->icons['field']['active'][0] = 'acymicon-times-circle acym__color__red';
@@ -96,24 +101,32 @@
96 101 $this->tooltips['campaign']['visible'][1] = 'ACYM_VISIBLE';
97 102 $this->tooltips['mail_override']['active'][0] = 'ACYM_INACTIVE';
98 103 $this->tooltips['mail_override']['active'][1] = 'ACYM_ACTIVE';
99 104
105 + // $this->deletableRows[] = TABLE NAME WITHOUT PREFIX;
100 106 $this->deletableRows[] = 'mail';
101 107 $this->deletableRows[] = 'queue';
102 108 }
103 109
104 - public function toggle()
110 + public function toggle(): void
105 111 {
106 - acym_checkToken();
112 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
107 113
108 114 $table = acym_getVar('word', 'table', '');
109 115 $field = acym_getVar('cmd', 'field', '');
110 116 $id = acym_getVar('int', 'id', 0);
111 117 $newValue = acym_getVar('int', 'value', 0);
112 - if (!empty($newValue)) $newValue = 1;
118 + if (!empty($newValue)) {
119 + $newValue = 1;
120 + }
113 121
114 - if (empty($table) || empty($field) || empty($id) || empty($this->toggleableColumns[$table][$field])) exit;
122 + if (empty($table) || empty($field) || empty($id) || empty($this->toggleableColumns[$table][$field])) {
123 + exit;
124 + }
115 125
126 + // Security (ACL): per-table check — the 'toggle' exception opens this controller to ~10 roles regardless of table.
127 + $this->checkToggleAcl($table);
128 +
116 129 $preciseMethod = $table.ucfirst($field);
117 130 $globalMethod = $table.'Global';
118 131 if (method_exists($this, $preciseMethod)) {
119 132 $this->$preciseMethod($id, $table, $field, $newValue);
@@ -124,8 +137,9 @@
124 137 }
125 138
126 139 acym_trigger('onAcymToggle'.ucfirst($table).ucfirst($field), [&$id, &$newValue]);
127 140
141 + // Return the replacement icon
128 142 if (empty($this->icons[$table][$field][$newValue])) {
129 143 acym_sendAjaxResponse(acym_translation('ACYM_UNAUTHORIZED_ACCESS'), [], false);
130 144 }
131 145
@@ -139,38 +153,83 @@
139 153
140 154 acym_sendAjaxResponse('', $data);
141 155 }
142 156
143 - protected function doToggle($id, $table, $field, $newValue)
157 + // Each toggle icon is only rendered on the page whose ACL the user already holds, so this per-table check blocks only forged cross-feature requests (the 'toggle' exception opens the controller to ~10 roles); overridden as a no-op by FronttoggleController.
158 + protected function checkToggleAcl(string $table): void
144 159 {
160 + $tableAcl = [
161 + 'user' => 'users',
162 + 'list' => 'lists',
163 + 'campaign' => 'campaigns',
164 + 'followup' => 'campaigns',
165 + 'automation' => 'automation',
166 + 'segment' => 'segments',
167 + 'scenario' => 'scenarios',
168 + 'form' => 'forms',
169 + 'field' => 'fields',
170 + 'mailbox_action' => 'bounces',
171 + 'rule' => 'bounces',
172 + 'mail_override' => 'override',
173 + ];
174 +
175 + if (empty($tableAcl[$table]) || !acym_isAllowed($tableAcl[$table])) {
176 + acym_sendAjaxResponse(acym_translation('ACYM_ACCESS_DENIED'), [], false);
177 + }
178 + }
179 +
180 + protected function userActive(int $id, string $table, string $field, int $newValue): void
181 + {
182 + $userClass = new UserClass();
183 + if ($newValue === 0) {
184 + $userClass->deactivate([$id]);
185 + } else {
186 + $userClass->reactivate([$id]);
187 + }
188 + }
189 +
190 + protected function doToggle(int $id, string $table, string $field, int $newValue): void
191 + {
145 192 $updateQuery = 'UPDATE '.acym_secureDBColumn(ACYM_DBPREFIX.$table);
146 - $updateQuery .= ' SET `'.acym_secureDBColumn($field).'` = '.intval($newValue);
147 - $updateQuery .= ' WHERE `'.acym_secureDBColumn($this->toggleableColumns[$table][$field]).'` = '.intval($id);
193 + $updateQuery .= ' SET `'.acym_secureDBColumn($field).'` = '.$newValue;
194 + $updateQuery .= ' WHERE `'.acym_secureDBColumn($this->toggleableColumns[$table][$field]).'` = '.$id;
148 195 $updateQuery .= ' LIMIT 1';
149 196 acym_query($updateQuery);
150 197 }
151 198
152 - public function delete()
199 + public function delete(): void
153 200 {
154 201 if (!acym_isAdmin()) exit;
155 - acym_checkToken();
202 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
156 203
157 204 $table = acym_getVar('word', 'table', '');
158 - $id = acym_getVar('cmd', 'id', 0);
159 - $method = acym_getVar('word', 'method', 'delete');
205 + $id = acym_getVar('int', 'id', 0);
160 206
161 207 if (empty($table) || !in_array($table, $this->deletableRows) || empty($id)) {
162 208 exit;
163 209 }
164 210
211 + if ($table === 'queue') {
212 + $allowed = acym_isAllowed('queue');
213 + } else {
214 + $mailClass = new MailClass();
215 + $allowed = $mailClass->hasUserAccess($id, true);
216 + }
217 +
218 + if (!$allowed) {
219 + acym_sendAjaxResponse(acym_translation('ACYM_ACCESS_DENIED'), [], false);
220 + }
221 +
222 + $method = $table === 'queue' ? 'deleteQueuedByUserIds' : 'delete';
223 +
165 224 $namespaceClass = 'AcyMailing\\Classes\\'.ucfirst($table).'Class';
166 - $elementClass = new $namespaceClass;
167 - $elementClass->$method($id);
225 + $elementClass = new $namespaceClass();
226 + $elementClass->$method([$id]);
168 227
169 228 exit;
170 229 }
171 230
172 - public function setDoNotRemindMe()
231 + public function setDoNotRemindMe(): void
173 232 {
174 233 $newValue = acym_getVar('string', 'value');
175 234
176 235 if (empty($newValue)) {
@@ -176,14 +235,14 @@
176 235 if (empty($newValue)) {
177 236 acym_sendAjaxResponse(acym_translation('ACYM_ERROR_SAVING'), [], false);
178 237 }
179 238
180 - $newConfig = new \stdClass();
181 - $newConfig->remindme = json_decode($this->config->get('remindme', '[]'));
182 - if (!in_array($newValue, $newConfig->remindme)) array_push($newConfig->remindme, $newValue);
183 - $newConfig->remindme = json_encode($newConfig->remindme);
239 + $remindMe = json_decode($this->config->get('remindme', '[]'));
240 + if (!in_array($newValue, $remindMe)) {
241 + $remindMe[] = $newValue;
242 + }
184 243
185 - if ($this->config->save($newConfig)) {
244 + if ($this->config->saveConfig(['remindme' => json_encode($remindMe)])) {
186 245 acym_sendAjaxResponse(acym_translation('ACYM_THANKS'));
187 246 } else {
188 247 acym_sendAjaxResponse(acym_translation('ACYM_ERROR_SAVING'), [], false);
189 248 }
@@ -188,16 +247,26 @@
188 247 acym_sendAjaxResponse(acym_translation('ACYM_ERROR_SAVING'), [], false);
189 248 }
190 249 }
191 250
192 - public function subscribeOnClick()
251 + public function subscribeOnClick(): void
193 252 {
194 - $userId = acym_getVar('int', 'userid');
195 - $listId = acym_getVar('int', 'listid');
253 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
254 + // Security (ACL): subscription management is restricted to the 'users' role (backend); no-op on front (ownership).
255 + $this->checkToggleAcl('user');
196 256
257 + $userIds = acym_getVar('array', 'userid', []);
258 + $listIds = acym_getVar('array', 'listid', []);
259 +
197 260 $userClass = new UserClass();
198 - $result = $userClass->subscribe($userId, [$listId]);
261 + $userClass->onlyManageableUsers($userIds);
199 262
263 + $listClass = new ListClass();
264 + $listClass->onlyManageableLists($listIds);
265 +
266 + $userClass = new UserClass();
267 + $result = $userClass->subscribe($userIds, $listIds);
268 +
200 269 if ($result) {
201 270 acym_sendAjaxResponse();
202 271 } else {
203 272 acym_sendAjaxResponse('', [], false);
@@ -203,16 +272,26 @@
203 272 acym_sendAjaxResponse('', [], false);
204 273 }
205 274 }
206 275
207 - public function unsubscribeOnClick()
276 + public function unsubscribeOnClick(): void
208 277 {
209 - $userId = acym_getVar('int', 'userid');
210 - $listId = acym_getVar('int', 'listid');
278 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
279 + // Security (ACL): subscription management is restricted to the 'users' role (backend); no-op on front (ownership).
280 + $this->checkToggleAcl('user');
211 281
282 + $userIds = acym_getVar('array', 'userid', []);
283 + $listIds = acym_getVar('array', 'listid', []);
284 +
212 285 $userClass = new UserClass();
213 - $result = $userClass->unsubscribe($userId, [$listId]);
286 + $userClass->onlyManageableUsers($userIds);
214 287
288 + $listClass = new ListClass();
289 + $listClass->onlyManageableLists($listIds);
290 +
291 + $userClass = new UserClass();
292 + $result = $userClass->unsubscribe($userIds, $listIds);
293 +
215 294 if ($result) {
216 295 acym_sendAjaxResponse();
217 296 } else {
218 297 acym_sendAjaxResponse('', [], false);
@@ -217,6 +296,5 @@
217 296 } else {
218 297 acym_sendAjaxResponse('', [], false);
219 298 }
220 299 }
221 -
222 300 }