]> git.mxchange.org Git - friendica.git/blob - src/Model/Group.php
Merge pull request #8063 from MrPetovan/bug/8058-use-default-user-acl-events
[friendica.git] / src / Model / Group.php
1 <?php
2 /**
3  * @file src/Model/Group.php
4  */
5
6 namespace Friendica\Model;
7
8 use Friendica\BaseModule;
9 use Friendica\Core\L10n;
10 use Friendica\Core\Logger;
11 use Friendica\Core\Protocol;
12 use Friendica\Core\Renderer;
13 use Friendica\Database\DBA;
14
15 /**
16  * @brief functions for interacting with the group database table
17  */
18 class Group
19 {
20         const FOLLOWERS = '~';
21         const MUTUALS = '&';
22
23         public static function getByUserId($uid, $includesDeleted = false)
24         {
25                 $conditions = ['uid' => $uid];
26
27                 if (!$includesDeleted) {
28                         $conditions['deleted'] = false;
29                 }
30
31                 return DBA::selectToArray('group', [], $conditions);
32         }
33
34         /**
35          * @param int $group_id
36          * @return bool
37          * @throws \Exception
38          */
39         public static function exists($group_id, $uid = null)
40         {
41                 $condition = ['id' => $group_id, 'deleted' => false];
42
43                 if (isset($uid)) {
44                         $condition = [
45                                 'uid' => $uid
46                         ];
47                 }
48
49                 return DBA::exists('group', $condition);
50         }
51
52         /**
53          * @brief Create a new contact group
54          *
55          * Note: If we found a deleted group with the same name, we restore it
56          *
57          * @param int    $uid
58          * @param string $name
59          * @return boolean
60          * @throws \Exception
61          */
62         public static function create($uid, $name)
63         {
64                 $return = false;
65                 if (!empty($uid) && !empty($name)) {
66                         $gid = self::getIdByName($uid, $name); // check for dupes
67                         if ($gid !== false) {
68                                 // This could be a problem.
69                                 // Let's assume we've just created a group which we once deleted
70                                 // all the old members are gone, but the group remains so we don't break any security
71                                 // access lists. What we're doing here is reviving the dead group, but old content which
72                                 // was restricted to this group may now be seen by the new group members.
73                                 $group = DBA::selectFirst('group', ['deleted'], ['id' => $gid]);
74                                 if (DBA::isResult($group) && $group['deleted']) {
75                                         DBA::update('group', ['deleted' => 0], ['id' => $gid]);
76                                         notice(L10n::t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
77                                 }
78                                 return true;
79                         }
80
81                         $return = DBA::insert('group', ['uid' => $uid, 'name' => $name]);
82                         if ($return) {
83                                 $return = DBA::lastInsertId();
84                         }
85                 }
86                 return $return;
87         }
88
89         /**
90          * Update group information.
91          *
92          * @param int    $id   Group ID
93          * @param string $name Group name
94          *
95          * @return bool Was the update successful?
96          * @throws \Exception
97          */
98         public static function update($id, $name)
99         {
100                 return DBA::update('group', ['name' => $name], ['id' => $id]);
101         }
102
103         /**
104          * @brief Get a list of group ids a contact belongs to
105          *
106          * @param int $cid
107          * @return array
108          * @throws \Exception
109          */
110         public static function getIdsByContactId($cid)
111         {
112                 $return = [];
113
114                 $stmt = DBA::select('group_member', ['gid'], ['contact-id' => $cid]);
115                 while ($group = DBA::fetch($stmt)) {
116                         $return[] = $group['gid'];
117                 }
118                 DBA::close($stmt);
119
120                 return $return;
121         }
122
123         /**
124          * @brief count unread group items
125          *
126          * Count unread items of each groups of the local user
127          *
128          * @return array
129          *    'id' => group id
130          *    'name' => group name
131          *    'count' => counted unseen group items
132          * @throws \Exception
133          */
134         public static function countUnseen()
135         {
136                 $stmt = DBA::p("SELECT `group`.`id`, `group`.`name`,
137                                 (SELECT COUNT(*) FROM `item` FORCE INDEX (`uid_unseen_contactid`)
138                                         WHERE `uid` = ?
139                                         AND `unseen`
140                                         AND `contact-id` IN
141                                                 (SELECT `contact-id`
142                                                 FROM `group_member`
143                                                 WHERE `group_member`.`gid` = `group`.`id`)
144                                         ) AS `count`
145                                 FROM `group`
146                                 WHERE `group`.`uid` = ?;",
147                         local_user(),
148                         local_user()
149                 );
150
151                 return DBA::toArray($stmt);
152         }
153
154         /**
155          * @brief Get the group id for a user/name couple
156          *
157          * Returns false if no group has been found.
158          *
159          * @param int    $uid
160          * @param string $name
161          * @return int|boolean
162          * @throws \Exception
163          */
164         public static function getIdByName($uid, $name)
165         {
166                 if (!$uid || !strlen($name)) {
167                         return false;
168                 }
169
170                 $group = DBA::selectFirst('group', ['id'], ['uid' => $uid, 'name' => $name]);
171                 if (DBA::isResult($group)) {
172                         return $group['id'];
173                 }
174
175                 return false;
176         }
177
178         /**
179          * @brief Mark a group as deleted
180          *
181          * @param int $gid
182          * @return boolean
183          * @throws \Exception
184          */
185         public static function remove($gid)
186         {
187                 if (!$gid) {
188                         return false;
189                 }
190
191                 $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]);
192                 if (!DBA::isResult($group)) {
193                         return false;
194                 }
195
196                 // remove group from default posting lists
197                 $user = DBA::selectFirst('user', ['def_gid', 'allow_gid', 'deny_gid'], ['uid' => $group['uid']]);
198                 if (DBA::isResult($user)) {
199                         $change = false;
200
201                         if ($user['def_gid'] == $gid) {
202                                 $user['def_gid'] = 0;
203                                 $change = true;
204                         }
205                         if (strpos($user['allow_gid'], '<' . $gid . '>') !== false) {
206                                 $user['allow_gid'] = str_replace('<' . $gid . '>', '', $user['allow_gid']);
207                                 $change = true;
208                         }
209                         if (strpos($user['deny_gid'], '<' . $gid . '>') !== false) {
210                                 $user['deny_gid'] = str_replace('<' . $gid . '>', '', $user['deny_gid']);
211                                 $change = true;
212                         }
213
214                         if ($change) {
215                                 DBA::update('user', $user, ['uid' => $group['uid']]);
216                         }
217                 }
218
219                 // remove all members
220                 DBA::delete('group_member', ['gid' => $gid]);
221
222                 // remove group
223                 $return = DBA::update('group', ['deleted' => 1], ['id' => $gid]);
224
225                 return $return;
226         }
227
228         /**
229          * @brief      Mark a group as deleted based on its name
230          *
231          * @param int    $uid
232          * @param string $name
233          * @return bool
234          * @throws \Exception
235          * @deprecated Use Group::remove instead
236          *
237          */
238         public static function removeByName($uid, $name)
239         {
240                 $return = false;
241                 if (!empty($uid) && !empty($name)) {
242                         $gid = self::getIdByName($uid, $name);
243
244                         $return = self::remove($gid);
245                 }
246
247                 return $return;
248         }
249
250         /**
251          * @brief Adds a contact to a group
252          *
253          * @param int $gid
254          * @param int $cid
255          * @return boolean
256          * @throws \Exception
257          */
258         public static function addMember($gid, $cid)
259         {
260                 if (!$gid || !$cid) {
261                         return false;
262                 }
263
264                 $row_exists = DBA::exists('group_member', ['gid' => $gid, 'contact-id' => $cid]);
265                 if ($row_exists) {
266                         // Row already existing, nothing to do
267                         $return = true;
268                 } else {
269                         $return = DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $cid]);
270                 }
271
272                 return $return;
273         }
274
275         /**
276          * @brief Removes a contact from a group
277          *
278          * @param int $gid
279          * @param int $cid
280          * @return boolean
281          * @throws \Exception
282          */
283         public static function removeMember($gid, $cid)
284         {
285                 if (!$gid || !$cid) {
286                         return false;
287                 }
288
289                 $return = DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $cid]);
290
291                 return $return;
292         }
293
294         /**
295          * @brief      Removes a contact from a group based on its name
296          *
297          * @param int    $uid
298          * @param string $name
299          * @param int    $cid
300          * @return boolean
301          * @throws \Exception
302          * @deprecated Use Group::removeMember instead
303          *
304          */
305         public static function removeMemberByName($uid, $name, $cid)
306         {
307                 $gid = self::getIdByName($uid, $name);
308
309                 $return = self::removeMember($gid, $cid);
310
311                 return $return;
312         }
313
314         /**
315          * @brief Returns the combined list of contact ids from a group id list
316          *
317          * @param int     $uid
318          * @param array   $group_ids
319          * @param boolean $check_dead
320          * @return array
321          * @throws \Exception
322          */
323         public static function expand($uid, array $group_ids, $check_dead = false)
324         {
325                 if (!is_array($group_ids) || !count($group_ids)) {
326                         return [];
327                 }
328
329                 $return = [];
330                 $pubmail = false;
331                 $networks = Protocol::SUPPORT_PRIVATE;
332
333                 $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', $uid]);
334                 if (DBA::isResult($mailacct)) {
335                         $pubmail = $mailacct['pubmail'];
336                 }
337
338                 if (!$pubmail) {
339                         $networks = array_diff($networks, [Protocol::MAIL]);
340                 }
341
342                 $key = array_search(self::FOLLOWERS, $group_ids);
343                 if ($key !== false) {
344                         $followers = Contact::selectToArray(['id'], [
345                                 'uid' => $uid,
346                                 'rel' => [Contact::FOLLOWER, Contact::FRIEND],
347                                 'network' => $networks,
348                                 'contact-type' => [Contact::TYPE_UNKNOWN, Contact::TYPE_PERSON],
349                                 'archive' => false,
350                                 'pending' => false,
351                                 'blocked' => false,
352                         ]);
353
354                         foreach ($followers as $follower) {
355                                 $return[] = $follower['id'];
356                         }
357
358                         unset($group_ids[$key]);
359                 }
360
361                 $key = array_search(self::MUTUALS, $group_ids);
362                 if ($key !== false) {
363                         $mutuals = Contact::selectToArray(['id'], [
364                                 'uid' => $uid,
365                                 'rel' => [Contact::FRIEND],
366                                 'network' => $networks,
367                                 'contact-type' => [Contact::TYPE_UNKNOWN, Contact::TYPE_PERSON],
368                                 'archive' => false,
369                                 'pending' => false,
370                                 'blocked' => false,
371                         ]);
372
373                         foreach ($mutuals as $mutual) {
374                                 $return[] = $mutual['id'];
375                         }
376
377                         unset($group_ids[$key]);
378                 }
379
380                 $stmt = DBA::select('group_member', ['contact-id'], ['gid' => $group_ids]);
381                 while ($group_member = DBA::fetch($stmt)) {
382                         $return[] = $group_member['contact-id'];
383                 }
384                 DBA::close($stmt);
385
386                 if ($check_dead) {
387                         $return = Contact::pruneUnavailable($return);
388                 }
389
390                 return $return;
391         }
392
393         /**
394          * @brief Returns a templated group selection list
395          *
396          * @param int    $uid
397          * @param int    $gid   An optional pre-selected group
398          * @param string $label An optional label of the list
399          * @return string
400          * @throws \Exception
401          */
402         public static function displayGroupSelection($uid, $gid = 0, $label = '')
403         {
404                 $display_groups = [
405                         [
406                                 'name' => '',
407                                 'id' => '0',
408                                 'selected' => ''
409                         ]
410                 ];
411
412                 $stmt = DBA::select('group', [], ['deleted' => 0, 'uid' => $uid], ['order' => ['name']]);
413                 while ($group = DBA::fetch($stmt)) {
414                         $display_groups[] = [
415                                 'name' => $group['name'],
416                                 'id' => $group['id'],
417                                 'selected' => $gid == $group['id'] ? 'true' : ''
418                         ];
419                 }
420                 DBA::close($stmt);
421
422                 Logger::info('Got groups', $display_groups);
423
424                 if ($label == '') {
425                         $label = L10n::t('Default privacy group for new contacts');
426                 }
427
428                 $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('group_selection.tpl'), [
429                         '$label' => $label,
430                         '$groups' => $display_groups
431                 ]);
432                 return $o;
433         }
434
435         /**
436          * @brief Create group sidebar widget
437          *
438          * @param string $every
439          * @param string $each
440          * @param string $editmode
441          *    'standard' => include link 'Edit groups'
442          *    'extended' => include link 'Create new group'
443          *    'full' => include link 'Create new group' and provide for each group a link to edit this group
444          * @param string $group_id
445          * @param int    $cid
446          * @return string
447          * @throws \Exception
448          */
449         public static function sidebarWidget($every = 'contact', $each = 'group', $editmode = 'standard', $group_id = '', $cid = 0)
450         {
451                 if (!local_user()) {
452                         return '';
453                 }
454
455                 $display_groups = [
456                         [
457                                 'text' => L10n::t('Everybody'),
458                                 'id' => 0,
459                                 'selected' => (($group_id === 'everyone') ? 'group-selected' : ''),
460                                 'href' => $every,
461                         ]
462                 ];
463
464                 $member_of = [];
465                 if ($cid) {
466                         $member_of = self::getIdsByContactId($cid);
467                 }
468
469                 $stmt = DBA::select('group', [], ['deleted' => 0, 'uid' => local_user()], ['order' => ['name']]);
470                 while ($group = DBA::fetch($stmt)) {
471                         $selected = (($group_id == $group['id']) ? ' group-selected' : '');
472
473                         if ($editmode == 'full') {
474                                 $groupedit = [
475                                         'href' => 'group/' . $group['id'],
476                                         'title' => L10n::t('edit'),
477                                 ];
478                         } else {
479                                 $groupedit = null;
480                         }
481
482                         $display_groups[] = [
483                                 'id'   => $group['id'],
484                                 'cid'  => $cid,
485                                 'text' => $group['name'],
486                                 'href' => $each . '/' . $group['id'],
487                                 'edit' => $groupedit,
488                                 'selected' => $selected,
489                                 'ismember' => in_array($group['id'], $member_of),
490                         ];
491                 }
492                 DBA::close($stmt);
493
494                 // Don't show the groups on the network page when there is only one
495                 if ((count($display_groups) <= 2) && ($each == 'network')) {
496                         return '';
497                 }
498
499                 $tpl = Renderer::getMarkupTemplate('group_side.tpl');
500                 $o = Renderer::replaceMacros($tpl, [
501                         '$add' => L10n::t('add'),
502                         '$title' => L10n::t('Groups'),
503                         '$groups' => $display_groups,
504                         'newgroup' => $editmode == 'extended' || $editmode == 'full' ? 1 : '',
505                         'grouppage' => 'group/',
506                         '$edittext' => L10n::t('Edit group'),
507                         '$ungrouped' => $every === 'contact' ? L10n::t('Contacts not in any group') : '',
508                         '$ungrouped_selected' => (($group_id === 'none') ? 'group-selected' : ''),
509                         '$createtext' => L10n::t('Create a new group'),
510                         '$creategroup' => L10n::t('Group Name: '),
511                         '$editgroupstext' => L10n::t('Edit groups'),
512                         '$form_security_token' => BaseModule::getFormSecurityToken('group_edit'),
513                 ]);
514
515                 return $o;
516         }
517 }