Commit | Line | Data |
---|---|---|
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 | 18 | use Civi\Api4\DashboardContact; |
19 | ||
6a488035 | 20 | /** |
192d36c5 | 21 | * Class contains Contact dashboard related functions. |
6a488035 TO |
22 | */ |
23 | class 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 | } |