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