APIv4 - Generic handler for domain_id field.
[civicrm-core.git] / CRM / Core / BAO / Dashboard.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
192d36c5 19 * Class contains Contact dashboard related functions.
6a488035
TO
20 */
21class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
518fa0ee 22
3cfa8e5e 23 /**
fe482240 24 * Add Dashboard.
3cfa8e5e 25 *
6a0b768e
TO
26 * @param array $params
27 * Values.
3cfa8e5e 28 *
3cfa8e5e
EM
29 *
30 * @return object
31 */
00be9182 32 public static function create($params) {
3cfa8e5e
EM
33 $hook = empty($params['id']) ? 'create' : 'edit';
34 CRM_Utils_Hook::pre($hook, 'Dashboard', CRM_Utils_Array::value('id', $params), $params);
35 $dao = self::addDashlet($params);
36 CRM_Utils_Hook::post($hook, 'Dashboard', $dao->id, $dao);
37 return $dao;
38 }
6a488035
TO
39
40 /**
fe482240 41 * Get the list of dashlets enabled by admin.
6a488035 42 *
6a0b768e
TO
43 * @param bool $all
44 * All or only active.
45 * @param bool $checkPermission
46 * All or only authorized for the current user.
6a488035 47 *
a6c01b45
CW
48 * @return array
49 * array of dashlets
6a488035 50 */
00be9182 51 public static function getDashlets($all = TRUE, $checkPermission = TRUE) {
be2fb01f 52 $dashlets = [];
6a488035
TO
53 $dao = new CRM_Core_DAO_Dashboard();
54
55 if (!$all) {
56 $dao->is_active = 1;
57 }
58
59 $dao->domain_id = CRM_Core_Config::domainID();
60
61 $dao->find();
62 while ($dao->fetch()) {
ee117e9c 63 if ($checkPermission && !self::checkPermission($dao->permission, $dao->permission_operator)) {
6a488035
TO
64 continue;
65 }
66
be2fb01f 67 $values = [];
6a488035
TO
68 CRM_Core_DAO::storeValues($dao, $values);
69 $dashlets[$dao->id] = $values;
70 }
71
72 return $dashlets;
73 }
74
75 /**
08727453 76 * Get the list of dashlets for the current user or the specified user.
6a488035 77 *
5aa910d4
JM
78 * Additionlly, initializes the dashboard with defaults if this is the
79 * user's first visit to their dashboard.
6a488035 80 *
6a0b768e 81 * @param int $contactID
94864a5f 82 * Defaults to the current user.
77b97be7 83 *
a6c01b45
CW
84 * @return array
85 * array of dashlets
6a488035 86 */
94864a5f 87 public static function getContactDashlets($contactID = NULL) {
3bdcd4ec 88 $contactID = $contactID ? $contactID : CRM_Core_Session::getLoggedInContactID();
be2fb01f 89 $dashlets = [];
6a488035 90
5aa910d4 91 // Get contact dashboard dashlets.
be2fb01f 92 $results = civicrm_api3('DashboardContact', 'get', [
94864a5f 93 'contact_id' => $contactID,
dd3770bc
CW
94 'is_active' => 1,
95 'dashboard_id.is_active' => 1,
1a23f3fd 96 'dashboard_id.domain_id' => CRM_Core_Config::domainID(),
be2fb01f
CW
97 'options' => ['sort' => 'weight', 'limit' => 0],
98 'return' => [
dd3770bc
CW
99 'id',
100 'weight',
101 'column_no',
dd3770bc
CW
102 'dashboard_id',
103 'dashboard_id.name',
104 'dashboard_id.label',
105 'dashboard_id.url',
106 'dashboard_id.fullscreen_url',
a8f56d71 107 'dashboard_id.cache_minutes',
dd3770bc
CW
108 'dashboard_id.permission',
109 'dashboard_id.permission_operator',
be2fb01f
CW
110 ],
111 ]);
5f3f6ec3 112
94864a5f 113 foreach ($results['values'] as $item) {
dd3770bc 114 if (self::checkPermission(CRM_Utils_Array::value('dashboard_id.permission', $item), CRM_Utils_Array::value('dashboard_id.permission_operator', $item))) {
be2fb01f 115 $dashlets[$item['id']] = [
dd3770bc
CW
116 'dashboard_id' => $item['dashboard_id'],
117 'weight' => $item['weight'],
118 'column_no' => $item['column_no'],
dd3770bc
CW
119 'name' => $item['dashboard_id.name'],
120 'label' => $item['dashboard_id.label'],
121 'url' => $item['dashboard_id.url'],
a8f56d71 122 'cache_minutes' => $item['dashboard_id.cache_minutes'],
6b409353 123 'fullscreen_url' => $item['dashboard_id.fullscreen_url'] ?? NULL,
be2fb01f 124 ];
6a488035
TO
125 }
126 }
127
dd3770bc 128 // If empty, then initialize default dashlets for this user.
94864a5f 129 if (!$results['count']) {
dd3770bc 130 // They may just have disabled all their dashlets. Check if any records exist for this contact.
1a23f3fd 131 if (!civicrm_api3('DashboardContact', 'getcount', ['contact_id' => $contactID, 'dashboard_id.domain_id' => CRM_Core_Config::domainID()])) {
dd3770bc
CW
132 $dashlets = self::initializeDashlets();
133 }
5aa910d4 134 }
94864a5f 135
5aa910d4 136 return $dashlets;
15d9b3ae
N
137 }
138
242055d3
CW
139 /**
140 * @return array
141 */
dd3770bc 142 public static function getContactDashletsForJS() {
be2fb01f 143 $data = [[], []];
dd3770bc 144 foreach (self::getContactDashlets() as $item) {
be2fb01f 145 $data[$item['column_no']][] = [
dd3770bc 146 'id' => (int) $item['dashboard_id'],
dd3770bc
CW
147 'name' => $item['name'],
148 'title' => $item['label'],
149 'url' => self::parseUrl($item['url']),
a8f56d71 150 'cacheMinutes' => $item['cache_minutes'],
dd3770bc 151 'fullscreenUrl' => self::parseUrl($item['fullscreen_url']),
be2fb01f 152 ];
dd3770bc
CW
153 }
154 return $data;
155 }
156
b5c2afd0 157 /**
fe482240 158 * Setup default dashlets for new users.
b5c2afd0 159 *
5aa910d4
JM
160 * When a user accesses their dashboard for the first time, set up
161 * the default dashlets.
162 *
a6c01b45 163 * @return array
518fa0ee 164 * Array of dashboard_id's
ad37ac8e 165 * @throws \CiviCRM_API3_Exception
b5c2afd0 166 */
94864a5f 167 public static function initializeDashlets() {
be2fb01f
CW
168 $dashlets = [];
169 $getDashlets = civicrm_api3("Dashboard", "get", [
cf9ccf98
TO
170 'domain_id' => CRM_Core_Config::domainID(),
171 'option.limit' => 0,
172 ]);
3bdcd4ec 173 $contactID = CRM_Core_Session::getLoggedInContactID();
be2fb01f
CW
174 $allDashlets = CRM_Utils_Array::index(['name'], $getDashlets['values']);
175 $defaultDashlets = [];
176 $defaults = ['blog' => 1, 'getting-started' => '0'];
c202dd9e 177 foreach ($defaults as $name => $column) {
fbd19c80 178 if (!empty($allDashlets[$name]) && !empty($allDashlets[$name]['id'])) {
be2fb01f 179 $defaultDashlets[$name] = [
40c0dd53 180 'dashboard_id' => $allDashlets[$name]['id'],
181 'is_active' => 1,
182 'column_no' => $column,
183 'contact_id' => $contactID,
be2fb01f 184 ];
40c0dd53 185 }
15d9b3ae
N
186 }
187 CRM_Utils_Hook::dashboard_defaults($allDashlets, $defaultDashlets);
188 if (is_array($defaultDashlets) && !empty($defaultDashlets)) {
5aa910d4
JM
189 foreach ($defaultDashlets as $id => $defaultDashlet) {
190 $dashboard_id = $defaultDashlet['dashboard_id'];
dd3770bc
CW
191 $dashlet = $getDashlets['values'][$dashboard_id];
192 if (!self::checkPermission(CRM_Utils_Array::value('permission', $dashlet), CRM_Utils_Array::value('permission_operator', $dashlet))) {
15d9b3ae
N
193 continue;
194 }
195 else {
196 $assignDashlets = civicrm_api3("dashboard_contact", "create", $defaultDashlet);
94864a5f 197 $values = $assignDashlets['values'][$assignDashlets['id']];
be2fb01f 198 $dashlets[$assignDashlets['id']] = [
dd3770bc
CW
199 'dashboard_id' => $values['dashboard_id'],
200 'weight' => $values['weight'],
201 'column_no' => $values['column_no'],
dd3770bc
CW
202 'name' => $dashlet['name'],
203 'label' => $dashlet['label'],
a8f56d71 204 'cache_minutes' => $dashlet['cache_minutes'],
dd3770bc 205 'url' => $dashlet['url'],
6b409353 206 'fullscreen_url' => $dashlet['fullscreen_url'] ?? NULL,
be2fb01f 207 ];
6a488035 208 }
6a488035
TO
209 }
210 }
5aa910d4 211 return $dashlets;
6a488035 212 }
08727453 213
dd3770bc
CW
214 /**
215 * @param $url
216 * @return string
217 */
218 public static function parseUrl($url) {
8f6fefed 219 // Check if it is already a fully-formed url
7ec4b96d 220 if ($url && substr($url, 0, 4) != 'http' && $url[0] != '/') {
dd3770bc 221 $urlParam = explode('?', $url);
8f6fefed 222 $url = CRM_Utils_System::url($urlParam[0], CRM_Utils_Array::value(1, $urlParam), FALSE, NULL, FALSE);
dd3770bc
CW
223 }
224 return $url;
225 }
6a488035
TO
226
227 /**
fe482240 228 * Check dashlet permission for current user.
6a488035 229 *
6a0b768e
TO
230 * @param string $permission
231 * Comma separated list.
c490a46a 232 * @param string $operator
6a488035 233 *
408b79bf 234 * @return bool
a6c01b45 235 * true if use has permission else false
6a488035 236 */
00be9182 237 public static function checkPermission($permission, $operator) {
6a488035
TO
238 if ($permission) {
239 $permissions = explode(',', $permission);
240 $config = CRM_Core_Config::singleton();
241
242 static $allComponents;
243 if (!$allComponents) {
244 $allComponents = CRM_Core_Component::getNames();
245 }
246
247 $hasPermission = FALSE;
248 foreach ($permissions as $key) {
249 $showDashlet = TRUE;
250
251 $componentName = NULL;
252 if (strpos($key, 'access') === 0) {
253 $componentName = trim(substr($key, 6));
254 if (!in_array($componentName, $allComponents)) {
255 $componentName = NULL;
256 }
257 }
258
259 // hack to handle case permissions
cf9ccf98
TO
260 if (!$componentName
261 && in_array($key, ['access my cases and activities', 'access all cases and activities'])
353ffa53 262 ) {
6a488035
TO
263 $componentName = 'CiviCase';
264 }
265
266 //hack to determine if it's a component related permission
267 if ($componentName) {
268 if (!in_array($componentName, $config->enableComponents) ||
269 !CRM_Core_Permission::check($key)
270 ) {
271 $showDashlet = FALSE;
272 if ($operator == 'AND') {
273 return $showDashlet;
274 }
275 }
276 else {
277 $hasPermission = TRUE;
278 }
279 }
280 elseif (!CRM_Core_Permission::check($key)) {
281 $showDashlet = FALSE;
282 if ($operator == 'AND') {
283 return $showDashlet;
284 }
285 }
286 else {
287 $hasPermission = TRUE;
288 }
289 }
290
291 if (!$showDashlet && !$hasPermission) {
292 return FALSE;
293 }
294 else {
295 return TRUE;
296 }
297 }
298 else {
299 // if permission is not set consider everyone has permission to access it.
300 return TRUE;
301 }
302 }
303
304 /**
242055d3 305 * Save changes made by user to the Dashlet.
6a488035 306 *
6a0b768e 307 * @param array $columns
6a488035 308 *
100fef9d 309 * @param int $contactID
77b97be7
EM
310 *
311 * @throws RuntimeException
6a488035 312 */
2aa397bc 313 public static function saveDashletChanges($columns, $contactID = NULL) {
15d9b3ae 314 if (!$contactID) {
ce2cc43e 315 $contactID = CRM_Core_Session::getLoggedInContactID();
15d9b3ae
N
316 }
317
f583d89b
TO
318 if (empty($contactID)) {
319 throw new RuntimeException("Failed to determine contact ID");
320 }
6a488035 321
be2fb01f 322 $dashletIDs = [];
6a488035
TO
323 if (is_array($columns)) {
324 foreach ($columns as $colNo => $dashlets) {
408b79bf 325 if (!is_int($colNo)) {
6a488035
TO
326 continue;
327 }
328 $weight = 1;
329 foreach ($dashlets as $dashletID => $isMinimized) {
00c27b41
CW
330 $dashletID = (int) $dashletID;
331 $query = "INSERT INTO civicrm_dashboard_contact
242055d3
CW
332 (weight, column_no, is_active, dashboard_id, contact_id)
333 VALUES({$weight}, {$colNo}, 1, {$dashletID}, {$contactID})
334 ON DUPLICATE KEY UPDATE weight = {$weight}, column_no = {$colNo}, is_active = 1";
6a488035 335 // fire update query for each column
00c27b41 336 CRM_Core_DAO::executeQuery($query);
6a488035
TO
337
338 $dashletIDs[] = $dashletID;
339 $weight++;
340 }
341 }
342 }
343
d3eb2e98
CW
344 // Find dashlets in this domain.
345 $domainDashlets = civicrm_api3('Dashboard', 'get', [
346 'return' => array('id'),
347 'domain_id' => CRM_Core_Config::domainID(),
cbf61ce3 348 'options' => ['limit' => 0],
d3eb2e98
CW
349 ]);
350
351 // Get the array of IDs.
352 $domainDashletIDs = [];
353 if ($domainDashlets['is_error'] == 0) {
4020bce8 354 $domainDashletIDs = CRM_Utils_Array::collect('id', $domainDashlets['values']);
d3eb2e98
CW
355 }
356
357 // Restrict query to Dashlets in this domain.
358 $domainDashletClause = !empty($domainDashletIDs) ? "dashboard_id IN (" . implode(',', $domainDashletIDs) . ")" : '(1)';
359
c0543d08
CW
360 // Target only those Dashlets which are inactive.
361 $dashletClause = $dashletIDs ? "dashboard_id NOT IN (" . implode(',', $dashletIDs) . ")" : '(1)';
362
363 // Build params.
364 $params = [
365 1 => [$contactID, 'Integer'],
366 ];
367
368 // Build query.
00c27b41
CW
369 $updateQuery = "UPDATE civicrm_dashboard_contact
370 SET is_active = 0
d3eb2e98
CW
371 WHERE $domainDashletClause
372 AND $dashletClause
c0543d08 373 AND contact_id = %1";
6a488035 374
c0543d08
CW
375 // Disable inactive widgets.
376 CRM_Core_DAO::executeQuery($updateQuery, $params);
6a488035
TO
377 }
378
379 /**
fe482240 380 * Add dashlets.
6a488035 381 *
6a0b768e 382 * @param array $params
6a488035 383 *
a6c01b45
CW
384 * @return object
385 * $dashlet returns dashlet object
6a488035 386 */
00be9182 387 public static function addDashlet(&$params) {
6a488035 388
32c93376 389 // special case to handle duplicate entries for report instances
9c1bc317 390 $dashboardID = $params['id'] ?? NULL;
15d9b3ae 391
a7488080 392 if (!empty($params['instanceURL'])) {
6a488035
TO
393 $query = "SELECT id
394 FROM `civicrm_dashboard`
395 WHERE url LIKE '" . CRM_Utils_Array::value('instanceURL', $params) . "&%'";
396 $dashboardID = CRM_Core_DAO::singleValueQuery($query);
397 }
398
399 $dashlet = new CRM_Core_DAO_Dashboard();
400
401 if (!$dashboardID) {
1a23f3fd
CW
402
403 // Assign domain before search to allow identical dashlets in different domains.
404 if (empty($params['domain_id'])) {
405 $dashlet->domain_id = CRM_Core_Config::domainID();
406 }
420019a6 407 else {
9c1bc317 408 $dashlet->domain_id = $params['domain_id'] ?? NULL;
420019a6 409 }
1a23f3fd
CW
410
411 // Try and find an existing dashlet - it will be updated if found.
a7488080 412 if (!empty($params['name'])) {
9c1bc317 413 $dashlet->name = $params['name'] ?? NULL;
15d9b3ae
N
414 $dashlet->find(TRUE);
415 }
416 else {
9c1bc317 417 $dashlet->url = $params['url'] ?? NULL;
15d9b3ae
N
418 $dashlet->find(TRUE);
419 }
1a23f3fd 420
6a488035
TO
421 }
422 else {
423 $dashlet->id = $dashboardID;
424 }
425
6a488035 426 $dashlet->copyValues($params);
6a488035
TO
427 $dashlet->save();
428
429 // now we need to make dashlet entries for each contact
430 self::addContactDashlet($dashlet);
431
432 return $dashlet;
433 }
434
435 /**
fe482240 436 * Update contact dashboard with new dashlet.
6a488035 437 *
192d36c5 438 * @param object $dashlet
6a488035 439 */
00be9182 440 public static function addContactDashlet($dashlet) {
6a488035
TO
441 $admin = CRM_Core_Permission::check('administer CiviCRM');
442
443 // if dashlet is created by admin then you need to add it all contacts.
444 // else just add to contact who is creating this dashlet
be2fb01f 445 $contactIDs = [];
6a488035
TO
446 if ($admin) {
447 $query = "SELECT distinct( contact_id )
a3138c9e 448 FROM civicrm_dashboard_contact";
6a488035
TO
449 $dao = CRM_Core_DAO::executeQuery($query);
450 while ($dao->fetch()) {
a3138c9e 451 $contactIDs[$dao->contact_id] = NULL;
6a488035
TO
452 }
453 }
454 else {
455 //Get the id of Logged in User
df099613 456 $contactID = CRM_Core_Session::getLoggedInContactID();
22e263ad 457 if (!empty($contactID)) {
a3138c9e 458 $contactIDs[$contactID] = NULL;
155a0ed0 459 }
6a488035
TO
460 }
461
a3138c9e
JM
462 // Remove contact ids that already have this dashlet to avoid DB
463 // constraint violation.
464 $query = "SELECT distinct( contact_id )
465 FROM civicrm_dashboard_contact WHERE dashboard_id = {$dashlet->id}";
466 $dao = CRM_Core_DAO::executeQuery($query);
a3138c9e 467 while ($dao->fetch()) {
cc4988ae 468 if (array_key_exists($dao->contact_id, $contactIDs)) {
a3138c9e
JM
469 unset($contactIDs[$dao->contact_id]);
470 }
471 }
6a488035 472 if (!empty($contactIDs)) {
a3138c9e 473 foreach ($contactIDs as $contactID => $value) {
6a488035
TO
474 $valuesArray[] = " ( {$dashlet->id}, {$contactID} )";
475 }
6a488035
TO
476 $valuesString = implode(',', $valuesArray);
477 $query = "
478 INSERT INTO civicrm_dashboard_contact ( dashboard_id, contact_id )
479 VALUES {$valuesString}";
480
481 CRM_Core_DAO::executeQuery($query);
482 }
483 }
484
dcf56200 485 /**
6a0b768e
TO
486 * @param array $params
487 * Each item is a spec for a dashlet on the contact's dashboard.
dcf56200
TO
488 * @return bool
489 */
00be9182 490 public static function addContactDashletToDashboard(&$params) {
15d9b3ae 491 $valuesString = NULL;
be2fb01f 492 $columns = [];
15d9b3ae 493 foreach ($params as $dashboardIDs) {
9c1bc317
CW
494 $contactID = $dashboardIDs['contact_id'] ?? NULL;
495 $dashboardID = $dashboardIDs['dashboard_id'] ?? NULL;
2975f0aa 496 $column = $dashboardIDs['column_no'] ?? 0;
15d9b3ae
N
497 $columns[$column][$dashboardID] = 0;
498 }
499 self::saveDashletChanges($columns, $contactID);
500 return TRUE;
501 }
502
6a488035 503 /**
fe482240 504 * Delete Dashlet.
6a488035 505 *
100fef9d 506 * @param int $dashletID
2a6da8d7 507 *
192d36c5 508 * @return bool
6a488035 509 */
00be9182 510 public static function deleteDashlet($dashletID) {
6a488035
TO
511 $dashlet = new CRM_Core_DAO_Dashboard();
512 $dashlet->id = $dashletID;
a60c0bc8
SL
513 if (!$dashlet->find(TRUE)) {
514 return FALSE;
515 }
6a488035 516 $dashlet->delete();
15d9b3ae 517 return TRUE;
6a488035 518 }
96025800 519
6a488035 520}