(NFC) Apply upcoming civicrm/coder policies (batch 1)
[civicrm-core.git] / CRM / Admin / Page / AJAX.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
ce064e4f 35 * This class contains all the function that are called using AJAX.
6a488035
TO
36 */
37class CRM_Admin_Page_AJAX {
38
39 /**
b30809e4 40 * Outputs menubar data (json format) for the current user.
73538697 41 */
b30809e4
CW
42 public static function navMenu() {
43 if (CRM_Core_Session::getLoggedInContactID()) {
44
45 $menu = CRM_Core_BAO_Navigation::buildNavigationTree();
46 CRM_Core_BAO_Navigation::buildHomeMenu($menu);
47 CRM_Utils_Hook::navigationMenu($menu);
48 CRM_Core_BAO_Navigation::fixNavigationMenu($menu);
49 CRM_Core_BAO_Navigation::orderByWeight($menu);
50 CRM_Core_BAO_Navigation::filterByPermission($menu);
51 self::formatMenuItems($menu);
52
53 $output = [
54 'menu' => $menu,
55 'search' => CRM_Utils_Array::makeNonAssociative(self::getSearchOptions()),
56 ];
57 // Encourage browsers to cache for a long time - 1 year
58 $ttl = 60 * 60 * 24 * 364;
59 CRM_Utils_System::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
60 CRM_Utils_System::setHttpHeader('Cache-Control', "max-age=$ttl, public");
61 CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
62 print (json_encode($output));
73538697 63 }
0a15daa2 64 CRM_Utils_System::civiExit();
73538697
CW
65 }
66
b30809e4
CW
67 /**
68 * @param array $menu
69 */
70 public static function formatMenuItems(&$menu) {
71 foreach ($menu as $key => &$item) {
72 $props = $item['attributes'];
73 unset($item['attributes']);
74 if (!empty($props['separator'])) {
75 $item['separator'] = ($props['separator'] == 1 ? 'bottom' : 'top');
76 }
77 if (!empty($props['icon'])) {
78 $item['icon'] = $props['icon'];
79 }
80 if (!empty($props['attr'])) {
81 $item['attr'] = $props['attr'];
82 }
83 if (!empty($props['url'])) {
84 $item['url'] = CRM_Utils_System::evalUrl(CRM_Core_BAO_Navigation::makeFullyFormedUrl($props['url']));
85 }
86 if (!empty($props['label'])) {
87 $item['label'] = ts($props['label'], ['context' => 'menu']);
88 }
89 $item['name'] = !empty($props['name']) ? $props['name'] : CRM_Utils_String::munge(CRM_Utils_Array::value('label', $props));
90 if (!empty($item['child'])) {
91 self::formatMenuItems($item['child']);
92 }
93 }
94 $menu = array_values($menu);
95 }
96
4235341b 97 public static function getSearchOptions() {
b30809e4
CW
98 $searchOptions = array_merge(['sort_name'], Civi::settings()->get('quicksearch_options'));
99 $labels = CRM_Core_SelectValues::quicksearchOptions();
100 $result = [];
101 foreach ($searchOptions as $key) {
102 $label = $labels[$key];
4235341b 103 if (strpos($key, 'custom_') === 0) {
b30809e4
CW
104 $key = 'custom_' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', substr($key, 7), 'id', 'name');
105 $label = array_slice(explode(': ', $label, 2), -1);
4235341b 106 }
b30809e4 107 $result[$key] = $label;
4235341b 108 }
b30809e4 109 return $result;
4235341b
CW
110 }
111
6a488035 112 /**
ce064e4f 113 * Process drag/move action for menu tree.
6a488035 114 */
00be9182 115 public static function menuTree() {
73538697 116 CRM_Core_BAO_Navigation::processNavigation($_GET);
6a488035
TO
117 }
118
119 /**
ce064e4f 120 * Build status message while enabling/ disabling various objects.
6a488035 121 */
00be9182 122 public static function getStatusMsg() {
02fc859b 123 require_once 'api/v3/utils.php';
353ffa53 124 $recordID = CRM_Utils_Type::escape($_GET['id'], 'Integer');
12798ddc 125 $entity = CRM_Utils_Type::escape($_GET['entity'], 'String');
be2fb01f 126 $ret = [];
6a488035 127
4d17a233 128 if ($recordID && $entity && $recordBAO = _civicrm_api3_get_BAO($entity)) {
6a488035
TO
129 switch ($recordBAO) {
130 case 'CRM_Core_BAO_UFGroup':
6a488035 131 $method = 'getUFJoinRecord';
be2fb01f
CW
132 $result = [$recordBAO, $method];
133 $ufJoin = call_user_func_array(($result), [$recordID, TRUE]);
6a488035 134 if (!empty($ufJoin)) {
be2fb01f 135 $ret['content'] = ts('This profile is currently used for %1.', [1 => implode(', ', $ufJoin)]) . ' <br/><br/>' . ts('If you disable the profile - it will be removed from these forms and/or modules. Do you want to continue?');
6a488035
TO
136 }
137 else {
4d17a233 138 $ret['content'] = ts('Are you sure you want to disable this profile?');
6a488035
TO
139 }
140 break;
141
9da8dc8c 142 case 'CRM_Price_BAO_PriceSet':
9da8dc8c 143 $usedBy = CRM_Price_BAO_PriceSet::getUsedBy($recordID);
144 $priceSet = CRM_Price_BAO_PriceSet::getTitle($recordID);
6a488035
TO
145
146 if (!CRM_Utils_System::isNull($usedBy)) {
147 $template = CRM_Core_Smarty::singleton();
148 $template->assign('usedBy', $usedBy);
be2fb01f 149 $comps = [
6a488035
TO
150 'Event' => 'civicrm_event',
151 'Contribution' => 'civicrm_contribution_page',
21dfd5f5 152 'EventTemplate' => 'civicrm_event_template',
be2fb01f
CW
153 ];
154 $contexts = [];
6a488035
TO
155 foreach ($comps as $name => $table) {
156 if (array_key_exists($table, $usedBy)) {
157 $contexts[] = $name;
158 }
159 }
160 $template->assign('contexts', $contexts);
161
4d17a233 162 $ret['illegal'] = TRUE;
353ffa53 163 $table = $template->fetch('CRM/Price/Page/table.tpl');
be2fb01f 164 $ret['content'] = ts('Unable to disable the \'%1\' price set - it is currently in use by one or more active events, contribution pages or contributions.', [
0d48f1cc
TO
165 1 => $priceSet,
166 ]) . "<br/> $table";
6a488035
TO
167 }
168 else {
be2fb01f 169 $ret['content'] = ts('Are you sure you want to disable \'%1\' Price Set?', [1 => $priceSet]);
6a488035
TO
170 }
171 break;
172
173 case 'CRM_Event_BAO_Event':
4d17a233 174 $ret['content'] = ts('Are you sure you want to disable this Event?');
6a488035
TO
175 break;
176
177 case 'CRM_Core_BAO_UFField':
4d17a233 178 $ret['content'] = ts('Are you sure you want to disable this CiviCRM Profile field?');
6a488035
TO
179 break;
180
37828d4f 181 case 'CRM_Contribute_BAO_Product':
4d17a233 182 $ret['content'] = ts('Are you sure you want to disable this premium? This action will remove the premium from any contribution pages that currently offer it. However it will not delete the premium record - so you can re-enable it and add it back to your contribution page(s) at a later time.');
6a488035
TO
183 break;
184
6e4cdf9c
CW
185 case 'CRM_Contact_BAO_Relationship':
186 $ret['content'] = ts('Are you sure you want to disable this relationship?');
187 break;
188
6a488035 189 case 'CRM_Contact_BAO_RelationshipType':
4d17a233 190 $ret['content'] = ts('Are you sure you want to disable this relationship type?') . '<br/><br/>' . ts('Users will no longer be able to select this value when adding or editing relationships between contacts.');
6a488035
TO
191 break;
192
7b3622bf 193 case 'CRM_Financial_BAO_FinancialType':
4d17a233 194 $ret['content'] = ts('Are you sure you want to disable this financial type?');
6a488035 195 break;
8ef12e64 196
7b3622bf
PN
197 case 'CRM_Financial_BAO_FinancialAccount':
198 if (!CRM_Financial_BAO_FinancialAccount::getARAccounts($recordID)) {
4d17a233
CW
199 $ret['illegal'] = TRUE;
200 $ret['content'] = ts('The selected financial account cannot be disabled because at least one Accounts Receivable type account is required (to ensure that accounting transactions are in balance).');
7b3622bf
PN
201 }
202 else {
4d17a233 203 $ret['content'] = ts('Are you sure you want to disable this financial account?');
7b3622bf
PN
204 }
205 break;
6a488035 206
8ef12e64 207 case 'CRM_Financial_BAO_PaymentProcessor':
4d17a233 208 $ret['content'] = ts('Are you sure you want to disable this payment processor?') . ' <br/><br/>' . ts('Users will no longer be able to select this value when adding or editing transaction pages.');
6a488035
TO
209 break;
210
211 case 'CRM_Financial_BAO_PaymentProcessorType':
4d17a233 212 $ret['content'] = ts('Are you sure you want to disable this payment processor type?');
6a488035
TO
213 break;
214
215 case 'CRM_Core_BAO_LocationType':
4d17a233 216 $ret['content'] = ts('Are you sure you want to disable this location type?') . ' <br/><br/>' . ts('Users will no longer be able to select this value when adding or editing contact locations.');
6a488035
TO
217 break;
218
219 case 'CRM_Event_BAO_ParticipantStatusType':
4d17a233 220 $ret['content'] = ts('Are you sure you want to disable this Participant Status?') . '<br/><br/> ' . ts('Users will no longer be able to select this value when adding or editing Participant Status.');
6a488035
TO
221 break;
222
4825de4a 223 case 'CRM_Mailing_BAO_MailingComponent':
4d17a233 224 $ret['content'] = ts('Are you sure you want to disable this component?');
6a488035
TO
225 break;
226
227 case 'CRM_Core_BAO_CustomField':
4d17a233 228 $ret['content'] = ts('Are you sure you want to disable this custom data field?');
6a488035
TO
229 break;
230
231 case 'CRM_Core_BAO_CustomGroup':
4d17a233 232 $ret['content'] = ts('Are you sure you want to disable this custom data group? Any profile fields that are linked to custom fields of this group will be disabled.');
6a488035
TO
233 break;
234
c6327d7d 235 case 'CRM_Core_BAO_MessageTemplate':
4d17a233 236 $ret['content'] = ts('Are you sure you want to disable this message tempate?');
6a488035
TO
237 break;
238
239 case 'CRM_ACL_BAO_ACL':
4d17a233 240 $ret['content'] = ts('Are you sure you want to disable this ACL?');
6a488035
TO
241 break;
242
243 case 'CRM_ACL_BAO_EntityRole':
4d17a233 244 $ret['content'] = ts('Are you sure you want to disable this ACL Role Assignment?');
6a488035
TO
245 break;
246
247 case 'CRM_Member_BAO_MembershipType':
4d17a233 248 $ret['content'] = ts('Are you sure you want to disable this membership type?');
6a488035
TO
249 break;
250
251 case 'CRM_Member_BAO_MembershipStatus':
4d17a233 252 $ret['content'] = ts('Are you sure you want to disable this membership status rule?');
6a488035
TO
253 break;
254
9da8dc8c 255 case 'CRM_Price_BAO_PriceField':
4d17a233 256 $ret['content'] = ts('Are you sure you want to disable this price field?');
6a488035
TO
257 break;
258
259 case 'CRM_Contact_BAO_Group':
4d17a233 260 $ret['content'] = ts('Are you sure you want to disable this Group?');
240c0ebd 261 $ret['content'] .= '<br /><br /><strong>' . ts('WARNING - Disabling this group will disable all the child groups associated if any.') . '</strong>';
6a488035
TO
262 break;
263
264 case 'CRM_Core_BAO_OptionGroup':
4d17a233 265 $ret['content'] = ts('Are you sure you want to disable this Option?');
6a488035
TO
266 break;
267
268 case 'CRM_Contact_BAO_ContactType':
4d17a233 269 $ret['content'] = ts('Are you sure you want to disable this Contact Type?');
6a488035
TO
270 break;
271
272 case 'CRM_Core_BAO_OptionValue':
6a488035 273 $label = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $recordID, 'label');
be2fb01f 274 $ret['content'] = ts('Are you sure you want to disable the \'%1\' option ?', [1 => $label]);
4d17a233 275 $ret['content'] .= '<br /><br />' . ts('WARNING - Disabling an option which has been assigned to existing records will result in that option being cleared when the record is edited.');
6a488035
TO
276 break;
277
278 case 'CRM_Contribute_BAO_ContributionRecur':
279 $recurDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recordID);
4d17a233
CW
280 $ret['content'] = ts('Are you sure you want to mark this recurring contribution as cancelled?');
281 $ret['content'] .= '<br /><br /><strong>' . ts('WARNING - This action sets the CiviCRM recurring contribution status to Cancelled, but does NOT send a cancellation request to the payment processor. You will need to ensure that this recurring payment (subscription) is cancelled by the payment processor.') . '</strong>';
6a488035 282 if ($recurDetails->membership_id) {
4d17a233 283 $ret['content'] .= '<br /><br /><strong>' . ts('This recurring contribution is linked to an auto-renew membership. If you cancel it, the associated membership will no longer renew automatically. However, the current membership status will not be affected.') . '</strong>';
6a488035
TO
284 }
285 break;
8ef12e64 286
6a488035 287 default:
4d17a233 288 $ret['content'] = ts('Are you sure you want to disable this record?');
6a488035
TO
289 break;
290 }
291 }
4d17a233 292 else {
be2fb01f 293 $ret = ['status' => 'error', 'content' => 'Error: Unknown entity type.', 'illegal' => TRUE];
4d17a233
CW
294 }
295 CRM_Core_Page_AJAX::returnJsonResponse($ret);
6a488035
TO
296 }
297
f8b84800 298 /**
299 * Get a list of mappings.
300 *
301 * This appears to be only used by scheduled reminders.
302 */
303 static public function mappingList() {
581c7be2 304 if (empty($_GET['mappingID'])) {
be2fb01f 305 CRM_Utils_JSON::output(['status' => 'error', 'error_msg' => 'required params missing.']);
6a488035
TO
306 }
307
0905ee5d 308 $mapping = CRM_Core_BAO_ActionSchedule::getMapping($_GET['mappingID']);
be2fb01f 309 $dateFieldLabels = $mapping ? $mapping->getDateFields() : [];
9d97a648
TO
310
311 // The UX here is quirky -- for "Activity" types, there's a simple drop "Recipients"
312 // dropdown which is always displayed. For other types, the "Recipients" drop down is
313 // conditional upon the weird isLimit ('Limit To / Also Include / Neither') dropdown.
314 $noThanksJustKidding = !$_GET['isLimit'];
315 if ($mapping instanceof CRM_Activity_ActionMapping || !$noThanksJustKidding) {
be2fb01f 316 $entityRecipientLabels = $mapping ? ($mapping->getRecipientTypes() + CRM_Core_BAO_ActionSchedule::getAdditionalRecipients()) : [];
9d97a648
TO
317 }
318 else {
319 $entityRecipientLabels = CRM_Core_BAO_ActionSchedule::getAdditionalRecipients();
320 }
0905ee5d 321 $recipientMapping = array_combine(array_keys($entityRecipientLabels), array_keys($entityRecipientLabels));
6a488035 322
be2fb01f 323 $output = [
dde482e0
CW
324 'sel4' => CRM_Utils_Array::makeNonAssociative($dateFieldLabels),
325 'sel5' => CRM_Utils_Array::makeNonAssociative($entityRecipientLabels),
0905ee5d 326 'recipientMapping' => $recipientMapping,
be2fb01f 327 ];
6a488035 328
581c7be2 329 CRM_Utils_JSON::output($output);
6a488035
TO
330 }
331
bf2ce887
TO
332 /**
333 * (Scheduled Reminders) Get the list of possible recipient filters.
334 *
335 * Ex: GET /civicrm/ajax/recipientListing?mappingID=contribpage&recipientType=
336 */
337 public static function recipientListing() {
be2fb01f
CW
338 $mappingID = filter_input(INPUT_GET, 'mappingID', FILTER_VALIDATE_REGEXP, [
339 'options' => [
bf2ce887 340 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
be2fb01f
CW
341 ],
342 ]);
343 $recipientType = filter_input(INPUT_GET, 'recipientType', FILTER_VALIDATE_REGEXP, [
344 'options' => [
bf2ce887 345 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
be2fb01f
CW
346 ],
347 ]);
bf2ce887 348
be2fb01f 349 CRM_Utils_JSON::output([
dde482e0 350 'recipients' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_ActionSchedule::getRecipientListing($mappingID, $recipientType)),
be2fb01f 351 ]);
bf2ce887
TO
352 }
353
d3cbd0a5
CW
354 /**
355 * Outputs one branch in the tag tree
356 *
357 * Used by jstree to incrementally load tags
358 */
359 public static function getTagTree() {
360 $parent = CRM_Utils_Type::escape(CRM_Utils_Array::value('parent_id', $_GET, 0), 'Integer');
6e80ee11 361 $substring = CRM_Utils_Type::escape(CRM_Utils_Array::value('str', $_GET), 'String');
be2fb01f 362 $result = [];
d3cbd0a5 363
be2fb01f 364 $whereClauses = ['is_tagset <> 1'];
97dcf1d8 365 $orderColumn = 'name';
dfe61fcf 366
367 // fetch all child tags in Array('parent_tag' => array('child_tag_1', 'child_tag_2', ...)) format
6e80ee11 368 $childTagIDs = CRM_Core_BAO_Tag::getChildTags($substring);
369 $parentIDs = array_keys($childTagIDs);
370
97dcf1d8 371 if ($parent) {
372 $whereClauses[] = "parent_id = $parent";
373 }
374 elseif ($substring) {
6e80ee11 375 $whereClauses['substring'] = " name LIKE '%$substring%' ";
376 if (!empty($parentIDs)) {
97dcf1d8 377 $whereClauses['substring'] = sprintf(" %s OR id IN (%s) ", $whereClauses['substring'], implode(',', $parentIDs));
6e80ee11 378 }
97dcf1d8 379 $orderColumn = 'id';
380 }
381 else {
382 $whereClauses[] = "parent_id IS NULL";
6e80ee11 383 }
384
385 $dao = CRM_Utils_SQL_Select::from('civicrm_tag')
386 ->where($whereClauses)
387 ->groupBy('id')
97dcf1d8 388 ->orderBy($orderColumn)
6e80ee11 389 ->execute();
dfe61fcf 390
d3cbd0a5 391 while ($dao->fetch()) {
6e80ee11 392 if (!empty($substring)) {
393 $result[] = $dao->id;
394 if (!empty($childTagIDs[$dao->id])) {
395 $result = array_merge($result, $childTagIDs[$dao->id]);
396 }
397 }
398 else {
6e80ee11 399 $hasChildTags = empty($childTagIDs[$dao->id]) ? FALSE : TRUE;
400 $usedFor = (array) explode(',', $dao->used_for);
28dd94bd 401 $tag = [
6e80ee11 402 'id' => $dao->id,
403 'text' => $dao->name,
28dd94bd 404 'a_attr' => [
6e80ee11 405 'class' => 'crm-tag-item',
28dd94bd 406 ],
6e80ee11 407 'children' => $hasChildTags,
28dd94bd 408 'data' => [
6e80ee11 409 'description' => (string) $dao->description,
410 'is_selectable' => (bool) $dao->is_selectable,
411 'is_reserved' => (bool) $dao->is_reserved,
412 'used_for' => $usedFor,
413 'color' => $dao->color ? $dao->color : '#ffffff',
28dd94bd
CW
414 'usages' => civicrm_api3('EntityTag', 'getcount', [
415 'entity_table' => ['IN' => $usedFor],
6e80ee11 416 'tag_id' => $dao->id,
28dd94bd
CW
417 ]),
418 ],
419 ];
420 if ($dao->description || $dao->is_reserved) {
421 $tag['li_attr']['title'] = ((string) $dao->description) . ($dao->is_reserved ? ' (*' . ts('Reserved') . ')' : '');
422 }
423 if ($dao->is_reserved) {
424 $tag['li_attr']['class'] = 'is-reserved';
425 }
426 if ($dao->color) {
427 $tag['a_attr']['style'] = "background-color: {$dao->color}; color: " . CRM_Utils_Color::getContrast($dao->color);
428 }
429 $result[] = $tag;
d3cbd0a5 430 }
d3cbd0a5
CW
431 }
432
97dcf1d8 433 if ($substring) {
434 $result = array_values(array_unique($result));
435 }
436
dfe61fcf 437 if (!empty($_REQUEST['is_unit_test'])) {
438 return $result;
439 }
440
d3cbd0a5
CW
441 CRM_Utils_JSON::output($result);
442 }
443
6a488035 444}