Merge pull request #23211 from eileenmcnaughton/event1
[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
3106b838 18use Civi\Api4\DashboardContact;
19
6a488035 20/**
192d36c5 21 * Class contains Contact dashboard related functions.
6a488035
TO
22 */
23class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
518fa0ee 24
3cfa8e5e 25 /**
f263929f 26 * Create or update Dashboard.
3cfa8e5e 27 *
6a0b768e 28 * @param array $params
3cfa8e5e 29 *
f263929f 30 * @return CRM_Core_DAO_Dashboard
3cfa8e5e 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 /**
f263929f 41 * Get all available contact dashlets
77b97be7 42 *
a6c01b45
CW
43 * @return array
44 * array of dashlets
3106b838 45 * @throws \API_Exception
6a488035 46 */
3106b838 47 public static function getContactDashlets(): array {
0070596d
CW
48 $cid = CRM_Core_Session::getLoggedInContactID();
49 if ($cid && !isset(Civi::$statics[__CLASS__][__FUNCTION__][$cid])) {
50 Civi::$statics[__CLASS__][__FUNCTION__][$cid] = [];
3106b838 51 // If empty, then initialize default dashlets for this user.
52 if (0 === DashboardContact::get(FALSE)->selectRowCount()->addWhere('contact_id', '=', $cid)->execute()->count()) {
53 self::initializeDashlets();
54 }
55 $contactDashboards = (array) DashboardContact::get(FALSE)
56 ->addSelect('column_no', 'is_active', 'dashboard_id', 'weight', 'contact_id')
57 ->addWhere('contact_id', '=', $cid)
58 ->addOrderBy('weight')
59 ->execute()->indexBy('dashboard_id');
60
f263929f
CW
61 $params = [
62 'select' => ['*', 'dashboard_contact.*'],
f263929f
CW
63 'where' => [
64 ['domain_id', '=', 'current_domain'],
65 ],
f263929f 66 ];
6a488035 67
f263929f 68 // Get Dashboard + any joined DashboardContact records.
3106b838 69 $results = (array) civicrm_api4('Dashboard', 'get', $params);
f263929f 70 foreach ($results as $item) {
3106b838 71 $item['dashboard_contact.id'] = $contactDashboards[$item['id']]['id'] ?? NULL;
72 $item['dashboard_contact.contact_id'] = $contactDashboards[$item['id']]['contact_id'] ?? NULL;
73 $item['dashboard_contact.weight'] = $contactDashboards[$item['id']]['weight'] ?? NULL;
74 $item['dashboard_contact.column_no'] = $contactDashboards[$item['id']]['column_no'] ?? NULL;
75 $item['dashboard_contact.is_active'] = $contactDashboards[$item['id']]['is_active'] ?? NULL;
f263929f 76 if ($item['is_active'] && self::checkPermission($item['permission'], $item['permission_operator'])) {
0070596d 77 Civi::$statics[__CLASS__][__FUNCTION__][$cid][] = $item;
f263929f 78 }
dd3770bc 79 }
3106b838 80 usort(Civi::$statics[__CLASS__][__FUNCTION__][$cid], static function ($a, $b) {
81 // Sort by dashboard contact weight, preferring not null to null.
82 // I had hoped to do this in mysql either by
83 // 1) making the dashboard contact part of the query NOT permissioned while
84 // the parent query IS or
85 // 2) using FIELD like
86 // $params['orderBy'] = ['FIELD(id,' . implode(',', array_keys($contactDashboards)) . ')' => 'ASC'];
87 // 3) or making the dashboard contact acl more inclusive such that 'view own contact'
88 // is not required to view own contact's acl
89 // but I couldn't see a way to make any of the above work. Perhaps improve in master?
90 if (!isset($b['dashboard_contact.weight']) && !isset($a[$b['dashboard_contact.weight']])) {
91 return 0;
92 }
93 if (!isset($b['dashboard_contact.weight'])) {
94 return -1;
95 }
96 if (!isset($a['dashboard_contact.weight'])) {
97 return 1;
98 }
11d593ed 99 return $a['dashboard_contact.weight'] <=> $b['dashboard_contact.weight'];
3106b838 100 });
5aa910d4 101 }
0070596d 102 return Civi::$statics[__CLASS__][__FUNCTION__][$cid] ?? [];
15d9b3ae
N
103 }
104
242055d3 105 /**
f263929f 106 * Set default dashlets for new users.
5aa910d4 107 *
f263929f 108 * Called when a user accesses their dashboard for the first time.
b5c2afd0 109 */
94864a5f 110 public static function initializeDashlets() {
f263929f
CW
111 $allDashlets = (array) civicrm_api4('Dashboard', 'get', [
112 'where' => [['domain_id', '=', 'current_domain']],
113 ], 'name');
be2fb01f
CW
114 $defaultDashlets = [];
115 $defaults = ['blog' => 1, 'getting-started' => '0'];
c202dd9e 116 foreach ($defaults as $name => $column) {
fbd19c80 117 if (!empty($allDashlets[$name]) && !empty($allDashlets[$name]['id'])) {
be2fb01f 118 $defaultDashlets[$name] = [
40c0dd53 119 'dashboard_id' => $allDashlets[$name]['id'],
120 'is_active' => 1,
121 'column_no' => $column,
be2fb01f 122 ];
40c0dd53 123 }
15d9b3ae
N
124 }
125 CRM_Utils_Hook::dashboard_defaults($allDashlets, $defaultDashlets);
126 if (is_array($defaultDashlets) && !empty($defaultDashlets)) {
3106b838 127 DashboardContact::save(FALSE)
f263929f
CW
128 ->setRecords($defaultDashlets)
129 ->setDefaults(['contact_id' => CRM_Core_Session::getLoggedInContactID()])
130 ->execute();
6a488035 131 }
dd3770bc 132 }
6a488035
TO
133
134 /**
fe482240 135 * Check dashlet permission for current user.
6a488035 136 *
e9a48f3f
CW
137 * @param array|null $permissions
138 * @param string|null $operator
6a488035 139 *
408b79bf 140 * @return bool
f263929f 141 * true if user has permission to view dashlet
6a488035 142 */
e9a48f3f 143 private static function checkPermission(?array $permissions, ?string $operator): bool {
f263929f 144 if ($permissions) {
6a488035
TO
145 static $allComponents;
146 if (!$allComponents) {
147 $allComponents = CRM_Core_Component::getNames();
148 }
149
150 $hasPermission = FALSE;
151 foreach ($permissions as $key) {
152 $showDashlet = TRUE;
153
e9a48f3f 154 $componentName = CRM_Core_Permission::getComponentName($key);
6a488035 155
e9a48f3f 156 // If the permission depends on a component, ensure it is enabled
6a488035 157 if ($componentName) {
e46f73c7 158 if (!CRM_Core_Component::isEnabled($componentName) || !CRM_Core_Permission::check($key)) {
6a488035
TO
159 $showDashlet = FALSE;
160 if ($operator == 'AND') {
161 return $showDashlet;
162 }
163 }
164 else {
165 $hasPermission = TRUE;
166 }
167 }
168 elseif (!CRM_Core_Permission::check($key)) {
169 $showDashlet = FALSE;
170 if ($operator == 'AND') {
171 return $showDashlet;
172 }
173 }
174 else {
175 $hasPermission = TRUE;
176 }
177 }
178
e9a48f3f 179 return $showDashlet || $hasPermission;
6a488035 180 }
e9a48f3f
CW
181 // If permission is not set consider everyone has access.
182 return TRUE;
6a488035
TO
183 }
184
6a488035 185 /**
fe482240 186 * Add dashlets.
6a488035 187 *
6a0b768e 188 * @param array $params
6a488035 189 *
a6c01b45
CW
190 * @return object
191 * $dashlet returns dashlet object
6a488035 192 */
00be9182 193 public static function addDashlet(&$params) {
6a488035 194
32c93376 195 // special case to handle duplicate entries for report instances
9c1bc317 196 $dashboardID = $params['id'] ?? NULL;
15d9b3ae 197
a7488080 198 if (!empty($params['instanceURL'])) {
6a488035
TO
199 $query = "SELECT id
200 FROM `civicrm_dashboard`
201 WHERE url LIKE '" . CRM_Utils_Array::value('instanceURL', $params) . "&%'";
202 $dashboardID = CRM_Core_DAO::singleValueQuery($query);
203 }
204
205 $dashlet = new CRM_Core_DAO_Dashboard();
206
207 if (!$dashboardID) {
1a23f3fd 208 // Assign domain before search to allow identical dashlets in different domains.
a279e546 209 $dashlet->domain_id = $params['domain_id'] ?? CRM_Core_Config::domainID();
1a23f3fd
CW
210
211 // Try and find an existing dashlet - it will be updated if found.
8f7fd744 212 if (!empty($params['name'])) {
9c1bc317 213 $dashlet->name = $params['name'] ?? NULL;
15d9b3ae
N
214 $dashlet->find(TRUE);
215 }
6a488035
TO
216 }
217 else {
218 $dashlet->id = $dashboardID;
219 }
220
6a488035 221 $dashlet->copyValues($params);
6a488035
TO
222 $dashlet->save();
223
224 // now we need to make dashlet entries for each contact
225 self::addContactDashlet($dashlet);
226
227 return $dashlet;
228 }
229
230 /**
fe482240 231 * Update contact dashboard with new dashlet.
6a488035 232 *
192d36c5 233 * @param object $dashlet
6a488035 234 */
00be9182 235 public static function addContactDashlet($dashlet) {
6a488035
TO
236 $admin = CRM_Core_Permission::check('administer CiviCRM');
237
238 // if dashlet is created by admin then you need to add it all contacts.
239 // else just add to contact who is creating this dashlet
be2fb01f 240 $contactIDs = [];
6a488035
TO
241 if ($admin) {
242 $query = "SELECT distinct( contact_id )
a3138c9e 243 FROM civicrm_dashboard_contact";
6a488035
TO
244 $dao = CRM_Core_DAO::executeQuery($query);
245 while ($dao->fetch()) {
a3138c9e 246 $contactIDs[$dao->contact_id] = NULL;
6a488035
TO
247 }
248 }
249 else {
250 //Get the id of Logged in User
df099613 251 $contactID = CRM_Core_Session::getLoggedInContactID();
22e263ad 252 if (!empty($contactID)) {
a3138c9e 253 $contactIDs[$contactID] = NULL;
155a0ed0 254 }
6a488035
TO
255 }
256
a3138c9e
JM
257 // Remove contact ids that already have this dashlet to avoid DB
258 // constraint violation.
259 $query = "SELECT distinct( contact_id )
260 FROM civicrm_dashboard_contact WHERE dashboard_id = {$dashlet->id}";
261 $dao = CRM_Core_DAO::executeQuery($query);
a3138c9e 262 while ($dao->fetch()) {
cc4988ae 263 if (array_key_exists($dao->contact_id, $contactIDs)) {
a3138c9e
JM
264 unset($contactIDs[$dao->contact_id]);
265 }
266 }
6a488035 267 if (!empty($contactIDs)) {
a3138c9e 268 foreach ($contactIDs as $contactID => $value) {
6a488035
TO
269 $valuesArray[] = " ( {$dashlet->id}, {$contactID} )";
270 }
6a488035
TO
271 $valuesString = implode(',', $valuesArray);
272 $query = "
273 INSERT INTO civicrm_dashboard_contact ( dashboard_id, contact_id )
274 VALUES {$valuesString}";
275
276 CRM_Core_DAO::executeQuery($query);
277 }
278 }
279
6a488035 280}