2017-12-09 19:31:00 +01:00
< ? php
/**
2023-01-01 15:36:24 +01:00
* @ copyright Copyright ( C ) 2010 - 2023 , the Friendica project
2020-02-09 15:45:36 +01:00
*
* @ license GNU AGPL version 3 or any later version
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*
2017-12-09 19:31:00 +01:00
*/
2019-07-28 15:39:45 +02:00
2017-12-09 19:31:00 +01:00
namespace Friendica\Model ;
2018-10-17 21:30:41 +02:00
use Friendica\BaseModule ;
2018-10-29 22:20:46 +01:00
use Friendica\Core\Logger ;
2019-07-17 02:23:19 +02:00
use Friendica\Core\Protocol ;
2018-10-31 15:35:50 +01:00
use Friendica\Core\Renderer ;
2021-11-26 15:48:37 +01:00
use Friendica\Database\Database ;
2018-07-20 14:19:26 +02:00
use Friendica\Database\DBA ;
2020-01-18 22:07:07 +01:00
use Friendica\DI ;
2021-11-26 15:48:37 +01:00
use Friendica\Network\HTTPException ;
2022-02-09 22:34:25 +01:00
use Friendica\Protocol\ActivityPub ;
2017-12-09 19:31:00 +01:00
/**
2020-01-19 07:05:23 +01:00
* functions for interacting with the group database table
2017-12-09 19:31:00 +01:00
*/
2023-05-14 01:54:35 +02:00
class Circle
2017-12-09 19:31:00 +01:00
{
2019-07-15 03:48:35 +02:00
const FOLLOWERS = '~' ;
const MUTUALS = '&' ;
2022-06-18 17:22:10 +02:00
/**
2023-05-14 01:54:35 +02:00
* Fetches circle record by user id and maybe includes deleted circles as well
2022-06-18 17:22:10 +02:00
*
2023-05-14 01:54:35 +02:00
* @ param int $uid User id to fetch circle ( s ) for
* @ param bool $includesDeleted Whether deleted circles should be included
2022-06-18 17:22:10 +02:00
* @ return array | bool Array on success , bool on error
*/
public static function getByUserId ( int $uid , bool $includesDeleted = false )
2019-07-15 03:48:35 +02:00
{
2022-02-12 19:38:36 +01:00
$conditions = [ 'uid' => $uid , 'cid' => null ];
2019-07-15 03:48:35 +02:00
if ( ! $includesDeleted ) {
$conditions [ 'deleted' ] = false ;
}
2019-07-28 15:39:45 +02:00
return DBA :: selectToArray ( 'group' , [], $conditions );
2019-07-15 03:48:35 +02:00
}
2019-02-23 21:33:55 +01:00
/**
2023-05-14 01:54:35 +02:00
* Checks whether given circle id is found in database
2022-06-18 17:22:10 +02:00
*
2023-05-14 01:54:35 +02:00
* @ param int $circle_id Circle id
2022-06-18 17:22:10 +02:00
* @ param int $uid Optional user id
2019-02-23 21:33:55 +01:00
* @ return bool
* @ throws \Exception
*/
2023-05-14 01:54:35 +02:00
public static function exists ( int $circle_id , int $uid = null ) : bool
2019-02-23 21:33:55 +01:00
{
2023-05-14 01:54:35 +02:00
$condition = [ 'id' => $circle_id , 'deleted' => false ];
2019-02-23 21:33:55 +01:00
2022-06-18 17:22:10 +02:00
if ( ! is_null ( $uid )) {
2019-02-23 21:33:55 +01:00
$condition = [
'uid' => $uid
];
}
return DBA :: exists ( 'group' , $condition );
}
2017-12-09 19:31:00 +01:00
/**
2023-05-14 01:54:35 +02:00
* Create a new contact circle
2017-12-09 19:31:00 +01:00
*
2023-05-14 01:54:35 +02:00
* Note : If we found a deleted circle with the same name , we restore it
2017-12-09 19:31:00 +01:00
*
2023-05-14 01:54:35 +02:00
* @ param int $uid User id to create circle for
* @ param string $name Name of circle
* @ return int | boolean Id of newly created circle or false on error
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2022-06-18 17:22:10 +02:00
public static function create ( int $uid , string $name )
2017-12-09 19:31:00 +01:00
{
$return = false ;
2018-11-30 15:06:22 +01:00
if ( ! empty ( $uid ) && ! empty ( $name )) {
2017-12-09 19:31:00 +01:00
$gid = self :: getIdByName ( $uid , $name ); // check for dupes
if ( $gid !== false ) {
// This could be a problem.
2023-05-14 01:54:35 +02:00
// Let's assume we've just created a circle which we once deleted
// all the old members are gone, but the circle remains, so we don't break any security
// access lists. What we're doing here is reviving the dead circle, but old content which
// was restricted to this circle may now be seen by the new circle members.
$circle = DBA :: selectFirst ( 'group' , [ 'deleted' ], [ 'id' => $gid ]);
if ( DBA :: isResult ( $circle ) && $circle [ 'deleted' ]) {
2018-07-20 14:19:26 +02:00
DBA :: update ( 'group' , [ 'deleted' => 0 ], [ 'id' => $gid ]);
2023-05-14 01:54:35 +02:00
DI :: sysmsg () -> addNotice ( DI :: l10n () -> t ( 'A deleted circle with this name was revived. Existing item permissions <strong>may</strong> apply to this circle and any future members. If this is not what you intended, please create another circle with a different name.' ));
2017-12-09 19:31:00 +01:00
}
return true ;
}
2018-07-20 14:19:26 +02:00
$return = DBA :: insert ( 'group' , [ 'uid' => $uid , 'name' => $name ]);
2017-12-13 02:52:50 +01:00
if ( $return ) {
2018-07-20 14:19:26 +02:00
$return = DBA :: lastInsertId ();
2017-12-13 02:52:50 +01:00
}
2017-12-09 19:31:00 +01:00
}
return $return ;
}
2018-04-07 15:54:26 +02:00
/**
2023-05-14 01:54:35 +02:00
* Update circle information .
2018-04-07 15:54:26 +02:00
*
2023-05-14 01:54:35 +02:00
* @ param int $id Circle ID
* @ param string $name Circle name
2018-04-07 15:54:26 +02:00
*
* @ return bool Was the update successful ?
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2018-04-07 15:54:26 +02:00
*/
2022-06-18 17:22:10 +02:00
public static function update ( int $id , string $name ) : bool
2018-04-07 15:54:26 +02:00
{
2018-07-20 14:19:26 +02:00
return DBA :: update ( 'group' , [ 'name' => $name ], [ 'id' => $id ]);
2018-04-07 15:54:26 +02:00
}
2017-12-09 19:31:00 +01:00
/**
2023-05-14 01:54:35 +02:00
* Get a list of circle ids a contact belongs to
2017-12-09 19:31:00 +01:00
*
2022-06-18 17:22:10 +02:00
* @ param int $cid Contact id
2023-05-14 01:54:35 +02:00
* @ return array Circle ids
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2022-06-18 17:22:10 +02:00
public static function getIdsByContactId ( int $cid ) : array
2017-12-09 19:31:00 +01:00
{
2022-07-25 15:13:42 +02:00
$contact = Contact :: getById ( $cid , [ 'rel' ]);
if ( ! $contact ) {
return [];
}
2023-05-14 01:54:35 +02:00
$circleIds = [];
2017-12-10 21:12:23 +01:00
2019-07-28 00:06:29 +02:00
$stmt = DBA :: select ( 'group_member' , [ 'gid' ], [ 'contact-id' => $cid ]);
2023-05-14 01:54:35 +02:00
while ( $circle = DBA :: fetch ( $stmt )) {
$circleIds [] = $circle [ 'gid' ];
2017-12-09 19:31:00 +01:00
}
2019-07-28 00:06:29 +02:00
DBA :: close ( $stmt );
2017-12-09 19:31:00 +01:00
2023-05-14 01:54:35 +02:00
// Meta-circles
2019-11-08 04:02:34 +01:00
if ( $contact [ 'rel' ] == Contact :: FOLLOWER || $contact [ 'rel' ] == Contact :: FRIEND ) {
2023-05-14 01:54:35 +02:00
$circleIds [] = self :: FOLLOWERS ;
2019-11-08 04:02:34 +01:00
}
if ( $contact [ 'rel' ] == Contact :: FRIEND ) {
2023-05-14 01:54:35 +02:00
$circleIds [] = self :: MUTUALS ;
2019-11-08 04:02:34 +01:00
}
2023-05-14 01:54:35 +02:00
return $circleIds ;
2017-12-09 19:31:00 +01:00
}
/**
2023-05-14 01:54:35 +02:00
* count unread circle items
2017-12-09 19:31:00 +01:00
*
2023-05-14 01:54:35 +02:00
* Count unread items of each circle of the local user
2017-12-09 19:31:00 +01:00
*
* @ return array
2023-05-14 01:54:35 +02:00
* 'id' => circle id
* 'name' => circle name
* 'count' => counted unseen circle items
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
public static function countUnseen ()
{
2023-05-14 01:54:35 +02:00
$stmt = DBA :: p ( " SELECT `circle`.`id`, `circle`.`name`,
2021-03-06 06:47:49 +01:00
( SELECT COUNT ( * ) FROM `post-user`
2017-12-09 19:31:00 +01:00
WHERE `uid` = ?
AND `unseen`
AND `contact-id` IN
( SELECT `contact-id`
2023-05-14 01:54:35 +02:00
FROM `group_member` AS `circle_member`
WHERE `circle_member` . `gid` = `circle` . `id` )
2017-12-09 19:31:00 +01:00
) AS `count`
2023-05-14 01:54:35 +02:00
FROM `group` AS `circle`
WHERE `circle` . `uid` = ? ; " ,
2022-10-20 22:14:50 +02:00
DI :: userSession () -> getLocalUserId (),
DI :: userSession () -> getLocalUserId ()
2017-12-09 19:31:00 +01:00
);
2018-07-21 04:03:40 +02:00
return DBA :: toArray ( $stmt );
2017-12-09 19:31:00 +01:00
}
/**
2023-05-14 01:54:35 +02:00
* Get the circle id for a user / name couple
2017-12-09 19:31:00 +01:00
*
2023-05-14 01:54:35 +02:00
* Returns false if no circle has been found .
2017-12-09 19:31:00 +01:00
*
2022-06-18 17:22:10 +02:00
* @ param int $uid User id
2023-05-14 01:54:35 +02:00
* @ param string $name Circle name
* @ return int | boolean Circle ' s id number or false on error
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2022-06-18 17:22:10 +02:00
public static function getIdByName ( int $uid , string $name )
2017-12-09 19:31:00 +01:00
{
2017-12-10 07:07:48 +01:00
if ( ! $uid || ! strlen ( $name )) {
2017-12-09 19:31:00 +01:00
return false ;
}
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'id' ], [ 'uid' => $uid , 'name' => $name ]);
if ( DBA :: isResult ( $circle )) {
return $circle [ 'id' ];
2017-12-09 19:31:00 +01:00
}
return false ;
}
/**
2023-05-14 01:54:35 +02:00
* Mark a circle as deleted
2017-12-09 19:31:00 +01:00
*
2017-12-17 21:27:50 +01:00
* @ param int $gid
2017-12-09 19:31:00 +01:00
* @ return boolean
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2022-06-18 17:22:10 +02:00
public static function remove ( int $gid ) : bool
2019-07-28 15:39:45 +02:00
{
if ( ! $gid ) {
2017-12-09 19:31:00 +01:00
return false ;
}
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'uid' ], [ 'id' => $gid ]);
if ( ! DBA :: isResult ( $circle )) {
2017-12-17 21:31:37 +01:00
return false ;
}
2023-05-14 01:54:35 +02:00
// remove circle from default posting lists
$user = DBA :: selectFirst ( 'user' , [ 'def_gid' , 'allow_gid' , 'deny_gid' ], [ 'uid' => $circle [ 'uid' ]]);
2018-07-21 14:46:04 +02:00
if ( DBA :: isResult ( $user )) {
2017-12-09 19:31:00 +01:00
$change = false ;
if ( $user [ 'def_gid' ] == $gid ) {
$user [ 'def_gid' ] = 0 ;
$change = true ;
}
if ( strpos ( $user [ 'allow_gid' ], '<' . $gid . '>' ) !== false ) {
$user [ 'allow_gid' ] = str_replace ( '<' . $gid . '>' , '' , $user [ 'allow_gid' ]);
$change = true ;
}
if ( strpos ( $user [ 'deny_gid' ], '<' . $gid . '>' ) !== false ) {
$user [ 'deny_gid' ] = str_replace ( '<' . $gid . '>' , '' , $user [ 'deny_gid' ]);
$change = true ;
}
if ( $change ) {
2023-05-14 01:54:35 +02:00
DBA :: update ( 'user' , $user , [ 'uid' => $circle [ 'uid' ]]);
2017-12-09 19:31:00 +01:00
}
}
// remove all members
2018-07-20 14:19:26 +02:00
DBA :: delete ( 'group_member' , [ 'gid' => $gid ]);
2017-12-09 19:31:00 +01:00
2023-05-14 01:54:35 +02:00
// remove circle
2018-07-20 14:19:26 +02:00
$return = DBA :: update ( 'group' , [ 'deleted' => 1 ], [ 'id' => $gid ]);
2017-12-09 19:31:00 +01:00
return $return ;
}
/**
2023-05-14 01:54:35 +02:00
* Adds a contact to a circle
2017-12-09 19:31:00 +01:00
*
* @ param int $gid
* @ param int $cid
* @ return boolean
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2021-11-26 15:48:37 +01:00
public static function addMember ( int $gid , int $cid ) : bool
2017-12-09 19:31:00 +01:00
{
2017-12-10 07:06:12 +01:00
if ( ! $gid || ! $cid ) {
2017-12-09 19:31:00 +01:00
return false ;
}
2021-11-26 15:48:37 +01:00
// @TODO Backward compatibility with user contacts, remove by version 2022.03
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'uid' ], [ 'id' => $gid ]);
if ( empty ( $circle )) {
throw new HTTPException\NotFoundException ( 'Circle not found.' );
2017-12-09 19:31:00 +01:00
}
2023-05-14 01:54:35 +02:00
$cdata = Contact :: getPublicAndUserContactID ( $cid , $circle [ 'uid' ]);
2021-11-26 15:48:37 +01:00
if ( empty ( $cdata [ 'user' ])) {
throw new HTTPException\NotFoundException ( 'Invalid contact.' );
}
return DBA :: insert ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $cdata [ 'user' ]], Database :: INSERT_IGNORE );
2017-12-09 19:31:00 +01:00
}
/**
2023-05-14 01:54:35 +02:00
* Removes a contact from a circle
2017-12-09 19:31:00 +01:00
*
* @ param int $gid
* @ param int $cid
* @ return boolean
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2021-11-26 15:48:37 +01:00
public static function removeMember ( int $gid , int $cid ) : bool
2017-12-09 19:31:00 +01:00
{
2017-12-10 07:06:12 +01:00
if ( ! $gid || ! $cid ) {
2017-12-09 19:31:00 +01:00
return false ;
}
2021-11-26 15:48:37 +01:00
// @TODO Backward compatibility with user contacts, remove by version 2022.03
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'uid' ], [ 'id' => $gid ]);
if ( empty ( $circle )) {
throw new HTTPException\NotFoundException ( 'Circle not found.' );
2021-11-26 15:48:37 +01:00
}
2017-12-09 19:31:00 +01:00
2023-05-14 01:54:35 +02:00
$cdata = Contact :: getPublicAndUserContactID ( $cid , $circle [ 'uid' ]);
2021-11-26 15:48:37 +01:00
if ( empty ( $cdata [ 'user' ])) {
throw new HTTPException\NotFoundException ( 'Invalid contact.' );
}
return DBA :: delete ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $cid ]);
2017-12-09 19:31:00 +01:00
}
2022-02-19 23:16:21 +01:00
/**
2023-05-14 01:54:35 +02:00
* Adds contacts to a circle
2022-02-19 23:16:21 +01:00
*
* @ param int $gid
2022-06-18 17:22:10 +02:00
* @ param array $contacts Array with contact ids
* @ return void
2022-02-19 23:16:21 +01:00
* @ throws \Exception
*/
public static function addMembers ( int $gid , array $contacts )
{
if ( ! $gid || ! $contacts ) {
2022-06-18 17:22:10 +02:00
return ;
2022-02-19 23:16:21 +01:00
}
// @TODO Backward compatibility with user contacts, remove by version 2022.03
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'uid' ], [ 'id' => $gid ]);
if ( empty ( $circle )) {
throw new HTTPException\NotFoundException ( 'Circle not found.' );
2022-02-19 23:16:21 +01:00
}
foreach ( $contacts as $cid ) {
2023-05-14 01:54:35 +02:00
$cdata = Contact :: getPublicAndUserContactID ( $cid , $circle [ 'uid' ]);
2022-02-19 23:16:21 +01:00
if ( empty ( $cdata [ 'user' ])) {
throw new HTTPException\NotFoundException ( 'Invalid contact.' );
}
DBA :: insert ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $cdata [ 'user' ]], Database :: INSERT_IGNORE );
}
}
/**
2023-05-14 01:54:35 +02:00
* Removes contacts from a circle
2022-02-19 23:16:21 +01:00
*
2023-05-14 01:54:35 +02:00
* @ param int $gid Circle id
2022-06-18 17:22:10 +02:00
* @ param array $contacts Contact ids
* @ return bool
2022-02-19 23:16:21 +01:00
* @ throws \Exception
*/
public static function removeMembers ( int $gid , array $contacts )
{
if ( ! $gid || ! $contacts ) {
return false ;
}
// @TODO Backward compatibility with user contacts, remove by version 2022.03
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'uid' ], [ 'id' => $gid ]);
if ( empty ( $circle )) {
throw new HTTPException\NotFoundException ( 'Circle not found.' );
2022-02-19 23:16:21 +01:00
}
2022-02-20 14:10:57 +01:00
$contactIds = [];
2022-02-19 23:16:21 +01:00
foreach ( $contacts as $cid ) {
2023-05-14 01:54:35 +02:00
$cdata = Contact :: getPublicAndUserContactID ( $cid , $circle [ 'uid' ]);
2022-02-19 23:16:21 +01:00
if ( empty ( $cdata [ 'user' ])) {
throw new HTTPException\NotFoundException ( 'Invalid contact.' );
}
2022-02-20 14:10:57 +01:00
$contactIds [] = $cdata [ 'user' ];
2022-02-19 23:16:21 +01:00
}
2022-02-20 14:10:57 +01:00
2022-06-18 17:22:10 +02:00
// Return status of deletion
return DBA :: delete ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $contactIds ]);
2022-02-19 23:16:21 +01:00
}
2017-12-09 19:31:00 +01:00
/**
2023-05-14 01:54:35 +02:00
* Returns the combined list of contact ids from a circle id list
2017-12-09 19:31:00 +01:00
*
2023-04-28 07:13:23 +02:00
* @ param int $uid User id
2023-05-14 01:54:35 +02:00
* @ param array $circle_ids Circles ids
2023-04-28 07:13:23 +02:00
* @ param boolean $check_dead Whether check " dead " records ( ? )
* @ param boolean $expand_followers Expand the list of followers
2017-12-09 19:31:00 +01:00
* @ return array
2019-01-06 22:06:53 +01:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2023-05-14 01:54:35 +02:00
public static function expand ( int $uid , array $circle_ids , bool $check_dead = false , bool $expand_followers = true ) : array
2017-12-09 19:31:00 +01:00
{
2023-05-14 01:54:35 +02:00
if ( ! is_array ( $circle_ids ) || ! count ( $circle_ids )) {
2017-12-09 19:31:00 +01:00
return [];
}
2023-04-28 07:13:23 +02:00
$return = [];
$pubmail = false ;
$followers_collection = false ;
$networks = Protocol :: SUPPORT_PRIVATE ;
2019-12-03 00:04:11 +01:00
$mailacct = DBA :: selectFirst ( 'mailacct' , [ 'pubmail' ], [ '`uid` = ? AND `server` != ""' , $uid ]);
if ( DBA :: isResult ( $mailacct )) {
$pubmail = $mailacct [ 'pubmail' ];
}
if ( ! $pubmail ) {
$networks = array_diff ( $networks , [ Protocol :: MAIL ]);
}
2019-07-15 03:48:35 +02:00
2023-05-14 01:54:35 +02:00
$key = array_search ( self :: FOLLOWERS , $circle_ids );
2019-07-15 03:48:35 +02:00
if ( $key !== false ) {
2023-04-28 07:13:23 +02:00
if ( $expand_followers ) {
$followers = Contact :: selectToArray ([ 'id' ], [
'uid' => $uid ,
'rel' => [ Contact :: FOLLOWER , Contact :: FRIEND ],
'network' => $networks ,
'contact-type' => [ Contact :: TYPE_UNKNOWN , Contact :: TYPE_PERSON ],
'archive' => false ,
'pending' => false ,
'blocked' => false ,
]);
foreach ( $followers as $follower ) {
$return [] = $follower [ 'id' ];
}
} else {
$followers_collection = true ;
2019-07-15 03:48:35 +02:00
}
2023-05-14 01:54:35 +02:00
unset ( $circle_ids [ $key ]);
2019-07-15 03:48:35 +02:00
}
2023-05-14 01:54:35 +02:00
$key = array_search ( self :: MUTUALS , $circle_ids );
2019-07-15 03:48:35 +02:00
if ( $key !== false ) {
2019-07-28 00:06:29 +02:00
$mutuals = Contact :: selectToArray ([ 'id' ], [
2019-07-17 02:23:19 +02:00
'uid' => $uid ,
'rel' => [ Contact :: FRIEND ],
2019-12-03 00:04:11 +01:00
'network' => $networks ,
'contact-type' => [ Contact :: TYPE_UNKNOWN , Contact :: TYPE_PERSON ],
'archive' => false ,
'pending' => false ,
'blocked' => false ,
2019-07-17 02:23:19 +02:00
]);
2019-07-15 03:48:35 +02:00
2019-07-28 00:06:29 +02:00
foreach ( $mutuals as $mutual ) {
2019-07-15 03:48:35 +02:00
$return [] = $mutual [ 'id' ];
}
2023-05-14 01:54:35 +02:00
unset ( $circle_ids [ $key ]);
2019-07-15 03:48:35 +02:00
}
2023-05-14 01:54:35 +02:00
$stmt = DBA :: select ( 'group_member' , [ 'contact-id' ], [ 'gid' => $circle_ids ]);
while ( $circle_member = DBA :: fetch ( $stmt )) {
$return [] = $circle_member [ 'contact-id' ];
2017-12-09 19:31:00 +01:00
}
2019-07-28 00:06:29 +02:00
DBA :: close ( $stmt );
2017-12-09 19:31:00 +01:00
2018-08-23 15:51:58 +02:00
if ( $check_dead ) {
2020-01-05 23:07:33 +01:00
$return = Contact :: pruneUnavailable ( $return );
2017-12-09 19:31:00 +01:00
}
2018-08-23 15:51:58 +02:00
2023-04-28 07:13:23 +02:00
if ( $followers_collection ) {
$return [] = - 1 ;
}
2017-12-09 19:31:00 +01:00
return $return ;
}
/**
2023-05-14 01:54:35 +02:00
* Returns a templated circle selection list
2017-12-09 19:31:00 +01:00
*
2022-06-18 17:22:10 +02:00
* @ param int $uid User id
2023-05-14 01:54:35 +02:00
* @ param int $gid An optional pre - selected circle
2017-12-09 19:31:00 +01:00
* @ param string $label An optional label of the list
* @ return string
2019-07-15 03:48:35 +02:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2023-05-14 01:54:35 +02:00
public static function getSelectorHTML ( int $uid , int $gid = 0 , string $label = '' ) : string
2017-12-09 19:31:00 +01:00
{
2023-05-14 01:54:35 +02:00
$display_circles = [
2017-12-09 19:31:00 +01:00
[
'name' => '' ,
'id' => '0' ,
'selected' => ''
]
];
2019-07-28 00:06:29 +02:00
2022-02-12 19:38:36 +01:00
$stmt = DBA :: select ( 'group' , [], [ 'deleted' => false , 'uid' => $uid , 'cid' => null ], [ 'order' => [ 'name' ]]);
2023-05-14 01:54:35 +02:00
while ( $circle = DBA :: fetch ( $stmt )) {
$display_circles [] = [
'name' => $circle [ 'name' ],
'id' => $circle [ 'id' ],
'selected' => $gid == $circle [ 'id' ] ? 'true' : ''
2017-12-09 19:31:00 +01:00
];
}
2019-07-28 00:06:29 +02:00
DBA :: close ( $stmt );
2023-05-14 01:54:35 +02:00
Logger :: info ( 'Got circles' , $display_circles );
2017-12-09 19:31:00 +01:00
if ( $label == '' ) {
2023-05-14 01:54:35 +02:00
$label = DI :: l10n () -> t ( 'Default privacy circle for new contacts' );
2017-12-09 19:31:00 +01:00
}
2023-05-14 01:54:35 +02:00
$o = Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'circle_selection.tpl' ), [
2017-12-09 19:31:00 +01:00
'$label' => $label ,
2023-05-14 01:54:35 +02:00
'$circles' => $display_circles
2018-01-15 14:05:12 +01:00
]);
2017-12-09 19:31:00 +01:00
return $o ;
}
/**
2023-05-14 01:54:35 +02:00
* Create circle sidebar widget
2017-12-09 19:31:00 +01:00
*
* @ param string $every
* @ param string $each
* @ param string $editmode
2023-05-14 01:54:35 +02:00
* 'standard' => include link 'Edit circles'
* 'extended' => include link 'Create new circle'
* 'full' => include link 'Create new circle' and provide for each circle a link to edit this circle
* @ param string | int $circle_id Distinct circle id or 'everyone'
2022-06-18 17:22:10 +02:00
* @ param int $cid Contact id
* @ return string Sidebar widget HTML code
2019-07-15 03:48:35 +02:00
* @ throws \Exception
2017-12-09 19:31:00 +01:00
*/
2023-05-14 01:54:35 +02:00
public static function sidebarWidget ( string $every = 'contact' , string $each = 'circle' , string $editmode = 'standard' , $circle_id = '' , int $cid = 0 )
2017-12-09 19:31:00 +01:00
{
2022-10-20 22:14:50 +02:00
if ( ! DI :: userSession () -> getLocalUserId ()) {
2017-12-09 19:31:00 +01:00
return '' ;
}
2023-05-14 01:54:35 +02:00
$display_circles = [
2017-12-09 19:31:00 +01:00
[
2020-01-18 20:52:34 +01:00
'text' => DI :: l10n () -> t ( 'Everybody' ),
2017-12-09 19:31:00 +01:00
'id' => 0 ,
2023-05-14 01:54:35 +02:00
'selected' => (( $circle_id === 'everyone' ) ? 'circle-selected' : '' ),
2017-12-09 19:31:00 +01:00
'href' => $every ,
]
];
2018-01-15 14:05:12 +01:00
$member_of = [];
2017-12-09 19:31:00 +01:00
if ( $cid ) {
2017-12-16 17:50:58 +01:00
$member_of = self :: getIdsByContactId ( $cid );
2017-12-09 19:31:00 +01:00
}
2022-10-20 22:14:50 +02:00
$stmt = DBA :: select ( 'group' , [], [ 'deleted' => false , 'uid' => DI :: userSession () -> getLocalUserId (), 'cid' => null ], [ 'order' => [ 'name' ]]);
2023-05-14 01:54:35 +02:00
while ( $circle = DBA :: fetch ( $stmt )) {
$selected = (( $circle_id == $circle [ 'id' ]) ? ' circle-selected' : '' );
2017-12-09 19:31:00 +01:00
2017-12-10 07:06:12 +01:00
if ( $editmode == 'full' ) {
2023-05-14 01:54:35 +02:00
$circleedit = [
'href' => 'circle/' . $circle [ 'id' ],
2020-01-18 20:52:34 +01:00
'title' => DI :: l10n () -> t ( 'edit' ),
2017-12-09 19:31:00 +01:00
];
2017-12-10 07:06:12 +01:00
} else {
2023-05-14 01:54:35 +02:00
$circleedit = null ;
2017-12-09 19:31:00 +01:00
}
2017-12-10 07:06:12 +01:00
2023-05-14 01:54:35 +02:00
if ( $each == 'circle' ) {
$count = DBA :: count ( 'group_member' , [ 'gid' => $circle [ 'id' ]]);
$circle_name = sprintf ( '%s (%d)' , $circle [ 'name' ], $count );
2020-10-07 08:19:09 +02:00
} else {
2023-05-14 01:54:35 +02:00
$circle_name = $circle [ 'name' ];
2020-10-07 08:19:09 +02:00
}
2023-05-14 01:54:35 +02:00
$display_circles [] = [
'id' => $circle [ 'id' ],
2017-12-10 07:06:12 +01:00
'cid' => $cid ,
2023-05-14 01:54:35 +02:00
'text' => $circle_name ,
'href' => $each . '/' . $circle [ 'id' ],
'edit' => $circleedit ,
2017-12-10 07:06:12 +01:00
'selected' => $selected ,
2023-05-14 01:54:35 +02:00
'ismember' => in_array ( $circle [ 'id' ], $member_of ),
2017-12-10 07:06:12 +01:00
];
2017-12-09 19:31:00 +01:00
}
2019-07-28 00:06:29 +02:00
DBA :: close ( $stmt );
2017-12-09 19:31:00 +01:00
2023-05-14 01:54:35 +02:00
// Don't show the circles on the network page when there is only one
if (( count ( $display_circles ) <= 2 ) && ( $each == 'network' )) {
2018-11-24 13:10:30 +01:00
return '' ;
}
2023-05-14 01:54:35 +02:00
$tpl = Renderer :: getMarkupTemplate ( 'circle_side.tpl' );
2018-10-31 15:35:50 +01:00
$o = Renderer :: replaceMacros ( $tpl , [
2020-01-18 20:52:34 +01:00
'$add' => DI :: l10n () -> t ( 'add' ),
2023-05-14 01:54:35 +02:00
'$title' => DI :: l10n () -> t ( 'Circles' ),
'$circles' => $display_circles ,
'$new_circle' => $editmode == 'extended' || $editmode == 'full' ? 1 : '' ,
'$circle_page' => 'circle/' ,
'$edittext' => DI :: l10n () -> t ( 'Edit circle' ),
'$uncircled' => $every === 'contact' ? DI :: l10n () -> t ( 'Contacts not in any circle' ) : '' ,
'$uncircled_selected' => (( $circle_id === 'none' ) ? 'circle-selected' : '' ),
'$createtext' => DI :: l10n () -> t ( 'Create a new circle' ),
'$create_circle' => DI :: l10n () -> t ( 'Circle Name: ' ),
'$edit_circles_text' => DI :: l10n () -> t ( 'Edit circles' ),
'$form_security_token' => BaseModule :: getFormSecurityToken ( 'circle_edit' ),
2017-12-09 19:31:00 +01:00
]);
return $o ;
}
2022-02-09 22:34:25 +01:00
/**
2023-05-14 01:54:35 +02:00
* Fetch the circle id for the given contact id
2022-02-09 22:34:25 +01:00
*
* @ param integer $id Contact ID
2023-05-14 01:54:35 +02:00
* @ return integer Circle ID
2022-02-09 22:34:25 +01:00
*/
2023-05-30 15:15:17 +02:00
public static function getIdForGroup ( int $id ) : int
2022-02-12 19:38:36 +01:00
{
2023-05-30 15:15:17 +02:00
Logger :: info ( 'Get id for group id' , [ 'id' => $id ]);
2022-02-12 19:38:36 +01:00
$contact = Contact :: getById ( $id , [ 'uid' , 'name' , 'contact-type' , 'manually-approve' ]);
if ( empty ( $contact ) || ( $contact [ 'contact-type' ] != Contact :: TYPE_COMMUNITY ) || ! $contact [ 'manually-approve' ]) {
return 0 ;
2022-02-09 22:34:25 +01:00
}
2022-02-12 19:38:36 +01:00
2023-05-14 01:54:35 +02:00
$circle = DBA :: selectFirst ( 'group' , [ 'id' ], [ 'uid' => $contact [ 'uid' ], 'cid' => $id ]);
if ( empty ( $circle )) {
2022-02-09 22:34:25 +01:00
$fields = [
'uid' => $contact [ 'uid' ],
'name' => $contact [ 'name' ],
'cid' => $id ,
];
DBA :: insert ( 'group' , $fields );
$gid = DBA :: lastInsertId ();
} else {
2023-05-14 01:54:35 +02:00
$gid = $circle [ 'id' ];
2022-02-09 22:34:25 +01:00
}
2022-02-12 19:38:36 +01:00
return $gid ;
}
/**
2023-05-14 01:54:35 +02:00
* Fetch the followers of a given contact id and store them as circle members
2022-02-12 19:38:36 +01:00
*
* @ param integer $id Contact ID
2022-06-18 17:22:10 +02:00
* @ return void
2022-02-12 19:38:36 +01:00
*/
2023-05-30 15:15:17 +02:00
public static function updateMembersForGroup ( int $id )
2022-02-12 19:38:36 +01:00
{
2023-05-30 15:15:17 +02:00
Logger :: info ( 'Update group members' , [ 'id' => $id ]);
2022-02-12 19:38:36 +01:00
$contact = Contact :: getById ( $id , [ 'uid' , 'url' ]);
if ( empty ( $contact )) {
return ;
}
$apcontact = APContact :: getByURL ( $contact [ 'url' ]);
if ( empty ( $apcontact [ 'followers' ])) {
return ;
}
2023-05-30 15:15:17 +02:00
$gid = self :: getIdForGroup ( $id );
2022-02-12 19:38:36 +01:00
if ( empty ( $gid )) {
return ;
}
2023-05-14 01:54:35 +02:00
$circle_members = DBA :: selectToArray ( 'group_member' , [ 'contact-id' ], [ 'gid' => $gid ]);
if ( ! empty ( $circle_members )) {
$current = array_unique ( array_column ( $circle_members , 'contact-id' ));
2022-02-09 22:34:25 +01:00
} else {
$current = [];
}
2022-02-12 19:38:36 +01:00
foreach ( ActivityPub :: fetchItems ( $apcontact [ 'followers' ], $contact [ 'uid' ]) as $follower ) {
2022-02-09 22:34:25 +01:00
$id = Contact :: getIdForURL ( $follower );
if ( ! in_array ( $id , $current )) {
DBA :: insert ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $id ]);
} else {
$key = array_search ( $id , $current );
unset ( $current [ $key ]);
}
}
2022-02-12 19:38:36 +01:00
2022-02-09 22:34:25 +01:00
DBA :: delete ( 'group_member' , [ 'gid' => $gid , 'contact-id' => $current ]);
2023-05-30 15:15:17 +02:00
Logger :: info ( 'Updated group members' , [ 'id' => $id , 'count' => DBA :: count ( 'group_member' , [ 'gid' => $gid ])]);
2022-02-09 22:34:25 +01:00
}
2017-12-09 19:31:00 +01:00
}