2016-04-19 03:38:38 +00:00
< ? php
namespace Zotlabs\Module ;
2019-10-02 00:44:58 +00:00
use App ;
use Zotlabs\Web\Controller ;
2018-06-05 01:40:11 +00:00
use Zotlabs\Lib\Libsync ;
2019-02-14 23:26:37 +00:00
use Zotlabs\Lib\AccessList ;
2019-10-02 01:29:39 +00:00
use Zotlabs\Lib\ActivityStreams ;
use Zotlabs\Lib\Activity ;
use Zotlabs\Web\HTTPSig ;
use Zotlabs\Lib\Config ;
2019-10-02 02:03:48 +00:00
use Zotlabs\Lib\LDSignatures ;
2016-04-19 03:38:38 +00:00
2019-10-02 00:44:58 +00:00
class Lists extends Controller {
2016-04-19 03:38:38 +00:00
2018-06-17 14:58:12 +00:00
function init () {
2019-10-02 01:29:39 +00:00
if ( ActivityStreams :: is_as_request ()) {
$item_id = argv ( 1 );
if ( ! $item_id ) {
http_status_exit ( 404 , 'Not found' );
}
$x = q ( " select * from pgrp where hash = '%s' limit 1 " ,
dbesc ( $item_id )
);
if ( ! $x ) {
http_status_exit ( 404 , 'Not found' );
}
$group = array_shift ( $x );
// process an authenticated fetch
$sigdata = HTTPSig :: verify ( EMPTY_STR );
if ( $sigdata [ 'portable_id' ] && $sigdata [ 'header_valid' ]) {
$portable_id = $sigdata [ 'portable_id' ];
if ( ! check_channelallowed ( $portable_id )) {
http_status_exit ( 403 , 'Permission denied' );
}
if ( ! check_siteallowed ( $sigdata [ 'signer' ])) {
http_status_exit ( 403 , 'Permission denied' );
}
observer_auth ( $portable_id );
}
2019-11-04 23:26:05 +00:00
elseif ( Config :: get ( 'system' , 'require_authenticated_fetch' , false )) {
2019-10-02 01:29:39 +00:00
http_status_exit ( 403 , 'Permission denied' );
}
2019-10-02 02:03:48 +00:00
if ( ! perm_is_allowed ( $group [ 'uid' ], get_observer_hash (), 'view_contacts' )) {
2019-10-02 01:29:39 +00:00
http_status_exit ( 403 , 'Permission denied' );
}
2019-10-02 02:43:53 +00:00
$channel = channelx_by_n ( $group [ 'uid' ]);
if ( ! $channel ) {
http_status_exit ( 404 , 'Not found' );
}
2019-10-02 01:29:39 +00:00
if ( ! $group [ 'visible' ]) {
2019-10-02 02:43:53 +00:00
if ( $channel [ 'channel_hash' ] !== get_observer_hash ()) {
2019-10-02 01:29:39 +00:00
http_status_exit ( 403 , 'Permission denied' );
}
}
2020-08-07 06:22:24 +00:00
$total = AccessList :: members ( $group [ 'uid' ], $group [ 'id' ], true );
if ( $total ) {
App :: set_pager_total ( $total );
App :: set_pager_itemspage ( 100 );
}
if ( App :: $pager [ 'unset' ] && $total > 100 ) {
$ret = Activity :: paged_collection_init ( $total , App :: $query_string );
}
else {
$members = AccessList :: members ( $group [ 'uid' ], $group [ 'id' ], false , App :: $pager [ 'start' ], App :: $pager [ 'itemspage' ]);
$ret = Activity :: encode_follow_collection ( $members , App :: $query_string , 'OrderedCollection' , $total );
}
2019-10-02 01:29:39 +00:00
$x = array_merge ([ '@context' => [
ACTIVITYSTREAMS_JSONLD_REV ,
'https://w3id.org/security/v1' ,
z_root () . ZOT_APSCHEMA_REV
2020-08-07 06:22:24 +00:00
]], $ret );
2019-10-02 01:29:39 +00:00
$headers = [];
$headers [ 'Content-Type' ] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x [ 'signature' ] = LDSignatures :: sign ( $x , $channel );
$ret = json_encode ( $x , JSON_UNESCAPED_SLASHES );
2019-11-08 20:16:29 +00:00
$headers [ 'Date' ] = datetime_convert ( 'UTC' , 'UTC' , 'now' , 'D, d M Y H:i:s \\G\\M\\T' );
2019-10-02 01:29:39 +00:00
$headers [ 'Digest' ] = HTTPSig :: generate_digest_header ( $ret );
$headers [ '(request-target)' ] = strtolower ( $_SERVER [ 'REQUEST_METHOD' ]) . ' ' . $_SERVER [ 'REQUEST_URI' ];
$h = HTTPSig :: create_sig ( $headers , $channel [ 'channel_prvkey' ], channel_url ( $channel ));
HTTPSig :: set_headers ( $h );
echo $ret ;
killme ();
}
2019-10-02 00:44:58 +00:00
if ( ! local_channel ()) {
2018-06-17 14:58:12 +00:00
notice ( t ( 'Permission denied.' ) . EOL );
return ;
}
2019-10-02 00:44:58 +00:00
App :: $profile_uid = local_channel ();
2019-02-14 23:26:37 +00:00
nav_set_selected ( 'Access Lists' );
2018-06-17 14:58:12 +00:00
}
2016-04-19 03:38:38 +00:00
function post () {
2019-10-02 00:44:58 +00:00
if ( ! local_channel ()) {
2016-04-19 03:38:38 +00:00
notice ( t ( 'Permission denied.' ) . EOL );
return ;
}
2019-10-02 00:44:58 +00:00
if (( argc () == 2 ) && ( argv ( 1 ) === 'new' )) {
check_form_security_token_redirectOnErr ( '/lists/new' , 'group_edit' );
2016-04-19 03:38:38 +00:00
$name = notags ( trim ( $_POST [ 'groupname' ]));
$public = intval ( $_POST [ 'public' ]);
2019-02-14 23:26:37 +00:00
$r = AccessList :: add ( local_channel (), $name , $public );
2019-10-02 00:44:58 +00:00
if ( $r ) {
2019-02-14 23:26:37 +00:00
info ( t ( 'Access list created.' ) . EOL );
2016-04-19 03:38:38 +00:00
}
2018-06-17 14:58:12 +00:00
else {
2019-02-14 23:26:37 +00:00
notice ( t ( 'Could not create access list.' ) . EOL );
2018-06-17 14:58:12 +00:00
}
2019-10-02 00:44:58 +00:00
goaway ( z_root () . '/lists' );
2016-04-19 03:38:38 +00:00
}
2019-10-02 00:44:58 +00:00
if (( argc () == 2 ) && ( intval ( argv ( 1 )))) {
check_form_security_token_redirectOnErr ( '/lists' , 'group_edit' );
2016-04-19 03:38:38 +00:00
2018-09-26 00:47:43 +00:00
$r = q ( " SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1 " ,
2016-04-19 03:38:38 +00:00
intval ( argv ( 1 )),
intval ( local_channel ())
);
2019-10-02 00:44:58 +00:00
if ( ! $r ) {
2019-02-14 23:26:37 +00:00
notice ( t ( 'Access list not found.' ) . EOL );
2016-04-19 03:38:38 +00:00
goaway ( z_root () . '/connections' );
}
2019-10-02 00:44:58 +00:00
$group = array_shift ( $r );
2016-04-19 03:38:38 +00:00
$groupname = notags ( trim ( $_POST [ 'groupname' ]));
$public = intval ( $_POST [ 'public' ]);
2019-10-02 00:44:58 +00:00
if (( strlen ( $groupname )) && (( $groupname != $group [ 'gname' ]) || ( $public != $group [ 'visible' ]))) {
2018-09-26 00:47:43 +00:00
$r = q ( " UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d " ,
2016-04-19 03:38:38 +00:00
dbesc ( $groupname ),
intval ( $public ),
intval ( local_channel ()),
intval ( $group [ 'id' ])
);
2019-10-02 00:44:58 +00:00
if ( $r ) {
2019-02-14 23:26:37 +00:00
info ( t ( 'Access list updated.' ) . EOL );
2019-10-02 00:44:58 +00:00
}
2018-06-05 01:40:11 +00:00
Libsync :: build_sync_packet ( local_channel (), null , true );
2016-04-19 03:38:38 +00:00
}
2019-10-02 00:44:58 +00:00
goaway ( z_root () . '/lists/' . argv ( 1 ) . '/' . argv ( 2 ));
2016-04-19 03:38:38 +00:00
}
return ;
}
2017-07-20 01:32:16 +00:00
function get () {
2016-04-19 03:38:38 +00:00
$change = false ;
2019-10-23 23:07:12 +00:00
logger ( 'mod_lists: ' . App :: $cmd , LOGGER_DEBUG );
2016-04-19 03:38:38 +00:00
2019-10-23 23:07:12 +00:00
if ( argc () > 2 && argv ( 1 ) === 'view' ) {
$grp = argv ( 2 );
if ( $grp ) {
$r = q ( " select * from pgrp where hash = '%s' and deleted = 0 " ,
dbesc ( $grp )
);
if ( $r ) {
$uid = $r [ 0 ][ 'uid' ];
if ( local_channel () && local_channel () == $uid ) {
goaway ( z_root () . '/lists/' . $r [ 0 ][ 'id' ]);
}
if ( ! ( $r [ 0 ][ 'visible' ] && perm_is_allowed ( $uid , get_observer_hash (), 'view_contacts' ))) {
notice ( t ( 'Permission denied' ) . EOL );
return ;
}
$members = [];
$memberlist = AccessList :: members ( $uid , $r [ 0 ][ 'id' ]);
if ( $memberlist ) {
foreach ( $memberlist as $member ) {
2019-10-23 23:11:10 +00:00
$members [] = micropro ( $member , true , 'mpgroup' , 'card' );
2019-10-23 23:07:12 +00:00
}
}
$o = replace_macros ( get_markup_template ( 'listmembers.tpl' ), [
'$title' => t ( 'List members' ),
'$members' => $members
]);
return $o ;
}
else {
notice ( t ( 'List not found' ) . EOL );
return ;
}
}
}
2019-10-02 00:44:58 +00:00
if ( ! local_channel ()) {
2016-04-19 03:38:38 +00:00
notice ( t ( 'Permission denied' ) . EOL );
return ;
}
2018-06-17 14:58:12 +00:00
2019-10-23 23:07:12 +00:00
2020-07-27 23:57:58 +00:00
// Switch to text mode interface if we have more than 'n' contacts or group members, else loading avatars will lead to poor interactivity
$switchtotext = get_pconfig ( local_channel (), 'system' , 'listedit_image_limit' , get_config ( 'system' , 'listedit_image_limit' , 1000 ));
2018-06-17 14:58:12 +00:00
2019-10-02 00:44:58 +00:00
if (( argc () == 1 ) || (( argc () == 2 ) && ( argv ( 1 ) === 'new' ))) {
2018-06-17 14:58:12 +00:00
$new = ((( argc () == 2 ) && ( argv ( 1 ) === 'new' )) ? true : false );
2018-09-26 00:47:43 +00:00
$groups = q ( " SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC " ,
2018-06-17 14:58:12 +00:00
intval ( local_channel ())
);
$i = 0 ;
2019-10-02 00:44:58 +00:00
foreach ( $groups as $group ) {
2018-06-17 14:58:12 +00:00
$entries [ $i ][ 'name' ] = $group [ 'gname' ];
$entries [ $i ][ 'id' ] = $group [ 'id' ];
2019-10-02 01:29:39 +00:00
$entries [ $i ][ 'count' ] = count ( AccessList :: members ( local_channel (), $group [ 'id' ]));
2018-06-17 14:58:12 +00:00
$i ++ ;
}
$tpl = get_markup_template ( 'privacy_groups.tpl' );
$o = replace_macros ( $tpl , [
2019-02-14 23:26:37 +00:00
'$title' => t ( 'Access Lists' ),
'$add_new_label' => t ( 'Create access list' ),
2018-06-17 14:58:12 +00:00
'$new' => $new ,
// new group form
2019-02-14 23:26:37 +00:00
'$gname' => array ( 'groupname' , t ( 'Access list name' )),
2018-06-17 14:58:12 +00:00
'$public' => array ( 'public' , t ( 'Members are visible to other channels' ), false ),
2016-04-19 03:38:38 +00:00
'$form_security_token' => get_form_security_token ( " group_edit " ),
2018-06-17 14:58:12 +00:00
'$submit' => t ( 'Submit' ),
// groups list
2019-02-14 23:26:37 +00:00
'$title' => t ( 'Access Lists' ),
2018-06-17 14:58:12 +00:00
'$name_label' => t ( 'Name' ),
'$count_label' => t ( 'Members' ),
'$entries' => $entries
]);
return $o ;
2016-04-19 03:38:38 +00:00
}
2018-06-17 14:58:12 +00:00
$context = array ( '$submit' => t ( 'Submit' ));
$tpl = get_markup_template ( 'group_edit.tpl' );
2016-04-19 03:38:38 +00:00
if (( argc () == 3 ) && ( argv ( 1 ) === 'drop' )) {
2019-10-02 00:44:58 +00:00
check_form_security_token_redirectOnErr ( '/lists' , 'group_drop' , 't' );
2016-04-19 03:38:38 +00:00
if ( intval ( argv ( 2 ))) {
2018-09-26 00:47:43 +00:00
$r = q ( " SELECT gname FROM pgrp WHERE id = %d AND uid = %d LIMIT 1 " ,
2016-04-19 03:38:38 +00:00
intval ( argv ( 2 )),
intval ( local_channel ())
);
if ( $r )
2019-02-14 23:26:37 +00:00
$result = AccessList :: remove ( local_channel (), $r [ 0 ][ 'gname' ]);
2016-04-19 03:38:38 +00:00
if ( $result )
2019-02-14 23:26:37 +00:00
info ( t ( 'Access list removed.' ) . EOL );
2016-04-19 03:38:38 +00:00
else
2019-02-14 23:26:37 +00:00
notice ( t ( 'Unable to remove access list.' ) . EOL );
2016-04-19 03:38:38 +00:00
}
2019-10-02 00:44:58 +00:00
goaway ( z_root () . '/lists' );
2016-04-19 03:38:38 +00:00
// NOTREACHED
}
if (( argc () > 2 ) && intval ( argv ( 1 )) && argv ( 2 )) {
check_form_security_token_ForbiddenOnErr ( 'group_member_change' , 't' );
$r = q ( " SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 limit 1 " ,
dbesc ( base64url_decode ( argv ( 2 ))),
intval ( local_channel ())
);
if ( count ( $r ))
$change = base64url_decode ( argv ( 2 ));
}
if (( argc () > 1 ) && ( intval ( argv ( 1 )))) {
require_once ( 'include/acl_selectors.php' );
2018-09-26 00:47:43 +00:00
$r = q ( " SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1 " ,
2016-04-19 03:38:38 +00:00
intval ( argv ( 1 )),
intval ( local_channel ())
);
if ( ! $r ) {
2019-02-14 23:26:37 +00:00
notice ( t ( 'Access list not found.' ) . EOL );
2016-04-19 03:38:38 +00:00
goaway ( z_root () . '/connections' );
}
$group = $r [ 0 ];
2019-10-23 23:07:12 +00:00
2019-10-02 01:29:39 +00:00
$members = AccessList :: members ( local_channel (), $group [ 'id' ]);
2019-10-23 23:07:12 +00:00
2016-04-19 03:38:38 +00:00
$preselected = array ();
if ( count ( $members )) {
foreach ( $members as $member )
if ( ! in_array ( $member [ 'xchan_hash' ], $preselected ))
$preselected [] = $member [ 'xchan_hash' ];
}
if ( $change ) {
if ( in_array ( $change , $preselected )) {
2019-02-14 23:26:37 +00:00
AccessList :: member_remove ( local_channel (), $group [ 'gname' ], $change );
2016-04-19 03:38:38 +00:00
}
else {
2019-02-14 23:26:37 +00:00
AccessList :: member_add ( local_channel (), $group [ 'gname' ], $change );
2016-04-19 03:38:38 +00:00
}
2019-10-02 01:29:39 +00:00
$members = AccessList :: members ( local_channel (), $group [ 'id' ]);
2016-04-19 03:38:38 +00:00
$preselected = array ();
if ( count ( $members )) {
foreach ( $members as $member )
$preselected [] = $member [ 'xchan_hash' ];
}
}
2018-06-17 14:58:12 +00:00
2016-04-19 03:38:38 +00:00
$context = $context + array (
2019-02-14 23:26:37 +00:00
'$title' => sprintf ( t ( 'Access List: %s' ), $group [ 'gname' ]),
2018-06-17 14:58:12 +00:00
'$details_label' => t ( 'Edit' ),
2019-02-14 23:26:37 +00:00
'$gname' => array ( 'groupname' , t ( 'Access list name: ' ), $group [ 'gname' ], '' ),
2016-04-19 03:38:38 +00:00
'$gid' => $group [ 'id' ],
'$drop' => $drop_txt ,
'$public' => array ( 'public' , t ( 'Members are visible to other channels' ), $group [ 'visible' ], '' ),
2018-06-17 14:58:12 +00:00
'$form_security_token_edit' => get_form_security_token ( 'group_edit' ),
2019-02-14 23:26:37 +00:00
'$delete' => t ( 'Delete access list' ),
2018-06-17 14:58:12 +00:00
'$form_security_token_drop' => get_form_security_token ( " group_drop " ),
2016-04-19 03:38:38 +00:00
);
}
if ( ! isset ( $group ))
return ;
$groupeditor = array (
2019-02-14 23:26:37 +00:00
'label_members' => t ( 'List members' ),
2016-04-19 03:38:38 +00:00
'members' => array (),
2019-02-14 23:26:37 +00:00
'label_contacts' => t ( 'Not in this list' ),
2016-04-19 03:38:38 +00:00
'contacts' => array (),
);
$sec_token = addslashes ( get_form_security_token ( 'group_member_change' ));
2018-06-17 14:58:12 +00:00
$textmode = (( $switchtotext && ( count ( $members ) > $switchtotext )) ? true : 'card' );
2016-04-19 03:38:38 +00:00
foreach ( $members as $member ) {
if ( $member [ 'xchan_url' ]) {
$member [ 'archived' ] = ( intval ( $member [ 'abook_archived' ]) ? true : false );
$member [ 'click' ] = 'groupChangeMember(' . $group [ 'id' ] . ',\'' . base64url_encode ( $member [ 'xchan_hash' ]) . '\',\'' . $sec_token . '\'); return false;' ;
$groupeditor [ 'members' ][] = micropro ( $member , true , 'mpgroup' , $textmode );
}
else
2019-02-14 23:26:37 +00:00
AccessList :: member_remove ( local_channel (), $group [ 'gname' ], $member [ 'xchan_hash' ]);
2016-04-19 03:38:38 +00:00
}
2016-10-04 05:01:14 +00:00
$r = q ( " SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc " ,
2016-04-19 03:38:38 +00:00
intval ( local_channel ())
);
if ( count ( $r )) {
2018-06-17 14:58:12 +00:00
$textmode = (( $switchtotext && ( count ( $r ) > $switchtotext )) ? true : 'card' );
2016-04-19 03:38:38 +00:00
foreach ( $r as $member ) {
if ( ! in_array ( $member [ 'xchan_hash' ], $preselected )) {
$member [ 'archived' ] = ( intval ( $member [ 'abook_archived' ]) ? true : false );
$member [ 'click' ] = 'groupChangeMember(' . $group [ 'id' ] . ',\'' . base64url_encode ( $member [ 'xchan_hash' ]) . '\',\'' . $sec_token . '\'); return false;' ;
$groupeditor [ 'contacts' ][] = micropro ( $member , true , 'mpall' , $textmode );
}
}
}
$context [ '$groupeditor' ] = $groupeditor ;
2019-10-02 02:54:00 +00:00
$context [ '$desc' ] = t ( 'Select a channel to toggle membership' );
2016-04-19 03:38:38 +00:00
if ( $change ) {
$tpl = get_markup_template ( 'groupeditor.tpl' );
echo replace_macros ( $tpl , $context );
killme ();
}
return replace_macros ( $tpl , $context );
}
}