diff options
Diffstat (limited to 'Zotlabs/Module')
35 files changed, 3368 insertions, 2523 deletions
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index aeb02eeaa..5b37f2707 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -3,9 +3,9 @@ namespace Zotlabs\Module; use Zotlabs\Lib\Libzotdir; +use Zotlabs\Lib\AccessList; require_once 'include/acl_selectors.php'; -require_once 'include/group.php'; /** * @brief ACL selector json backend. @@ -123,7 +123,7 @@ class Acl extends \Zotlabs\Web\Controller { "name" => t('Profile','acl') . ' ' . $rv['profile_name'], "id" => 'vp' . $rv['id'], "xid" => 'vp.' . $rv['profile_guid'], - "uids" => group_get_profile_members_xchan(local_channel(), $rv['id']), + "uids" => AccessList::profile_members_xchan(local_channel(), $rv['id']), "link" => '' ); } @@ -146,14 +146,14 @@ class Acl extends \Zotlabs\Web\Controller { if($r) { foreach($r as $g){ - // logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id'])); + // logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(), $g['id'])); $groups[] = array( "type" => "g", "photo" => "images/twopeople.png", "name" => $g['gname'], "id" => $g['id'], "xid" => $g['hash'], - "uids" => group_get_members_xchan($g['id']), + "uids" => AccessList::members_xchan(local_channel(), $g['id']), "link" => '' ); } diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index 76e117a84..00095187d 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -339,8 +339,8 @@ class Site { // now invert the logic for the setting. $discover_tab = (1 - $discover_tab); - $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); - $default_role = get_config('system','default_permissions_role','social'); + $perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles(); + $default_role = get_config('system','default_permissions_role','personal'); $role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles); diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php index 26e564aa5..d287115d4 100644 --- a/Zotlabs/Module/Appman.php +++ b/Zotlabs/Module/Appman.php @@ -55,8 +55,6 @@ class Appman extends \Zotlabs\Web\Controller { if(Apps::app_installed(local_channel(),$papp)) info( t('App installed.') . EOL); -hz_syslog('install: ' . print_r($papp,true)); - $sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1", intval(local_channel()), dbesc($papp['guid']) diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php index eab82eb29..e8d45c522 100644 --- a/Zotlabs/Module/Apschema.php +++ b/Zotlabs/Module/Apschema.php @@ -14,7 +14,7 @@ class Apschema extends \Zotlabs\Web\Controller { 'zot' => z_root() . '/apschema#', 'id' => '@id', 'type' => '@type', - 'commentPolicy' => 'as:commentPolicy', + 'commentPolicy' => 'zot:commentPolicy', 'meData' => 'zot:meData', 'meDataType' => 'zot:meDataType', 'meEncoding' => 'zot:meEncoding', @@ -33,6 +33,9 @@ class Apschema extends \Zotlabs\Web\Controller { 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value', + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + + 'magicEnv' => [ '@id' => 'zot:magicEnv', '@type' => '@id' diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 6261a2f06..aebc70c15 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -66,8 +66,7 @@ class Channel extends Controller { $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); if ($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { - $data = json_encode(Libzot::zotinfo(['address' => $channel['channel_address'], 'target_url' => $sigdata['signer']])); - + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer']])); $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", dbesc($sigdata['signer']) ); @@ -96,6 +95,10 @@ class Channel extends Controller { http_status_exit(410, 'Gone'); } + if (get_pconfig($channel['channel_id'], 'system', 'index_opt_out')) { + App::$meta->set('robots', 'noindex, noarchive'); + } + if (ActivityStreams::is_as_request($channel)) { // Somebody may attempt an ActivityStreams fetch on one of our message permalinks diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index 5025f4e22..0f674965d 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -2,32 +2,32 @@ namespace Zotlabs\Module; use App; +use Zotlabs\Lib\Permcat; require_once('include/socgraph.php'); require_once('include/selectors.php'); -require_once('include/group.php'); class Connections extends \Zotlabs\Web\Controller { function init() { - + if(! local_channel()) return; App::$profile_uid = local_channel(); - + $channel = App::get_channel(); if($channel) head_set_icon($channel['xchan_photo_s']); - + } - + function get() { - + $sort_type = 0; $o = ''; - - + + if(! local_channel()) { notice( t('Permission denied.') . EOL); return login(); @@ -44,13 +44,13 @@ class Connections extends \Zotlabs\Web\Controller { $pending = false; $unconnected = false; $all = false; - + if(! $_REQUEST['aj']) $_SESSION['return_url'] = App::$query_string; - + $search_flags = ""; $head = ''; - + if(argc() == 2) { switch(argv(1)) { case 'active': @@ -106,7 +106,7 @@ class Connections extends \Zotlabs\Web\Controller { // $head = t('Unconnected'); // $unconnected = true; // break; - + case 'all': $head = t('All'); break; @@ -115,19 +115,19 @@ class Connections extends \Zotlabs\Web\Controller { $active = true; $head = t('Active'); break; - + } - + $sql_extra = $search_flags; if(argv(1) === 'pending') $sql_extra .= " and abook_ignored = 0 "; - + } else { $sql_extra = " and abook_blocked = 0 "; $unblocked = true; } - + switch($_REQUEST['order']) { case 'name_desc': $sql_order = 'xchan_name DESC'; @@ -143,32 +143,32 @@ class Connections extends \Zotlabs\Web\Controller { } $search = ((x($_REQUEST,'search')) ? notags(trim($_REQUEST['search'])) : ''); - + $tabs = array( /* array( 'label' => t('Suggestions'), - 'url' => z_root() . '/suggest', + 'url' => z_root() . '/suggest', 'sel' => '', 'title' => t('Suggest new connections'), ), */ - + 'active' => array( 'label' => t('Active Connections'), - 'url' => z_root() . '/connections/active', + 'url' => z_root() . '/connections/active', 'sel' => ($active) ? 'active' : '', 'title' => t('Show active connections'), ), 'pending' => array( 'label' => t('New Connections'), - 'url' => z_root() . '/connections/pending', + 'url' => z_root() . '/connections/pending', 'sel' => ($pending) ? 'active' : '', 'title' => t('Show pending (new) connections'), ), - - + + /* array( 'label' => t('Unblocked'), @@ -177,55 +177,55 @@ class Connections extends \Zotlabs\Web\Controller { 'title' => t('Only show unblocked connections'), ), */ - + 'blocked' => array( 'label' => t('Blocked'), 'url' => z_root() . '/connections/blocked', 'sel' => ($blocked) ? 'active' : '', 'title' => t('Only show blocked connections'), ), - + 'ignored' => array( 'label' => t('Ignored'), 'url' => z_root() . '/connections/ignored', 'sel' => ($ignored) ? 'active' : '', 'title' => t('Only show ignored connections'), ), - + 'archived' => array( 'label' => t('Archived/Unreachable'), 'url' => z_root() . '/connections/archived', 'sel' => ($archived) ? 'active' : '', 'title' => t('Only show archived/unreachable connections'), ), - + 'hidden' => array( 'label' => t('Hidden'), 'url' => z_root() . '/connections/hidden', 'sel' => ($hidden) ? 'active' : '', 'title' => t('Only show hidden connections'), ), - + // array( // 'label' => t('Unconnected'), // 'url' => z_root() . '/connections/unconnected', // 'sel' => ($unconnected) ? 'active' : '', // 'title' => t('Only show one-way connections'), // ), - + 'all' => array( 'label' => t('All Connections'), - 'url' => z_root() . '/connections', + 'url' => z_root() . '/connections', 'sel' => ($all) ? 'active' : '', 'title' => t('Show all connections'), ), - + ); - + //$tab_tpl = get_markup_template('common_tabs.tpl'); //$t = replace_macros($tab_tpl, array('$tabs'=>$tabs)); - + $searching = false; if($search) { $search_hdr = $search; @@ -233,12 +233,12 @@ class Connections extends \Zotlabs\Web\Controller { $searching = true; } $sql_extra .= (($searching) ? protect_sprintf(" AND xchan_name like '%$search_txt%' ") : ""); - + if($_REQUEST['gid']) { $sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) "; } - - $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash + + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ", intval(local_channel()) ); @@ -246,19 +246,27 @@ class Connections extends \Zotlabs\Web\Controller { App::set_pager_total($r[0]['total']); $total = $r[0]['total']; } - + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ORDER BY $sql_order LIMIT %d OFFSET %d ", intval(local_channel()), intval(App::$pager['itemspage']), intval(App::$pager['start']) ); - + + $roles = new Permcat(local_channel()); + $roles_list = $roles->listing(); + $roles_dict = []; + + foreach ($roles_list as $role) { + $roles_dict[$role['name']] = $role['localname']; + } + $contacts = array(); - + if($r) { - vcard_query($r); + //vcard_query($r); foreach($r as $rr) { @@ -268,7 +276,7 @@ class Connections extends \Zotlabs\Web\Controller { $phone = $rr['vcard']['tels'][0]['nr']; else $phone = ''; - + $status_str = ''; $status = array( ((intval($rr['abook_active'])) ? t('Active') : ''), @@ -306,7 +314,7 @@ class Connections extends \Zotlabs\Web\Controller { $perminfo['connperms'] .= t('Nothing'); } - + foreach($status as $str) { if(!$str) continue; @@ -314,19 +322,16 @@ class Connections extends \Zotlabs\Web\Controller { $status_str .= ', '; } $status_str = rtrim($status_str, ', '); - + $contacts[] = array( 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), 'edit_hover' => t('Edit connection'), 'edit' => t('Edit'), 'delete_hover' => t('Delete connection'), 'id' => $rr['abook_id'], - 'thumb' => $rr['xchan_photo_m'], + 'thumb' => $rr['xchan_photo_m'], 'name' => $rr['xchan_name'], 'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''), - 'link' => z_root() . '/connedit/' . $rr['abook_id'], - 'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop', - 'delete' => t('Delete'), 'url' => chanlink_hash($rr['xchan_hash']), 'webbie_label' => t('Channel address'), 'webbie' => $rr['xchan_addr'], @@ -337,6 +342,7 @@ class Connections extends \Zotlabs\Web\Controller { 'phone' => $phone, 'status_label' => t('Status'), 'status' => $status_str, + 'states' => $status, 'connected_label' => t('Connected'), 'connected' => datetime_convert('UTC',date_default_timezone_get(),$rr['abook_created'], 'c'), 'approve_hover' => t('Approve connection'), @@ -349,13 +355,22 @@ class Connections extends \Zotlabs\Web\Controller { 'perminfo' => $perminfo, 'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''), 'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0', - 'connect_hover' => t('Connect at this location') + 'connect_hover' => t('Connect at this location'), + 'role' => $roles_dict[$rr['abook_role']], + 'pending' => intval($rr['abook_pending']) ); } } } - - + + $limit = service_class_fetch(local_channel(),'total_channels'); + if($limit !== false) { + $abook_usage_message = sprintf( t("You have %1$.0f of %2$.0f allowed connections."), $$total, $limit); + } + else { + $abook_usage_message = ''; + } + if($_REQUEST['aj']) { if($contacts) { $o = replace_macros(get_markup_template('contactsajax.tpl'),array( @@ -371,27 +386,30 @@ class Connections extends \Zotlabs\Web\Controller { } else { $o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; </script>"; - $o .= replace_macros(get_markup_template('connections.tpl'),array( + $o .= replace_macros(get_markup_template('connections.tpl'), [ '$header' => t('Connections') . (($head) ? ': ' . $head : ''), '$tabs' => $tabs, '$total' => $total, '$search' => $search_hdr, '$label' => t('Search'), + '$role_label' => t('Contact role'), '$desc' => t('Search your connections'), - '$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""), + '$finding' => (($searching) ? t('Contact search') . ": '" . $search . "'" : ""), '$submit' => t('Find'), '$edit' => t('Edit'), + '$approve' => t('Approve'), '$cmd' => App::$cmd, '$contacts' => $contacts, '$paginate' => paginate($a), - - )); + '$abook_usage_message' => $abook_usage_message, + '$group_label' => t('This is a group/forum channel') + ]); } - + if(! $contacts) $o .= '<div id="content-complete"></div>'; - + return $o; } - + } diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 7fabf1224..6bebef026 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -1,4 +1,5 @@ <?php + namespace Zotlabs\Module; /* @file connedit.php @@ -8,8 +9,8 @@ namespace Zotlabs\Module; */ use App; +use Sabre\VObject\Reader; use Zotlabs\Lib\Apps; -use Zotlabs\Lib\Crypto; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libsync; use Zotlabs\Daemon\Master; @@ -18,13 +19,12 @@ use Zotlabs\Access\Permissions; use Zotlabs\Access\PermissionLimits; use Zotlabs\Web\HTTPHeaders; use Zotlabs\Lib\Permcat; +use Zotlabs\Lib\AccessList; require_once('include/socgraph.php'); require_once('include/selectors.php'); -require_once('include/group.php'); require_once('include/photos.php'); - class Connedit extends Controller { /* @brief Initialize the connection-editor @@ -34,26 +34,25 @@ class Connedit extends Controller { function init() { - if(! local_channel()) + if (!local_channel()) return; - if((argc() >= 2) && intval(argv(1))) { + if ((argc() >= 2) && intval(argv(1))) { $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d and abook_id = %d and xchan_deleted = 0 LIMIT 1", + WHERE abook_channel = %d and abook_id = %d and abook_self = 0 and xchan_deleted = 0 LIMIT 1", intval(local_channel()), intval(argv(1)) ); - if($r) { + if ($r) { App::$poi = $r[0]; } } - $channel = App::get_channel(); - if($channel) + if ($channel) { head_set_icon($channel['xchan_photo_s']); - + } } @@ -63,188 +62,98 @@ class Connedit extends Controller { function post() { - if(! local_channel()) + if (!local_channel()) return; $contact_id = intval(argv(1)); - if(! $contact_id) + if (!$contact_id) return; $channel = App::get_channel(); - // TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the - // connection enable is toggled to a special autopost url and set permissions immediately, leaving - // the other form elements alone pending a manual submit of the form. The downside is that there - // will be a window of opportunity when the permissions have been set but before you've had a chance - // to review and possibly restrict them. The upside is we won't have to warn you that your connection - // can't do anything until you save the bloody form. - - $autopost = (((argc() > 2) && (argv(2) === 'auto')) ? true : false); - - $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", intval($contact_id), intval(local_channel()) ); - if(! $orig_record) { - notice( t('Could not access contact record.') . EOL); + if (!$orig_record) { + notice(t('Could not access contact record.') . EOL); goaway(z_root() . '/connections'); return; // NOTREACHED } call_hooks('contact_edit_post', $_POST); - $vc = get_abconfig(local_channel(),$orig_record['abook_xchan'],'system','vcard'); - $vcard = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); - $serialised_vcard = update_vcard($_REQUEST,$vcard); - if($serialised_vcard) - set_abconfig(local_channel(),$orig_record[0]['abook_xchan'],'system','vcard',$serialised_vcard); - - if(intval($orig_record[0]['abook_self'])) { - $autoperms = intval($_POST['autoperms']); - $is_self = true; - } - else { - $autoperms = null; - $is_self = false; - } + $vc = get_abconfig(local_channel(), $orig_record['abook_xchan'], 'system', 'vcard'); + $vcard = (($vc) ? Reader::read($vc) : null); + $serialised_vcard = update_vcard($_REQUEST, $vcard); + if ($serialised_vcard) + set_abconfig(local_channel(), $orig_record[0]['abook_xchan'], 'system', 'vcard', $serialised_vcard); + $profile_id = ((array_key_exists('profile_assign', $_POST)) ? $_POST['profile_assign'] : $orig_record[0]['abook_profile']); - $profile_id = ((array_key_exists('profile_assign',$_POST)) ? $_POST['profile_assign'] : $orig_record[0]['abook_profile']); - - if($profile_id) { + if ($profile_id) { $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1", dbesc($profile_id), intval(local_channel()) ); - if(! count($r)) { - notice( t('Could not locate selected profile.') . EOL); + if (!count($r)) { + notice(t('Could not locate selected profile.') . EOL); return; } } - $abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']); - $abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']); - - - $hidden = intval($_POST['hidden']); + $abook_incl = ((array_key_exists('abook_incl', $_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']); + $abook_excl = ((array_key_exists('abook_excl', $_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']); + $abook_role = ((array_key_exists('permcat', $_POST)) ? escape_tags($_POST['permcat']) : $orig_record[0]['abook_role']); - $priority = intval($_POST['poll']); - if($priority > 5 || $priority < 0) - $priority = 0; - - if(! array_key_exists('closeness',$_POST)) { + if (!array_key_exists('closeness', $_POST)) { $_POST['closeness'] = 80; } $closeness = intval($_POST['closeness']); - if($closeness < 0 || $closeness > 99) { + if ($closeness < 0 || $closeness > 99) { $closeness = 80; } - $rating = intval($_POST['rating']); - if($rating < (-10)) - $rating = (-10); - if($rating > 10) - $rating = 10; - - $rating_text = trim(escape_tags($_REQUEST['rating_text'])); + $new_friend = ((intval($orig_record[0]['abook_pending'])) ? true : false); - $all_perms = Permissions::Perms(); +/* + $perms = []; + $permcats = new Permcat(local_channel()); + $role_perms = $permcats->fetch($abook_role); + $all_perms = Permissions::Perms(); - if($all_perms) { - foreach($all_perms as $perm => $desc) { - if(array_key_exists('perms_' . $perm, $_POST)) { - set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'my_perms',$perm, - intval($_POST['perms_' . $perm])); - if($autoperms) { - set_pconfig($channel['channel_id'],'autoperms',$perm,intval($_POST['perms_' . $perm])); - } - } - else { - set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'my_perms',$perm,0); - if($autoperms) { - set_pconfig($channel['channel_id'],'autoperms',$perm,0); - } - } - } + // if we got a valid role use the role (default behaviour because a role is mandatory since version 7.0) + if (!isset($role_perms['error'])) { + $perms = $role_perms['raw_perms']; + if (intval($orig_record[0]['abook_pending'])) + $new_friend = true; } - if(! is_null($autoperms)) - set_pconfig($channel['channel_id'],'system','autoperms',$autoperms); - - $new_friend = false; - - // only store a record and notify the directory if the rating changed - - if(! $is_self) { - - $signed = $orig_record[0]['abook_xchan'] . '.' . $rating . '.' . $rating_text; - $sig = base64url_encode(Crypto::sign($signed,$channel['channel_prvkey'])); - - $rated = ((intval($rating) || strlen($rating_text)) ? true : false); - - $record = 0; - - $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", - dbesc($channel['channel_hash']), - dbesc($orig_record[0]['abook_xchan']) - ); - - if($z) { - if(($z[0]['xlink_rating'] != $rating) || ($z[0]['xlink_rating_text'] != $rating_text)) { - $record = $z[0]['xlink_id']; - $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s' - where xlink_id = %d", - intval($rating), - dbesc($rating_text), - dbesc($sig), - dbesc(datetime_convert()), - intval($record) - ); - } - } - elseif($rated) { - // only create a record if there's something to save - $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", - dbesc($channel['channel_hash']), - dbesc($orig_record[0]['abook_xchan']), - intval($rating), - dbesc($rating_text), - dbesc($sig), - dbesc(datetime_convert()) - ); - $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", - dbesc($channel['channel_hash']), - dbesc($orig_record[0]['abook_xchan']) - ); - if($z) - $record = $z[0]['xlink_id']; - } - } - - if(($_REQUEST['pending']) && intval($orig_record[0]['abook_pending'])) { - + // approve shortcut (no role provided) + if (!$perms && intval($orig_record[0]['abook_pending'])) { + $connect_perms = Permissions::connect_perms(local_channel()); + $perms = $connect_perms['perms']; + // set the role from $connect_perms + $abook_role = $connect_perms['role']; $new_friend = true; + } - // @fixme it won't be common, but when you accept a new connection request - // the permissions will now be that of your permissions role and ignore - // any you may have set manually on the form. We'll probably see a bug if somebody - // tries to set the permissions *and* approve the connection in the same - // request. The workaround is to approve the connection, then go back and - // adjust permissions as desired. - - $p = Permissions::connect_perms(local_channel()); - $my_perms = $p['perms']; - if($my_perms) { - foreach($my_perms as $k => $v) { - set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'my_perms',$k,$v); + if ($all_perms && $perms) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists($perm, $perms)) { + set_abconfig($channel['channel_id'], $orig_record[0]['abook_xchan'], 'my_perms', $perm, intval($perms[$perm])); + } + else { + set_abconfig($channel['channel_id'], $orig_record[0]['abook_xchan'], 'my_perms', $perm, 0); } } } +*/ - $abook_pending = (($new_friend) ? 0 : $orig_record[0]['abook_pending']); - + \Zotlabs\Lib\Permcat::assign($channel, $abook_role, [$orig_record[0]['abook_xchan']]); + $abook_pending = (($new_friend) ? 0 : $orig_record[0]['abook_pending']); $r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d, abook_incl = '%s', abook_excl = '%s' @@ -258,30 +167,29 @@ class Connedit extends Controller { intval(local_channel()) ); - if($r) - info( t('Connection updated.') . EOL); + if ($r) + info(t('Connection updated.') . EOL); else - notice( t('Failed to update connection record.') . EOL); + notice(t('Failed to update connection record.') . EOL); - if(! intval(App::$poi['abook_self'])) { - if($new_friend) { - Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] ); + if (!intval(App::$poi['abook_self'])) { + if ($new_friend) { + Master::Summon(['Notifier', 'permission_accept', $contact_id]); } - Master::Summon( [ + Master::Summon([ 'Notifier', (($new_friend) ? 'permission_create' : 'permission_update'), $contact_id ]); } - if($new_friend) { + if ($new_friend) { $default_group = $channel['channel_default_group']; - if($default_group) { - require_once('include/group.php'); - $g = group_rec_byhash(local_channel(),$default_group); - if($g) - group_add_member(local_channel(),'',App::$poi['abook_xchan'],$g['id']); + if ($default_group) { + $g = AccessList::by_hash(local_channel(), $default_group); + if ($g) + AccessList::member_add(local_channel(), '', App::$poi['abook_xchan'], $g['id']); } // Check if settings permit ("post new friend activity" is allowed, and @@ -291,18 +199,18 @@ class Connedit extends Controller { $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", intval($channel['channel_id']) ); - if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) { + if (($pr) && (!intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) { $xarr = []; - $xarr['item_wall'] = 1; - $xarr['item_origin'] = 1; + $xarr['item_wall'] = 1; + $xarr['item_origin'] = 1; $xarr['item_thread_top'] = 1; - $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; - $xarr['allow_cid'] = $channel['channel_allow_cid']; - $xarr['allow_gid'] = $channel['channel_allow_gid']; - $xarr['deny_cid'] = $channel['channel_deny_cid']; - $xarr['deny_gid'] = $channel['channel_deny_gid']; - $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); + $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; + $xarr['allow_cid'] = $channel['channel_allow_cid']; + $xarr['allow_gid'] = $channel['channel_allow_gid']; + $xarr['deny_cid'] = $channel['channel_deny_cid']; + $xarr['deny_gid'] = $channel['channel_deny_gid']; + $xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0); $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; @@ -312,9 +220,8 @@ class Connedit extends Controller { } - // pull in a bit of content if there is any to pull in - Master::Summon(array('Onepoll',$contact_id)); + Master::Summon(['Onepoll', $contact_id]); } @@ -326,18 +233,18 @@ class Connedit extends Controller { intval(local_channel()), intval($contact_id) ); - if($r) { + if ($r) { App::$poi = $r[0]; } - if($new_friend) { - $arr = array('channel_id' => local_channel(), 'abook' => App::$poi); + if ($new_friend) { + $arr = ['channel_id' => local_channel(), 'abook' => App::$poi]; call_hooks('accept_follow', $arr); } - $this->connedit_clone($a); + $this->connedit_clone(); - if(($_REQUEST['pending']) && (!$_REQUEST['done'])) + if (($_REQUEST['pending']) && (!$_REQUEST['done'])) goaway(z_root() . '/connections/ifpending'); return; @@ -349,35 +256,34 @@ class Connedit extends Controller { * */ - function connedit_clone(&$a) { - - if(! App::$poi) - return; + function connedit_clone() { + if (!App::$poi) + return; - $channel = App::get_channel(); + $channel = App::get_channel(); - $r = q("SELECT abook.*, xchan.* + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval(App::$poi['abook_id']) - ); - if($r) { - App::$poi = array_shift($r); - } + intval(local_channel()), + intval(App::$poi['abook_id']) + ); + if ($r) { + App::$poi = $r[0]; + } - $clone = App::$poi; + $clone = App::$poi; - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if($abconfig) - $clone['abconfig'] = $abconfig; + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + if ($abconfig) + $clone['abconfig'] = $abconfig; - Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone))); + Libsync::build_sync_packet(0 /* use the current local_channel */, ['abook' => [$clone]]); } /* @brief Generate content of connection edit page @@ -387,37 +293,19 @@ class Connedit extends Controller { function get() { - $sort_type = 0; $o = ''; - if(! local_channel()) { - notice( t('Permission denied.') . EOL); + if (!local_channel()) { + notice(t('Permission denied.') . EOL); return login(); } - $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); - $channel = App::get_channel(); - - $yes_no = array(t('No'),t('Yes')); - - $connect_perms = Permissions::connect_perms(local_channel()); - - $o .= "<script>function connectDefaultShare() { - \$('.abook-edit-me').each(function() { - if(! $(this).is(':disabled')) - $(this).prop('checked', false); - });\n\n"; - foreach($connect_perms['perms'] as $p => $v) { - if($v) { - $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n"; - } - } - $o .= " }\n</script>\n"; + $section = ((array_key_exists('section', $_REQUEST)) ? $_REQUEST['section'] : ''); - if(argc() == 3) { + if (argc() == 3) { $contact_id = intval(argv(1)); - if(! $contact_id) + if (!$contact_id) return; $cmd = argv(2); @@ -428,35 +316,35 @@ class Connedit extends Controller { intval(local_channel()) ); - if(! count($orig_record)) { - notice( t('Could not access address book record.') . EOL); + if (!count($orig_record)) { + notice(t('Could not access address book record.') . EOL); goaway(z_root() . '/connections'); } - if($cmd === 'update') { + if ($cmd === 'update') { // pull feed and consume it, which should subscribe to the hub. - Master::Summon(array('Poller',$contact_id)); + Master::Summon(['Poller', $contact_id]); goaway(z_root() . '/connedit/' . $contact_id); } - if($cmd === 'fetchvc') { - $url = str_replace('/channel/','/profile/',$orig_record[0]['xchan_url']) . '/vcard'; + if ($cmd === 'fetchvc') { + $url = str_replace('/channel/', '/profile/', $orig_record[0]['xchan_url']) . '/vcard'; $recurse = 0; - $x = z_fetch_url(zid($url),false,$recurse,['session' => true]); - if($x['success']) { - $h = new HTTPHeaders($x['header']); + $x = z_fetch_url(zid($url), false, $recurse, ['session' => true]); + if ($x['success']) { + $h = new HTTPHeaders($x['header']); $fields = $h->fetch(); - if($fields) { - foreach($fields as $y) { - if(array_key_exists('content-type',$y)) { - $type = explode(';',trim($y['content-type'])); - if($type && $type[0] === 'text/vcard' && $x['body']) { - $vc = \Sabre\VObject\Reader::read($x['body']); + if ($fields) { + foreach ($fields as $y) { + if (array_key_exists('content-type', $y)) { + $type = explode(';', trim($y['content-type'])); + if ($type && $type[0] === 'text/vcard' && $x['body']) { + $vc = Reader::read($x['body']); $vcard = $vc->serialize(); - if($vcard) { - set_abconfig(local_channel(),$orig_record[0]['abook_xchan'],'system','vcard',$vcard); - $this->connedit_clone($a); + if ($vcard) { + set_abconfig(local_channel(), $orig_record[0]['abook_xchan'], 'system', 'vcard', $vcard); + $this->connedit_clone(); } } } @@ -467,55 +355,55 @@ class Connedit extends Controller { } - if($cmd === 'resetphoto') { + if ($cmd === 'resetphoto') { q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'", dbesc($orig_record[0]['xchan_hash']) ); $cmd = 'refresh'; } - if($cmd === 'refresh') { - if($orig_record[0]['xchan_network'] === 'zot6') { - if(! Libzot::refresh($orig_record[0],App::get_channel())) - notice( t('Refresh failed - channel is currently unavailable.') ); + if ($cmd === 'refresh') { + if ($orig_record[0]['xchan_network'] === 'zot6') { + if (!Libzot::refresh($orig_record[0], App::get_channel())) + notice(t('Refresh failed - channel is currently unavailable.')); } else { // if you are on a different network we'll force a refresh of the connection basic info - Master::Summon(array('Notifier','permission_update',$contact_id)); + Master::Summon(['Notifier', 'permission_update', $contact_id]); } goaway(z_root() . '/connedit/' . $contact_id); } - if($cmd === 'block') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_BLOCKED)) { - $this->connedit_clone($a); + if ($cmd === 'block') { + if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_BLOCKED)) { + $this->connedit_clone(); } else notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - if($cmd === 'ignore') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) { - $this->connedit_clone($a); + if ($cmd === 'ignore') { + if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_IGNORED)) { + $this->connedit_clone(); } else notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - if($cmd === 'archive') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) { - $this->connedit_clone($a); + if ($cmd === 'archive') { + if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_ARCHIVED)) { + $this->connedit_clone(); } else notice(t('Unable to set address book parameters.') . EOL); goaway(z_root() . '/connedit/' . $contact_id); } - if($cmd === 'hide') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_HIDDEN)) { - $this->connedit_clone($a); + if ($cmd === 'hide') { + if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_HIDDEN)) { + $this->connedit_clone(); } else notice(t('Unable to set address book parameters.') . EOL); @@ -525,10 +413,10 @@ class Connedit extends Controller { // We'll prevent somebody from unapproving an already approved contact. // Though maybe somebody will want this eventually (??) - if($cmd === 'approve') { - if(intval($orig_record[0]['abook_pending'])) { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_PENDING)) { - $this->connedit_clone($a); + if ($cmd === 'approve') { + if (intval($orig_record[0]['abook_pending'])) { + if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_PENDING)) { + $this->connedit_clone(); } else notice(t('Unable to set address book parameters.') . EOL); @@ -537,132 +425,130 @@ class Connedit extends Controller { } - if($cmd === 'drop') { + if ($cmd === 'drop') { contact_remove(local_channel(), $orig_record[0]['abook_id']); - Master::Summon( [ 'Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash'] ] ); + Master::Summon(['Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash']]); Libsync::build_sync_packet(0 /* use the current local_channel */, - array('abook' => array(array( - 'abook_xchan' => $orig_record[0]['abook_xchan'], - 'entry_deleted' => true)) - ) + ['abook' => [[ + 'abook_xchan' => $orig_record[0]['abook_xchan'], + 'entry_deleted' => true]] + ] ); - info( t('Connection has been removed.') . EOL ); - if(x($_SESSION,'return_url')) + info(t('Connection has been removed.') . EOL); + if (x($_SESSION, 'return_url')) goaway(z_root() . '/' . $_SESSION['return_url']); goaway(z_root() . '/contacts'); } } - if(App::$poi) { + if (App::$poi) { $abook_prev = 0; $abook_next = 0; - $contact_id = App::$poi['abook_id']; - $contact = App::$poi; + $contact = App::$poi; $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name", intval(local_channel()) ); - if($cn) { + if ($cn) { $pntotal = count($cn); - for($x = 0; $x < $pntotal; $x ++) { - if($cn[$x]['abook_id'] == $contact_id) { - if($x === 0) + for ($x = 0; $x < $pntotal; $x++) { + if ($cn[$x]['abook_id'] == $contact_id) { + if ($x === 0) $abook_prev = 0; else $abook_prev = $cn[$x - 1]['abook_id']; - if($x === $pntotal) + if ($x === $pntotal) $abook_next = 0; else - $abook_next = $cn[$x +1]['abook_id']; + $abook_next = $cn[$x + 1]['abook_id']; } } - } + } - $tools = array( + $tools = [ - 'view' => array( + 'view' => [ 'label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', - 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), - ), + 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name']), + ], - 'refresh' => array( + 'refresh' => [ 'label' => t('Refresh Permissions'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', 'sel' => '', 'title' => t('Fetch updated permissions'), - ), + ], - 'rephoto' => array( + 'rephoto' => [ 'label' => t('Refresh Photo'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto', 'sel' => '', 'title' => t('Fetch updated photo'), - ), + ], - 'recent' => array( + 'recent' => [ 'label' => t('Recent Activity'), 'url' => z_root() . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments'), - ), + ], - 'block' => array( + 'block' => [ 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), 'title' => t('Block (or Unblock) all communications with this connection'), - 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), - ), + 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), + ], - 'ignore' => array( + 'ignore' => [ 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), - 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), - ), + 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), + ], - 'archive' => array( + 'archive' => [ 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), - 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), - ), + 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), + ], - 'hide' => array( + 'hide' => [ 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), 'title' => t('Hide or Unhide this connection from your other connections'), - 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), - ), + 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), + ], - 'delete' => array( + 'delete' => [ 'label' => t('Delete'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection'), - ), - - ); + ], + ]; - if($contact['xchan_network'] === 'zot6') { + if ($contact['xchan_network'] === 'zot6') { $tools['fetchvc'] = [ 'label' => t('Fetch Vcard'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc', + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc', 'sel' => '', 'title' => t('Fetch electronic calling card for this connection') ]; @@ -671,31 +557,16 @@ class Connedit extends Controller { $sections = []; - $sections['perms'] = [ - 'label' => t('Permissions'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=perms', - 'sel' => '', - 'title' => t('Open Individual Permissions section by default'), - ]; - - $self = false; - - if(intval($contact['abook_self'])) { - $self = true; - $abook_prev = $abook_next = 0; - } - - $vc = get_abconfig(local_channel(),$contact['abook_xchan'],'system','vcard'); + $vc = get_abconfig(local_channel(), $contact['abook_xchan'], 'system', 'vcard'); - $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); - $vcard = (($vctmp) ? get_vcard_array($vctmp,$contact['abook_id']) : [] ); - if(! $vcard) + $vctmp = (($vc) ? Reader::read($vc) : null); + $vcard = (($vctmp) ? get_vcard_array($vctmp, $contact['abook_id']) : []); + if (!$vcard['fn']) $vcard['fn'] = $contact['xchan_name']; - $tpl = get_markup_template("abook_edit.tpl"); - if(Apps::system_app_installed(local_channel(),'Affinity Tool')) { + if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) { $sections['affinity'] = [ 'label' => t('Affinity'), @@ -711,12 +582,12 @@ class Connedit extends Controller { t('Acquaintances'), t('All') ]; - call_hooks('affinity_labels',$labels); + call_hooks('affinity_labels', $labels); $label_str = ''; - if($labels) { - foreach($labels as $l) { - if($label_str) { + if ($labels) { + foreach ($labels as $l) { + if ($label_str) { $label_str .= ", '|'"; $label_str .= ", '" . $l . "'"; } @@ -729,14 +600,14 @@ class Connedit extends Controller { $slideval = intval($contact['abook_closeness']); - $slide = replace_macros($slider_tpl,array( - '$min' => 1, - '$val' => $slideval, + $slide = replace_macros($slider_tpl, [ + '$min' => 1, + '$val' => $slideval, '$labels' => $label_str, - )); + ]); } - if(feature_enabled(local_channel(),'connfilter')) { + if (feature_enabled(local_channel(), 'connfilter')) { $sections['filter'] = [ 'label' => t('Filter'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=filter', @@ -745,195 +616,148 @@ class Connedit extends Controller { ]; } - $rating_val = 0; - $rating_text = ''; - - $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", - dbesc($channel['channel_hash']), - dbesc($contact['xchan_hash']) - ); - - if($xl) { - $rating_val = intval($xl[0]['xlink_rating']); - $rating_text = $xl[0]['xlink_rating_text']; - } - - $rating_enabled = get_config('system','rating_enabled'); - - if($rating_enabled) { - $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( - '$min' => -10, - '$val' => $rating_val - )); - } - else { - $rating = false; - } - - - $perms = array(); - $channel = App::get_channel(); - + $perms = []; $global_perms = Permissions::Perms(); + $existing = get_all_perms(local_channel(), $contact['abook_xchan'], false); + $unapproved = ['pending', t('Approve this contact'), '', t('Accept contact to allow communication'), [t('No'), ('Yes')]]; + $multiprofs = ((feature_enabled(local_channel(), 'multi_profiles')) ? true : false); - $existing = get_all_perms(local_channel(),$contact['abook_xchan'],false); - - $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'),('Yes'))); - - $multiprofs = ((feature_enabled(local_channel(),'multi_profiles')) ? true : false); - - if($slide && !$multiprofs) + if ($slide && !$multiprofs) $affinity = t('Set Affinity'); - if(!$slide && $multiprofs) + if (!$slide && $multiprofs) $affinity = t('Set Profile'); - if($slide && $multiprofs) + if ($slide && $multiprofs) $affinity = t('Set Affinity & Profile'); $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", - intval(local_channel()), - dbesc($contact['abook_xchan']) + intval(local_channel()), + dbesc($contact['abook_xchan']) ); - $their_perms = array(); - if($theirs) { - foreach($theirs as $t) { + + $their_perms = []; + if ($theirs) { + foreach ($theirs as $t) { $their_perms[$t['k']] = $t['v']; } } - foreach($global_perms as $k => $v) { - $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); -//fixme - - $checkinherited = PermissionLimits::Get(local_channel(),$k); - - // For auto permissions (when $self is true) we don't want to look at existing - // permissions because they are enabled for the channel owner - if((! $self) && ($existing[$k])) - $thisperm = "1"; - - + foreach ($global_perms as $k => $v) { + $thisperm = $existing[$k]; + $checkinherited = PermissionLimits::Get(local_channel(), $k); + $perms[] = ['perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '0' : '1'), '', $checkinherited]; + } + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $default_role = get_pconfig(local_channel(), 'system', 'default_permcat'); + $current_permcat = (($contact['abook_pending']) ? $default_role : $contact['abook_role']); - $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + if (!$current_permcat) { + notice(t('Please select a role for this contact!') . EOL); + $permcats[] = ''; } - $pcat = new Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if($pcatlist) { - foreach($pcatlist as $pc) { + if ($pcatlist) { + foreach ($pcatlist as $pc) { $permcats[$pc['name']] = $pc['localname']; } } $locstr = locations_by_netid($contact['xchan_hash']); - if(! $locstr) + if (!$locstr) { $locstr = unpunify($contact['xchan_url']); + } $clone_warn = ''; - $clonable = in_array($contact['xchan_network'], ['zot6', 'rss']); - if(! $clonable) { + $clonable = in_array($contact['xchan_network'], ['zot6', 'rss']); + if (!$clonable) { $clone_warn = '<strong>'; $clone_warn .= ((intval($contact['abook_not_here'])) - ? t('This connection is unreachable from this location.') - : t('This connection may be unreachable from other channel locations.') + ? t('This contact is unreachable from this location.') + : t('This contact may be unreachable from other channel locations.') ); $clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.'); } - - - if(intval($contact['abook_not_here']) && $unclonable) - $not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.'); - $o .= replace_macros($tpl, [ - '$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])), - '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no), - '$permcat' => [ 'permcat', t('Permission role'), '', '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>',$permcats ], - '$permcat_new' => t('Add permission role'), - '$permcat_enable' => Apps::system_app_installed(local_channel(), 'Permission Categories'), - '$addr' => unpunify($contact['xchan_addr']), - '$primeurl' => unpunify($contact['xchan_url']), - '$section' => $section, - '$sections' => $sections, - '$vcard' => $vcard, - '$addr_text' => t('This connection\'s primary address is'), - '$loc_text' => t('Available locations:'), - '$locstr' => $locstr, - '$unclonable' => $clone_warn, - '$notself' => (($self) ? '' : '1'), - '$self' => (($self) ? '1' : ''), - '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), - '$tools_label' => t('Connection Tools'), - '$tools' => (($self) ? '' : $tools), - '$lbl_slider' => t('Slide to adjust your degree of friendship'), - '$lbl_rating' => t('Rating'), - '$lbl_rating_label' => t('Slide to adjust your rating'), - '$lbl_rating_txt' => t('Optionally explain your rating'), - '$connfilter' => feature_enabled(local_channel(),'connfilter'), + '$header' => sprintf(t('Contact: %s'), $contact['xchan_name']), + '$permcat' => ['permcat', t('Contact role'), $current_permcat, '', $permcats], + '$permcat_new' => t('Manage contact roles'), + '$permcat_value' => bin2hex($current_permcat), + '$addr' => unpunify($contact['xchan_addr']), + '$primeurl' => unpunify($contact['xchan_url']), + '$section' => $section, + '$sections' => $sections, + '$vcard' => $vcard, + '$addr_text' => t('This contacts\'s primary address is'), + '$loc_text' => t('Available locations:'), + '$locstr' => $locstr, + '$unclonable' => $clone_warn, + '$notself' => '1', + '$self' => '', + '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), + '$tools_label' => t('Contact Tools'), + '$tools' => $tools, + '$lbl_slider' => t('Slide to adjust your degree of friendship'), + '$connfilter' => feature_enabled(local_channel(), 'connfilter'), '$connfilter_label' => t('Custom Filter'), - '$incl' => array('abook_incl',t('Only import posts with this text'), $contact['abook_incl'],t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), - '$excl' => array('abook_excl',t('Do not import posts with this text'), $contact['abook_excl'],t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), - '$rating_text' => array('rating_text', t('Optionally explain your rating'),$rating_text,''), - '$rating_info' => t('This information is public!'), - '$rating' => $rating, - '$rating_val' => $rating_val, - '$slide' => $slide, - '$affinity' => $affinity, - '$pending_label' => t('Connection Pending Approval'), - '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), - '$unapproved' => $unapproved, - '$inherited' => t('inherited'), - '$submit' => t('Submit'), - '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), - '$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80), - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), - '$permnote_self' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), - '$lastupdtext' => t('Last update:'), - '$last_update' => relative_date($contact['abook_connected']), - '$profile_select' => contact_profile_assign($contact['abook_profile']), - '$multiprofs' => $multiprofs, - '$contact_id' => $contact['abook_id'], - '$name' => $contact['xchan_name'], - '$abook_prev' => $abook_prev, - '$abook_next' => $abook_next, - '$vcard_label' => t('Details'), - '$displayname' => $displayname, - '$name_label' => t('Name'), - '$org_label' => t('Organisation'), - '$title_label' => t('Title'), - '$tel_label' => t('Phone'), - '$email_label' => t('Email'), - '$impp_label' => t('Instant messenger'), - '$url_label' => t('Website'), - '$adr_label' => t('Address'), - '$note_label' => t('Note'), - '$mobile' => t('Mobile'), - '$home' => t('Home'), - '$work' => t('Work'), - '$other' => t('Other'), - '$add_card' => t('Add Contact'), - '$add_field' => t('Add Field'), - '$create' => t('Create'), - '$update' => t('Update'), - '$delete' => t('Delete'), - '$cancel' => t('Cancel'), - '$po_box' => t('P.O. Box'), - '$extra' => t('Additional'), - '$street' => t('Street'), - '$locality' => t('Locality'), - '$region' => t('Region'), - '$zip_code' => t('ZIP Code'), - '$country' => t('Country') + '$incl' => ['abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$excl' => ['abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$slide' => $slide, + '$affinity' => $affinity, + '$pending_label' => t('Contact Pending Approval'), + '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), + '$unapproved' => $unapproved, + '$inherited' => t('inherited'), + '$submit' => ((intval($contact['abook_pending'])) ? t('Approve contact') : t('Submit')), + '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), + '$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80), + '$them' => t('Their'), + '$me' => t('My'), + '$perms' => $perms, + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), + '$permnote_self' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), + '$lastupdtext' => t('Last update:'), + '$last_update' => relative_date($contact['abook_connected']), + '$profile_select' => contact_profile_assign($contact['abook_profile']), + '$multiprofs' => $multiprofs, + '$contact_id' => $contact['abook_id'], + '$name' => $contact['xchan_name'], + '$abook_prev' => $abook_prev, + '$abook_next' => $abook_next, + '$vcard_label' => t('Details'), + '$name_label' => t('Name'), + '$org_label' => t('Organisation'), + '$title_label' => t('Title'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + '$po_box' => t('P.O. Box'), + '$extra' => t('Additional'), + '$street' => t('Street'), + '$locality' => t('Locality'), + '$region' => t('Region'), + '$zip_code' => t('ZIP Code'), + '$country' => t('Country') ]); - $arr = array('contact' => $contact,'output' => $o); + $arr = ['contact' => $contact, 'output' => $o]; call_hooks('contact_edit', $arr); diff --git a/Zotlabs/Module/Contactedit.php b/Zotlabs/Module/Contactedit.php new file mode 100644 index 000000000..b09b5b1ec --- /dev/null +++ b/Zotlabs/Module/Contactedit.php @@ -0,0 +1,668 @@ +<?php + +namespace Zotlabs\Module; + +/* @file Cobtactedit.php + * @brief In this file the connection-editor form is generated and evaluated. + * + * + */ + +use App; +use Sabre\VObject\Reader; +use Zotlabs\Lib\Apps; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Libsync; +use Zotlabs\Daemon\Master; +use Zotlabs\Web\Controller; +use Zotlabs\Access\Permissions; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Web\HTTPHeaders; +use Zotlabs\Lib\Permcat; +use Zotlabs\Lib\AccessList; + +require_once('include/socgraph.php'); +require_once('include/selectors.php'); +require_once('include/group.php'); +require_once('include/photos.php'); + +class Contactedit extends Controller { + + /* @brief Initialize the connection-editor + * + * + */ + + function init() { + + if (!local_channel()) + return; + + if ((argc() >= 2) && intval(argv(1))) { + $r = q("SELECT abook.*, xchan.* FROM abook LEFT JOIN xchan ON abook_xchan = xchan_hash + WHERE abook_channel = %d AND abook_id = %d AND abook_self = 0 AND xchan_deleted = 0", + intval(local_channel()), + intval(argv(1)) + ); + if (!$r) { + json_return_and_die([ + 'success' => false, + 'message' => t('Invalid abook_id') + ]); + } + + App::$poi = $r[0]; + + } + } + + + /* @brief Evaluate posted values and set changes + * + */ + + function post() { + + if (!local_channel()) + return; + + $contact_id = intval(argv(1)); + if (!$contact_id) + return; + + $channel = App::get_channel(); + + $contact = App::$poi; + + if (!$contact) { + notice(t('Could not access contact record.') . EOL); + killme(); + } + + call_hooks('contact_edit_post', $_REQUEST); + + if (Apps::system_app_installed(local_channel(), 'Privacy Groups')) { + $pgrp_ids = q("SELECT id FROM pgrp WHERE deleted = 0 AND uid = %d", + intval(local_channel()) + ); + + foreach($pgrp_ids as $pgrp) { + if (array_key_exists('pgrp_id_' . $pgrp['id'], $_REQUEST)) { + AccessList::member_add(local_channel(), '', $contact['abook_xchan'], $pgrp['id']); + } + else { + AccessList::member_remove(local_channel(), '', $contact['abook_xchan'], $pgrp['id']); + } + } + } + + $profile_id = ((array_key_exists('profile_assign', $_REQUEST)) ? $_REQUEST['profile_assign'] : $contact['abook_profile']); + + if ($profile_id) { + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1", + dbesc($profile_id), + intval(local_channel()) + ); + if (!count($r)) { + notice(t('Could not locate selected profile.') . EOL); + return; + } + } + + $abook_incl = ((array_key_exists('abook_incl', $_REQUEST)) ? escape_tags($_REQUEST['abook_incl']) : $contact['abook_incl']); + $abook_excl = ((array_key_exists('abook_excl', $_REQUEST)) ? escape_tags($_REQUEST['abook_excl']) : $contact['abook_excl']); + $abook_role = ((array_key_exists('permcat', $_REQUEST)) ? escape_tags($_REQUEST['permcat']) : $contact['abook_role']); + + if (!array_key_exists('closeness', $_REQUEST)) { + $_REQUEST['closeness'] = 80; + } + + $closeness = intval($_REQUEST['closeness']); + + if ($closeness < 0 || $closeness > 99) { + $closeness = 80; + } + + $new_friend = ((intval($contact['abook_pending'])) ? true : false); + + \Zotlabs\Lib\Permcat::assign($channel, $abook_role, [$contact['abook_xchan']]); + + $abook_pending = (($new_friend) ? 0 : $contact['abook_pending']); + + $r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d, + abook_incl = '%s', abook_excl = '%s' + where abook_id = %d AND abook_channel = %d", + dbesc($profile_id), + intval($closeness), + intval($abook_pending), + dbesc($abook_incl), + dbesc($abook_excl), + intval($contact_id), + intval(local_channel()) + ); + + $_REQUEST['success'] = false; + + if ($r) { + $_REQUEST['success'] = true; + } + + + if (!intval($contact['abook_self'])) { + if ($new_friend) { + Master::Summon(['Notifier', 'permission_accept', $contact_id]); + } + + Master::Summon([ + 'Notifier', + (($new_friend) ? 'permission_create' : 'permission_update'), + $contact_id + ]); + } + + if ($new_friend) { + $default_group = $channel['channel_default_group']; + if ($default_group) { + $g = AccessList::by_hash(local_channel(), $default_group); + if ($g) { + AccessList::member_add(local_channel(), '', $contact['abook_xchan'], $g['id']); + } + } + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + + $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", + intval($channel['channel_id']) + ); + if (($pr) && (!intval($contact['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) { + $xarr = []; + + $xarr['item_wall'] = 1; + $xarr['item_origin'] = 1; + $xarr['item_thread_top'] = 1; + $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; + $xarr['allow_cid'] = $channel['channel_allow_cid']; + $xarr['allow_gid'] = $channel['channel_allow_gid']; + $xarr['deny_cid'] = $channel['channel_deny_cid']; + $xarr['deny_gid'] = $channel['channel_deny_gid']; + $xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0); + + $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . $contact['xchan_url'] . ']' . $contact['xchan_name'] . '[/zrl]'; + + $xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=80x80]' . $contact['xchan_photo_m'] . '[/zmg][/zrl]'; + + post_activity_item($xarr); + + } + + // pull in a bit of content if there is any to pull in + Master::Summon(['Onepoll', $contact_id]); + + } + + // Refresh the structure in memory with the new data + $this->init(); + + if ($new_friend) { + $arr = ['channel_id' => local_channel(), 'abook' => App::$poi]; + call_hooks('accept_follow', $arr); + } + + $this->contactedit_clone(); + $this->get(); + + killme(); + + return; + + } + + + /* @brief Generate content of contact edit page + * + * + */ + + function get() { + + if (!local_channel()) { + killme(); + } + + if (!App::$poi) { + killme(); + } + + + $channel = App::get_channel(); + $contact_id = App::$poi['abook_id']; + $contact = App::$poi; + $section = ((array_key_exists('section', $_REQUEST)) ? $_REQUEST['section'] : 'roles'); + $sub_section = ((array_key_exists('sub_section', $_REQUEST)) ? $_REQUEST['sub_section'] : ''); + + + if (argc() == 3) { + $cmd = argv(2); + $ret = $this->do_action($contact, $cmd); + $contact = App::$poi; + + $tools_html = replace_macros(get_markup_template("contact_edit_tools.tpl"), [ + '$tools_label' => t('Contact Tools'), + '$tools' => $this->get_tools($contact), + ]); + + $ret['tools'] = $tools_html; + + json_return_and_die($ret); + } + + $groups = []; + + if (Apps::system_app_installed(local_channel(), 'Privacy Groups')) { + + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + intval(local_channel()) + ); + + $member_of = AccessList::containing(local_channel(), $contact['xchan_hash']); + + if ($r) { + foreach ($r as $rr) { + $default_group = false; + if ($rr['hash'] === $channel['channel_default_group']) { + $default_group = true; + } + + $groups[] = [ + 'pgrp_id_' . $rr['id'], + $rr['gname'], + // if it's a new contact preset the default group if we have one + (($default_group && $contact['abook_pending']) ? 1 : in_array($rr['id'], $member_of)), + '', + [t('No'), t('Yes')] + ]; + } + } + } + + $slide = ''; + + if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) { + + $labels = [ + t('Me'), + t('Family'), + t('Friends'), + t('Acquaintances'), + t('All') + ]; + call_hooks('affinity_labels', $labels); + $label_str = ''; + + if ($labels) { + foreach ($labels as $l) { + if ($label_str) { + $label_str .= ", '|'"; + $label_str .= ", '" . $l . "'"; + } + else + $label_str .= "'" . $l . "'"; + } + } + + $slider_tpl = get_markup_template('contact_slider.tpl'); + + $slideval = intval($contact['abook_closeness']); + + $slide = replace_macros($slider_tpl, [ + '$min' => 1, + '$val' => $slideval, + '$labels' => $label_str, + ]); + } + + $perms = []; + $global_perms = Permissions::Perms(); + $existing = get_all_perms(local_channel(), $contact['abook_xchan'], false); + $unapproved = ['pending', t('Approve this contact'), '', t('Accept contact to allow communication'), [t('No'), ('Yes')]]; + $multiprofs = ((feature_enabled(local_channel(), 'multi_profiles')) ? true : false); + + $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", + intval(local_channel()), + dbesc($contact['abook_xchan']) + ); + + $their_perms = []; + if ($theirs) { + foreach ($theirs as $t) { + $their_perms[$t['k']] = $t['v']; + } + } + + foreach ($global_perms as $k => $v) { + $thisperm = $existing[$k]; + $checkinherited = PermissionLimits::Get(local_channel(), $k); + $perms[] = ['perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '0' : '1'), '', $checkinherited]; + } + + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $default_role = get_pconfig(local_channel(), 'system', 'default_permcat'); + $current_permcat = (($contact['abook_pending']) ? $default_role : $contact['abook_role']); + + $roles_dict = []; + foreach ($pcatlist as $role) { + $roles_dict[$role['name']] = $role['localname']; + } + + + if (!$current_permcat) { + notice(t('Please select a role for this contact!') . EOL); + $permcats[] = ''; + } + + if ($pcatlist) { + foreach ($pcatlist as $pc) { + $permcats[$pc['name']] = $pc['localname']; + } + } + + $locstr = locations_by_netid($contact['xchan_hash']); + if (!$locstr) { + $locstr = unpunify($contact['xchan_url']); + } + + $clone_warn = ''; + $clonable = in_array($contact['xchan_network'], ['zot6', 'rss']); + if (!$clonable) { + $clone_warn = '<strong>'; + $clone_warn .= ((intval($contact['abook_not_here'])) + ? t('This contact is unreachable from this location.') + : t('This contact may be unreachable from other channel locations.') + ); + $clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.'); + } + + $header_card = '<img src="' . $contact['xchan_photo_s'] . '" class="rounded" style="width: 3rem; height: 3rem;"> ' . $contact['xchan_name']; + + $header_html = replace_macros(get_markup_template("contact_edit_header.tpl"), [ + '$img_src' => $contact['xchan_photo_s'], + '$name' => $contact['xchan_name'], + '$addr' => (($contact['xchan_addr']) ? $contact['xchan_addr'] : $contact['xchan_url']), + '$href' => ((is_matrix_url($contact['xchan_url'])) ? zid($contact['xchan_url']) : $contact['xchan_url']), + '$link_label' => t('View profile'), + '$is_group' => $contact['xchan_pubforum'], + '$group_label' => t('This is a group/forum channel') + ]); + + $tools_html = replace_macros(get_markup_template("contact_edit_tools.tpl"), [ + '$tools_label' => t('Contact Tools'), + '$tools' => $this->get_tools($contact), + ]); + + $tpl = get_markup_template("contact_edit.tpl"); + + $o = replace_macros($tpl, [ + '$permcat' => ['permcat', t('Select a role for this contact'), $current_permcat, '', $permcats], + '$permcat_new' => t('Contact roles'), + '$permcat_value' => bin2hex($current_permcat), +// '$addr' => unpunify($contact['xchan_addr']), +// '$primeurl' => unpunify($contact['xchan_url']), + '$section' => $section, + '$sub_section' => $sub_section, + '$groups' => $groups, +// '$addr_text' => t('This contacts\'s primary address is'), +// '$loc_text' => t('Available locations:'), +// '$locstr' => $locstr, +// '$unclonable' => $clone_warn, + '$lbl_slider' => t('Slide to adjust your degree of friendship'), + '$connfilter' => feature_enabled(local_channel(), 'connfilter'), + '$connfilter_label' => t('Custom Filter'), + '$incl' => ['abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$excl' => ['abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$slide' => $slide, +// '$pending_label' => t('Contact Pending Approval'), +// '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), +// '$unapproved' => $unapproved, + '$submit' => ((intval($contact['abook_pending'])) ? t('Approve contact') : t('Submit')), + '$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80), + '$them' => t('Their'), + '$me' => t('My'), + '$perms' => $perms, +// '$lastupdtext' => t('Last update:'), +// '$last_update' => relative_date($contact['abook_connected']), + '$profile_select' => contact_profile_assign($contact['abook_profile']), + '$multiprofs' => $multiprofs, + '$contact_id' => $contact['abook_id'], +// '$name' => $contact['xchan_name'], + ]); + + $arr = ['contact' => $contact, 'output' => $o]; + + call_hooks('contact_edit', $arr); + + if (is_ajax()) { + json_return_and_die([ + 'success' => ((intval($_REQUEST['success'])) ? intval($_REQUEST['success']) : 1), + 'message' => (($_REQUEST['success']) ? t('Contact updated') : t('Contact update failed')), + 'id' => $contact_id, + 'title' => $header_html, + 'role' => ((intval($contact['abook_pending'])) ? '' : $roles_dict[$current_permcat]), + 'body' => $arr['output'], + 'tools' => $tools_html, + 'submit' => ((intval($contact['abook_pending'])) ? t('Approve connection') : t('Submit')), + 'pending' => intval($contact['abook_pending']) + ]); + } + + return $arr['output']; + + } + + function contactedit_clone() { + + if (!App::$poi) + return; + + $channel = App::get_channel(); + + $clone = App::$poi; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + if ($abconfig) + $clone['abconfig'] = $abconfig; + + Libsync::build_sync_packet(0 /* use the current local_channel */, ['abook' => [$clone]]); + } + + function do_action($contact, $cmd) { + $ret = [ + 'sucess' => false, + 'message' => '' + ]; + + if ($cmd === 'resetphoto') { + q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'", + dbesc($contact['xchan_hash']) + ); + $cmd = 'refresh'; + } + + if ($cmd === 'refresh') { + if ($contact['xchan_network'] === 'zot6') { + if (Libzot::refresh($contact, App::get_channel())) { + $ret['success'] = true; + $ret['message'] = t('Refresh succeeded'); + } + else { + $ret['message'] = t('Refresh failed - channel is currently unavailable'); + } + } + else { + // if you are on a different network we'll force a refresh of the connection basic info + Master::Summon(['Notifier', 'permission_update', $contact['abook_id']]); + $ret['success'] = true; + $ret['message'] = t('Refresh succeeded'); + } + + return $ret; + } + + if ($cmd === 'block') { + if (abook_toggle_flag($contact, ABOOK_FLAG_BLOCKED)) { + $this->init(); // refresh data + + $this->contactedit_clone(); + $ret['success'] = true; + $ret['message'] = t('Block status updated'); + } + else { + $ret['success'] = false; + $ret['message'] = t('Block failed'); + } + return $ret; + } + + if ($cmd === 'ignore') { + if (abook_toggle_flag($contact, ABOOK_FLAG_IGNORED)) { + $this->init(); // refresh data + + $this->contactedit_clone(); + $ret['success'] = true; + $ret['message'] = t('Ignore status updated'); + } + else { + $ret['success'] = false; + $ret['message'] = t('Ignore failed'); + } + return $ret; + } + + if ($cmd === 'archive') { + if (abook_toggle_flag($contact, ABOOK_FLAG_ARCHIVED)) { + $this->init(); // refresh data + + $this->contactedit_clone(); + $ret['success'] = true; + $ret['message'] = t('Archive status updated'); + } + else { + $ret['success'] = false; + $ret['message'] = t('Archive failed'); + } + return $ret; + } + + if ($cmd === 'hide') { + if (abook_toggle_flag($contact, ABOOK_FLAG_HIDDEN)) { + $this->init(); // refresh data + + $this->contactedit_clone(); + $ret['success'] = true; + $ret['message'] = t('Hide status updated'); + } + else { + $ret['success'] = false; + $ret['message'] = t('Hide failed'); + } + return $ret; + } + + // We'll prevent somebody from unapproving an already approved contact. + // Though maybe somebody will want this eventually (??) + + //if ($cmd === 'approve') { + //if (intval($contact['abook_pending'])) { + //if (abook_toggle_flag($contact, ABOOK_FLAG_PENDING)) { + //$this->contactedit_clone(); + //} + //else + //notice(t('Unable to set address book parameters.') . EOL); + //} + //goaway(z_root() . '/connedit/' . $contact_id); + //} + + + if ($cmd === 'drop') { + + if (contact_remove(local_channel(), $contact['abook_id'])) { + + Master::Summon(['Notifier', 'purge', local_channel(), $contact['xchan_hash']]); + Libsync::build_sync_packet(0 /* use the current local_channel */, + ['abook' => [ + [ + 'abook_xchan' => $contact['abook_xchan'], + 'entry_deleted' => true + ] + ] + ]); + + $ret['success'] = true; + $ret['message'] = t('Contact removed'); + } + else { + $ret['success'] = false; + $ret['message'] = t('Delete failed'); + } + return $ret; + } + } + + function get_tools($contact) { + return [ + + 'refresh' => [ + 'label' => t('Refresh Permissions'), + 'title' => t('Fetch updated permissions'), + ], + + 'rephoto' => [ + 'label' => t('Refresh Photo'), + 'title' => t('Fetch updated photo'), + ], + + + 'block' => [ + 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), + 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), + 'title' => t('Block (or Unblock) all communications with this connection'), + 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), + ], + + 'ignore' => [ + 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), + 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), + 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), + 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), + ], + + 'archive' => [ + 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), + 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), + 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), + 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), + ], + + 'hide' => [ + 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), + 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), + 'title' => t('Hide or Unhide this connection from your other connections'), + 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), + ], + + 'delete' => [ + 'label' => t('Delete'), + 'sel' => '', + 'title' => t('Delete this connection'), + ], + + ]; + } + +} diff --git a/Zotlabs/Module/Contactgroup.php b/Zotlabs/Module/Contactgroup.php index 36aaf7da0..3e88179fb 100644 --- a/Zotlabs/Module/Contactgroup.php +++ b/Zotlabs/Module/Contactgroup.php @@ -1,17 +1,17 @@ <?php namespace Zotlabs\Module; -require_once('include/group.php'); +use Zotlabs\Lib\AccessList; +use Zotlabs\Web\Controller; - -class Contactgroup extends \Zotlabs\Web\Controller { +class Contactgroup extends Controller { function get() { - + if(! local_channel()) { killme(); } - + if((argc() > 2) && (intval(argv(1))) && (argv(2))) { $r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc(base64url_decode(argv(2))), @@ -20,9 +20,9 @@ class Contactgroup extends \Zotlabs\Web\Controller { if($r) $change = $r[0]['abook_xchan']; } - + if((argc() > 1) && (intval(argv(1)))) { - + $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1", intval(argv(1)), intval(local_channel()) @@ -30,25 +30,25 @@ class Contactgroup extends \Zotlabs\Web\Controller { if(! $r) { killme(); } - + $group = $r[0]; - $members = group_get_members($group['id']); + $members = AccessList::members(local_channel(), $group['id']); $preselected = array(); if(count($members)) { foreach($members as $member) $preselected[] = $member['xchan_hash']; } - + if($change) { if(in_array($change,$preselected)) { - group_rmv_member(local_channel(),$group['gname'],$change); + AccessList::member_remove(local_channel(),$group['gname'],$change); } else { - group_add_member(local_channel(),$group['gname'],$change); + AccessList::member_add(local_channel(),$group['gname'],$change); } } } - + killme(); } } diff --git a/Zotlabs/Module/Defperms.php b/Zotlabs/Module/Defperms.php index 309a5a65a..70270d36b 100644 --- a/Zotlabs/Module/Defperms.php +++ b/Zotlabs/Module/Defperms.php @@ -8,7 +8,6 @@ use Zotlabs\Lib\Libsync; require_once('include/socgraph.php'); require_once('include/selectors.php'); -require_once('include/group.php'); require_once('include/photos.php'); class Defperms extends Controller { @@ -23,8 +22,8 @@ class Defperms extends Controller { if(! local_channel()) return; - if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) - return; + //if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) + // return; $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash @@ -50,8 +49,8 @@ class Defperms extends Controller { if(! local_channel()) return; - if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) - return; + //if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) + // return; $contact_id = intval(argv(1)); if(! $contact_id) @@ -183,12 +182,12 @@ class Defperms extends Controller { return login(); } - if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) { - //Do not display any associated widgets at this point - App::$pdl = ''; - $papp = Apps::get_papp('Default Permissions'); - return Apps::app_render($papp, 'module'); - } + //~ if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) { + //~ //Do not display any associated widgets at this point + //~ App::$pdl = ''; + //~ $papp = Apps::get_papp('Default Permissions'); + //~ return Apps::app_render($papp, 'module'); + //~ } $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); $channel = App::get_channel(); diff --git a/Zotlabs/Module/Follow.php b/Zotlabs/Module/Follow.php index 4fe20f56b..94daa4c70 100644 --- a/Zotlabs/Module/Follow.php +++ b/Zotlabs/Module/Follow.php @@ -108,7 +108,7 @@ class Follow extends Controller { } Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true); - $can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream'); + $can_view_stream = intval(get_abconfig($channel['channel_id'], $clone['abook_xchan'], 'their_perms', 'view_stream')); // If we can view their stream, pull in some posts @@ -117,7 +117,7 @@ class Follow extends Controller { } if ($interactive) { - goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1'); + goaway(z_root() . '/connections#' . $result['abook']['abook_id']); } else { json_return_and_die([ 'success' => true ]); diff --git a/Zotlabs/Module/Group.php b/Zotlabs/Module/Group.php index a2d55a325..1dce08757 100644 --- a/Zotlabs/Module/Group.php +++ b/Zotlabs/Module/Group.php @@ -5,8 +5,7 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; - -require_once('include/group.php'); +use Zotlabs\Lib\AccessList; class Group extends Controller { @@ -41,16 +40,17 @@ class Group extends Controller { $name = notags(trim($_POST['groupname'])); $public = intval($_POST['public']); - $r = group_add(local_channel(),$name,$public); + $r = AccessList::add(local_channel(),$name,$public); + $group_hash = $r; + if($r) { info( t('Privacy group created.') . EOL ); } else { notice( t('Could not create privacy group.') . EOL ); } - goaway(z_root() . '/group'); - } + if((argc() == 2) && (intval(argv(1)))) { check_form_security_token_redirectOnErr('/group', 'group_edit'); @@ -65,10 +65,11 @@ class Group extends Controller { } $group = $r[0]; $groupname = notags(trim($_POST['groupname'])); + $group_hash = $group['hash']; $public = intval($_POST['public']); $hookinfo = [ 'pgrp_extras' => '', 'group'=>$group['id'] ]; - call_hooks ('privacygroup_extras_post',$hookinfo); + call_hooks('privacygroup_extras_post',$hookinfo); if((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) { $r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d", @@ -79,13 +80,25 @@ class Group extends Controller { ); if($r) info( t('Privacy group updated.') . EOL ); + } + } + $channel = App::get_channel(); - Libsync::build_sync_packet(local_channel(),null,true); - } + $default_group = ((isset($_POST['set_default_group'])) ? $group_hash : (($channel['channel_default_group'] === $group_hash) ? '' : $channel['channel_default_group'])); + $default_acl = ((isset($_POST['set_default_acl'])) ? '<' . $group_hash . '>' : (($channel['channel_allow_gid'] === '<' . $group_hash . '>') ? '' : $channel['channel_allow_gid'])); + + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' + where channel_id = %d", + dbesc($default_group), + dbesc($default_acl), + intval(local_channel()) + ); + + Libsync::build_sync_packet(local_channel(),null,true); + + goaway(z_root() . '/group/' . argv(1) . ((argv(2)) ? '/' . argv(2) : '')); - goaway(z_root() . '/group/' . argv(1) . '/' . argv(2)); - } return; } @@ -117,51 +130,32 @@ class Group extends Controller { if((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) { - $new = (((argc() == 2) && (argv(1) === 'new')) ? true : false); - - $groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval(local_channel()) - ); - - $i = 0; - foreach($groups as $group) { - $entries[$i]['name'] = $group['gname']; - $entries[$i]['id'] = $group['id']; - $entries[$i]['count'] = count(group_get_members($group['id'])); - $i++; - } - $hookinfo = [ 'pgrp_extras' => '', 'group'=>argv(1) ]; call_hooks ('privacygroup_extras',$hookinfo); $pgrp_extras = $hookinfo['pgrp_extras']; + $is_default_acl = ['set_default_acl', t('Post to this group by default'), 0, '', [t('No'), t('Yes')]]; + $is_default_group = ['set_default_group', t('Add new contacts to this group by default'), 0, '', [t('No'), t('Yes')]]; + + $tpl = get_markup_template('privacy_groups.tpl'); $o = replace_macros($tpl, [ '$title' => t('Privacy Groups'), - '$add_new_label' => t('Add Group'), - '$new' => $new, // new group form '$gname' => array('groupname',t('Privacy group name')), - '$public' => array('public',t('Members are visible to other channels'), false), + '$public' => array('public',t('Members are visible to other channels'), 0, '', [t('No'), t('Yes')]), '$pgrp_extras' => $pgrp_extras, '$form_security_token' => get_form_security_token("group_edit"), '$submit' => t('Submit'), - - // groups list - '$title' => t('Privacy Groups'), - '$name_label' => t('Name'), - '$count_label' => t('Members'), - '$entries' => $entries + '$is_default_acl' => $is_default_acl, + '$is_default_group' => $is_default_group, ]); return $o; } - - - $context = array('$submit' => t('Submit')); $tpl = get_markup_template('group_edit.tpl'); @@ -174,7 +168,7 @@ class Group extends Controller { intval(local_channel()) ); if($r) - $result = group_rmv(local_channel(),$r[0]['gname']); + $result = AccessList::remove(local_channel(),$r[0]['gname']); if($result) { $hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ]; call_hooks ('privacygroup_extras_drop',$hookinfo); @@ -215,7 +209,7 @@ class Group extends Controller { $group = $r[0]; - $members = group_get_members($group['id']); + $members = AccessList::members(local_channel(), $group['id']); $preselected = array(); if(count($members)) { @@ -227,13 +221,13 @@ class Group extends Controller { if($change) { if(in_array($change,$preselected)) { - group_rmv_member(local_channel(),$group['gname'],$change); + AccessList::member_remove(local_channel(),$group['gname'],$change); } else { - group_add_member(local_channel(),$group['gname'],$change); + AccessList::member_add(local_channel(),$group['gname'],$change); } - $members = group_get_members($group['id']); + $members = AccessList::members(local_channel(), $group['id']); $preselected = array(); if(count($members)) { @@ -252,9 +246,9 @@ class Group extends Controller { '$gname' => array('groupname',t('Privacy group name: '),$group['gname'], ''), '$gid' => $group['id'], '$drop' => $drop_txt, - '$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''), + '$public' => array('public',t('Members are visible to other channels'), $group['visible'], '', [t('No'), t('Yes')]), '$form_security_token_edit' => get_form_security_token('group_edit'), - '$delete' => t('Delete Group'), + '$delete' => t('Delete'), '$form_security_token_drop' => get_form_security_token("group_drop"), '$pgrp_extras' => $pgrp_extras, ); @@ -280,7 +274,7 @@ class Group extends Controller { $groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode); } else - group_rmv_member(local_channel(),$group['gname'],$member['xchan_hash']); + AccessList::member_remove(local_channel(),$group['gname'],$member['xchan_hash']); } $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", @@ -302,6 +296,12 @@ class Group extends Controller { $context['$desc'] = t('Click a channel to toggle membership'); $context['$pgrp_extras'] = $pgrp_extras; + $channel = App::get_channel(); + + $context['$is_default_acl'] = ['set_default_acl', t('Post to this group by default'), intval($group['hash'] === trim($channel['channel_allow_gid'], '<>')), '', [t('No'), t('Yes')]]; + $context['$is_default_group'] = ['set_default_group', t('Add new contacts to this group by default'), intval($group['hash'] === $channel['channel_default_group']), '', [t('No'), t('Yes')]]; + + if($change) { $tpl = get_markup_template('groupeditor.tpl'); echo replace_macros($tpl, $context); diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php index e05027d9f..869de2669 100644 --- a/Zotlabs/Module/Impel.php +++ b/Zotlabs/Module/Impel.php @@ -1,5 +1,9 @@ <?php -namespace Zotlabs\Module; /** @file */ +namespace Zotlabs\Module; + +use URLify; + +/** @file */ // import page design element @@ -9,33 +13,33 @@ require_once('include/menu.php'); class Impel extends \Zotlabs\Web\Controller { function init() { - + $ret = array('success' => false); - + if(! local_channel()) json_return_and_die($ret); - + logger('impel: ' . print_r($_REQUEST,true), LOGGER_DATA); - + $elm = $_REQUEST['element']; $x = base64url_decode($elm); if(! $x) json_return_and_die($ret); - + $j = json_decode($x,true); if(! $j) json_return_and_die($ret); - + // logger('element: ' . print_r($j,true)); $channel = \App::get_channel(); - + $arr = array(); $is_menu = false; - + // a portable menu has its links rewritten with the local baseurl $portable_menu = false; - + switch($j['type']) { case 'webpage': $arr['item_type'] = ITEM_TYPE_WEBPAGE; @@ -58,12 +62,12 @@ class Impel extends \Zotlabs\Web\Controller { case 'menu': $is_menu = true; $installed_type = t('menu'); - break; + break; default: logger('mod_impel: unrecognised element type' . print_r($j,true)); break; } - + if($is_menu) { $m = array(); $m['menu_channel_id'] = local_channel(); @@ -73,23 +77,23 @@ class Impel extends \Zotlabs\Web\Controller { $m['menu_created'] = datetime_convert($j['created']); if($j['edited']) $m['menu_edited'] = datetime_convert($j['edited']); - + $m['menu_flags'] = 0; if($j['flags']) { if(in_array('bookmark',$j['flags'])) $m['menu_flags'] |= MENU_BOOKMARK; if(in_array('system',$j['flags'])) $m['menu_flags'] |= MENU_SYSTEM; - + } - + $menu_id = menu_create($m); - + if($menu_id) { if(is_array($j['items'])) { foreach($j['items'] as $it) { $mitem = array(); - + $mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']); $mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']); $mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']); @@ -115,7 +119,7 @@ class Impel extends \Zotlabs\Web\Controller { intval(local_channel()) ); } - } + } $ret['success'] = true; } $x = $ret; @@ -132,22 +136,21 @@ class Impel extends \Zotlabs\Web\Controller { $arr['owner_xchan'] = get_observer_hash(); $arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash()); $arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode'); - + if(! $j['mid']) { $j['uuid'] = item_message_id(); $j['mid'] = z_root() . '/item/' . $j['uuid']; } $arr['uuid'] = $j['uuid']; $arr['mid'] = $arr['parent_mid'] = $j['mid']; - - + + if($j['pagetitle']) { - require_once('library/urlify/URLify.php'); - $pagetitle = strtolower(\URLify::transliterate($j['pagetitle'])); + $pagetitle = strtolower(URLify::transliterate($j['pagetitle'])); } - + // Verify ability to use html or php!!! - + $execflag = ((intval($channel['channel_id']) == intval(local_channel()) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", @@ -156,7 +159,7 @@ class Impel extends \Zotlabs\Web\Controller { ); \Zotlabs\Lib\IConfig::Set($arr,'system',$namespace,(($pagetitle) ? $pagetitle : substr($arr['mid'],0,16)),true); - + if($i) { $arr['id'] = $i[0]['id']; // don't update if it has the same timestamp as the original @@ -174,24 +177,24 @@ class Impel extends \Zotlabs\Web\Controller { else $x = item_store($arr,$execflag); } - + if($x && $x['success']) { $item_id = $x['item_id']; } } - + if($x['success']) { $ret['success'] = true; - info( sprintf( t('%s element installed'), $installed_type)); + info( sprintf( t('%s element installed'), $installed_type)); } else { - notice( sprintf( t('%s element installation failed'), $installed_type)); + notice( sprintf( t('%s element installation failed'), $installed_type)); } - - //??? should perhaps return ret? + + //??? should perhaps return ret? json_return_and_die(true); - + } - + } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index c4c844b25..ec47e370b 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -5,14 +5,12 @@ namespace Zotlabs\Module; require_once('include/channel.php'); require_once('include/import.php'); require_once('include/perm_upgrade.php'); -require_once('library/urlify/URLify.php'); use App; +use URLify; use Zotlabs\Daemon\Master; use Zotlabs\Lib\Libzot; use Zotlabs\Web\Controller; -use Zotlabs\Web\HTTPSig; -use Zotlabs\Lib\PConfig; /** @@ -35,17 +33,17 @@ class Import extends Controller { return; } - $max_friends = account_service_class_fetch($account_id, 'total_channels'); - $max_feeds = account_service_class_fetch($account_id, 'total_feeds'); - $data = null; - $seize = ((x($_REQUEST, 'make_primary')) ? intval($_REQUEST['make_primary']) : 0); + $max_friends = account_service_class_fetch($account_id, 'total_channels'); + $max_feeds = account_service_class_fetch($account_id, 'total_feeds'); + $data = null; + $seize = ((x($_REQUEST, 'make_primary')) ? intval($_REQUEST['make_primary']) : 0); $import_posts = ((x($_REQUEST, 'import_posts')) ? intval($_REQUEST['import_posts']) : 0); - $moving = false; //intval($_REQUEST['moving']); - $src = $_FILES['filename']['tmp_name']; - $filename = basename($_FILES['filename']['name']); - $filesize = intval($_FILES['filename']['size']); - $filetype = $_FILES['filename']['type']; - $newname = trim(strtolower($_REQUEST['newname'])); + $moving = false; //intval($_REQUEST['moving']); + $src = $_FILES['filename']['tmp_name']; + $filename = basename($_FILES['filename']['name']); + $filesize = intval($_FILES['filename']['size']); + $filetype = $_FILES['filename']['type']; + $newname = trim(strtolower($_REQUEST['newname'])); // import channel from file if ($src) { @@ -71,16 +69,17 @@ class Import extends Controller { logger('Nothing to import.'); notice(t('Nothing to import.') . EOL); return; - } else if (strpos($old_address, 'ï¼ ')) { + } + else if (strpos($old_address, 'ï¼ ')) { // if you copy the identity address from your profile page, make it work for convenience - WARNING: this is a utf-8 variant and NOT an ASCII ampersand. Please do not edit. $old_address = str_replace('ï¼ ', '@', $old_address); } - $email = ((x($_REQUEST, 'email')) ? $_REQUEST['email'] : ''); + $email = ((x($_REQUEST, 'email')) ? $_REQUEST['email'] : ''); $password = ((x($_REQUEST, 'password')) ? $_REQUEST['password'] : ''); $channelname = substr($old_address, 0, strpos($old_address, '@')); - $servername = substr($old_address, strpos($old_address, '@') + 1); + $servername = substr($old_address, strpos($old_address, '@') + 1); $api_path = probe_api_path($servername); if (!$api_path) { @@ -90,13 +89,14 @@ class Import extends Controller { $api_path .= 'channel/export/basic?f=&channel=' . $channelname; - $binary = false; + $binary = false; $redirects = 0; - $opts = array('http_auth' => $email . ':' . $password); - $ret = z_fetch_url($api_path, $binary, $redirects, $opts); + $opts = ['http_auth' => $email . ':' . $password]; + $ret = z_fetch_url($api_path, $binary, $redirects, $opts); if ($ret['success']) { $data = $ret['body']; - } else { + } + else { notice(t('Unable to download data from old server') . EOL); return; } @@ -173,14 +173,15 @@ class Import extends Controller { } if ((!$x) || strlen($x) > 64) { - $x = strtolower(\URLify::transliterate($newname)); + $x = strtolower(URLify::transliterate($newname)); } $newname = $x; } $channel = import_channel($data['channel'], $account_id, $seize, $newname); - } else { - $moving = false; + } + else { + $moving = false; $channel = App::get_channel(); } @@ -216,20 +217,20 @@ class Import extends Controller { $r = hubloc_store_lowlevel( [ - 'hubloc_guid' => $channel['channel_guid'], + 'hubloc_guid' => $channel['channel_guid'], 'hubloc_guid_sig' => $channel['channel_guid_sig'], - 'hubloc_hash' => $channel['channel_hash'], - 'hubloc_addr' => channel_reddress($channel), - 'hubloc_network' => 'zot6', - 'hubloc_primary' => (($seize) ? 1 : 0), - 'hubloc_url' => z_root(), - 'hubloc_url_sig' => Libzot::sign(z_root(),$channel['channel_prvkey']), - 'hubloc_host' => App::get_hostname(), + 'hubloc_hash' => $channel['channel_hash'], + 'hubloc_addr' => channel_reddress($channel), + 'hubloc_network' => 'zot6', + 'hubloc_primary' => (($seize) ? 1 : 0), + 'hubloc_url' => z_root(), + 'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']), + 'hubloc_host' => App::get_hostname(), 'hubloc_callback' => z_root() . '/zot', - 'hubloc_sitekey' => get_config('system', 'pubkey'), - 'hubloc_updated' => datetime_convert(), - 'hubloc_id_url' => channel_url($channel), - 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), get_config('system', 'pubkey')) + 'hubloc_sitekey' => get_config('system', 'pubkey'), + 'hubloc_updated' => datetime_convert(), + 'hubloc_id_url' => channel_url($channel), + 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), get_config('system', 'pubkey')) ] ); @@ -257,21 +258,21 @@ class Import extends Controller { $r = xchan_store_lowlevel( [ - 'xchan_hash' => $channel['channel_hash'], - 'xchan_guid' => $channel['channel_guid'], - 'xchan_guid_sig' => $channel['channel_guid_sig'], - 'xchan_pubkey' => $channel['channel_pubkey'], - 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'], - 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'], - 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'], - 'xchan_addr' => channel_reddress($channel), - 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'], - 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], - 'xchan_follow' => z_root() . '/follow?f=&url=%s', - 'xchan_name' => $channel['channel_name'], - 'xchan_network' => 'zot6', + 'xchan_hash' => $channel['channel_hash'], + 'xchan_guid' => $channel['channel_guid'], + 'xchan_guid_sig' => $channel['channel_guid_sig'], + 'xchan_pubkey' => $channel['channel_pubkey'], + 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'], + 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'], + 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'], + 'xchan_addr' => channel_reddress($channel), + 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'], + 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], + 'xchan_follow' => z_root() . '/follow?f=&url=%s', + 'xchan_name' => $channel['channel_name'], + 'xchan_network' => 'zot6', 'xchan_photo_date' => datetime_convert(), - 'xchan_name_date' => datetime_convert() + 'xchan_name_date' => datetime_convert() ] ); @@ -293,13 +294,13 @@ class Import extends Controller { } if (!array_key_exists('xchan_hidden', $xchan)) { - $xchan['xchan_hidden'] = (($xchan['xchan_flags'] & 0x0001) ? 1 : 0); - $xchan['xchan_orphan'] = (($xchan['xchan_flags'] & 0x0002) ? 1 : 0); - $xchan['xchan_censored'] = (($xchan['xchan_flags'] & 0x0004) ? 1 : 0); + $xchan['xchan_hidden'] = (($xchan['xchan_flags'] & 0x0001) ? 1 : 0); + $xchan['xchan_orphan'] = (($xchan['xchan_flags'] & 0x0002) ? 1 : 0); + $xchan['xchan_censored'] = (($xchan['xchan_flags'] & 0x0004) ? 1 : 0); $xchan['xchan_selfcensored'] = (($xchan['xchan_flags'] & 0x0008) ? 1 : 0); - $xchan['xchan_system'] = (($xchan['xchan_flags'] & 0x0010) ? 1 : 0); - $xchan['xchan_pubforum'] = (($xchan['xchan_flags'] & 0x0020) ? 1 : 0); - $xchan['xchan_deleted'] = (($xchan['xchan_flags'] & 0x1000) ? 1 : 0); + $xchan['xchan_system'] = (($xchan['xchan_flags'] & 0x0010) ? 1 : 0); + $xchan['xchan_pubforum'] = (($xchan['xchan_flags'] & 0x0020) ? 1 : 0); + $xchan['xchan_deleted'] = (($xchan['xchan_flags'] & 0x1000) ? 1 : 0); } $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", @@ -319,7 +320,8 @@ class Import extends Controller { dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), dbesc($xchan['xchan_hash']) ); - } else { + } + else { $photos = import_xchan_photo($xchan['xchan_photo_l'], $xchan['xchan_hash']); if ($photos[4]) $photodate = NULL_DATE; @@ -348,7 +350,7 @@ class Import extends Controller { } $friends = 0; - $feeds = 0; + $feeds = 0; // import contacts $abooks = $data['abook']; @@ -372,14 +374,14 @@ class Import extends Controller { $abook['abook_account'] = $account_id; $abook['abook_channel'] = $channel['channel_id']; if (!array_key_exists('abook_blocked', $abook)) { - $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0); - $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002) ? 1 : 0); - $abook['abook_hidden'] = (($abook['abook_flags'] & 0x0004) ? 1 : 0); - $abook['abook_archived'] = (($abook['abook_flags'] & 0x0008) ? 1 : 0); - $abook['abook_pending'] = (($abook['abook_flags'] & 0x0010) ? 1 : 0); + $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0); + $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002) ? 1 : 0); + $abook['abook_hidden'] = (($abook['abook_flags'] & 0x0004) ? 1 : 0); + $abook['abook_archived'] = (($abook['abook_flags'] & 0x0008) ? 1 : 0); + $abook['abook_pending'] = (($abook['abook_flags'] & 0x0010) ? 1 : 0); $abook['abook_unconnected'] = (($abook['abook_flags'] & 0x0020) ? 1 : 0); - $abook['abook_self'] = (($abook['abook_flags'] & 0x0080) ? 1 : 0); - $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100) ? 1 : 0); + $abook['abook_self'] = (($abook['abook_flags'] & 0x0080) ? 1 : 0); + $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100) ? 1 : 0); } if (array_key_exists('abook_instance', $abook) && $abook['abook_instance'] && strpos($abook['abook_instance'], z_root()) === false) { @@ -393,7 +395,8 @@ class Import extends Controller { dbesc($abook['abook_xchan']) ); } - } else { + } + else { if ($max_friends !== false && $friends > $max_friends) continue; if ($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds)) @@ -413,7 +416,8 @@ class Import extends Controller { intval($channel['channel_id']) ); } - } else { + } + else { abook_store_lowlevel($abook); $friends++; @@ -438,9 +442,9 @@ class Import extends Controller { // import groups $groups = $data['group']; if ($groups) { - $saved = array(); + $saved = []; foreach ($groups as $group) { - $saved[$group['hash']] = array('old' => $group['id']); + $saved[$group['hash']] = ['old' => $group['id']]; if (array_key_exists('name', $group)) { $group['gname'] = $group['name']; unset($group['name']); @@ -507,7 +511,7 @@ class Import extends Controller { if (is_array($data['webpages'])) import_items($channel, $data['webpages'], false, $relocate); - $addon = array('channel' => $channel, 'data' => $data); + $addon = ['channel' => $channel, 'data' => $data]; call_hooks('import_channel', $addon); if ($import_posts && array_key_exists('item', $data) && $data['item']) { @@ -515,10 +519,10 @@ class Import extends Controller { } // Immediately notify old server about the new clone - Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); + Master::Summon(['Notifier', 'refresh_all', $channel['channel_id']]); // This will indirectly perform a refresh_all *and* update the directory - Master::Summon(array('Directory', $channel['channel_id'])); + Master::Summon(['Directory', $channel['channel_id']]); $cf_api_compat = true; @@ -529,14 +533,14 @@ class Import extends Controller { $hz_server = $m['scheme'] . '://' . $m['host']; - $since = datetime_convert(date_default_timezone_get(),date_default_timezone_get(),'0001-01-01 00:00'); - $until = datetime_convert(date_default_timezone_get(),date_default_timezone_get(),'now + 1 day'); + $since = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), '0001-01-01 00:00'); + $until = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), 'now + 1 day'); - $poll_interval = get_config('system','poll_interval',3); - $page = 0; + $poll_interval = get_config('system', 'poll_interval', 3); + $page = 0; - Master::Summon([ 'Content_importer', sprintf('%d',$page), $since, $until, $channel['channel_address'], urlencode($hz_server) ]); - Master::Summon([ 'File_importer',sprintf('%d',$page), $channel['channel_address'], urlencode($hz_server) ]); + Master::Summon(['Content_importer', sprintf('%d', $page), $since, $until, $channel['channel_address'], urlencode($hz_server)]); + Master::Summon(['File_importer', sprintf('%d', $page), $channel['channel_address'], urlencode($hz_server)]); } else { $cf_api_compat = false; @@ -550,7 +554,7 @@ class Import extends Controller { } if (!$cf_api_compat) { - notice(t('Automatic content and files import was not possible due to API version incompatiblity. Please import content and files manually!') . EOL); + notice(t('Automatic content and files import was not possible due to API version incompatiblity. Please import content and files manually!') . EOL); } goaway(z_root()); @@ -584,28 +588,28 @@ class Import extends Controller { nav_set_selected('Channel Import'); - $o = replace_macros(get_markup_template('channel_import.tpl'), array( - '$title' => t('Channel Import'), - '$desc' => t('Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file.'), + $o = replace_macros(get_markup_template('channel_import.tpl'), [ + '$title' => t('Channel Import'), + '$desc' => t('Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file.'), '$label_filename' => t('File to Upload'), - '$choice' => t('Or provide the old server/hub details'), + '$choice' => t('Or provide the old server/hub details'), - '$old_address' => ['old_address', t('Your old identity address (xyz@example.com)'), '', ''], - '$email' => ['email', t('Your old login email address'), '', ''], - '$password' => ['password', t('Your old login password'), '', ''], + '$old_address' => ['old_address', t('Your old identity address (xyz@example.com)'), '', ''], + '$email' => ['email', t('Your old login email address'), '', ''], + '$password' => ['password', t('Your old login password'), '', ''], '$import_posts' => ['import_posts', t('Import your items and files (limited by available memory)'), false, '', [t('No'), t('Yes')]], '$common' => t('For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'), '$make_primary' => ['make_primary', t('Make this hub my primary location'), false, '', [t('No'), t('Yes')]], - '$moving' => ['moving', t('Move this channel (disable all previous locations)'), false, '', [t('No'), t('Yes')]], - '$newname' => ['newname', t('Use this channel nickname instead of the one provided'), '', t('Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.')], + '$moving' => ['moving', t('Move this channel (disable all previous locations)'), false, '', [t('No'), t('Yes')]], + '$newname' => ['newname', t('Use this channel nickname instead of the one provided'), '', t('Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.')], '$pleasewait' => t('This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'), '$form_security_token' => get_form_security_token('channel_import'), - '$submit' => t('Submit') - )); + '$submit' => t('Submit') + ]); return $o; } diff --git a/Zotlabs/Module/Import_items.php b/Zotlabs/Module/Import_items.php index c2b2506fe..1a1e8d061 100644 --- a/Zotlabs/Module/Import_items.php +++ b/Zotlabs/Module/Import_items.php @@ -1,6 +1,11 @@ <?php + namespace Zotlabs\Module; +use App; +use ZipArchive; +use Zotlabs\Web\Controller; + require_once('include/import.php'); /** @@ -8,128 +13,184 @@ require_once('include/import.php'); * * Import existing posts and content from an export file. */ -class Import_items extends \Zotlabs\Web\Controller { +class Import_items extends Controller { function post() { - if(! local_channel()) + if (!local_channel()) return; check_form_security_token_redirectOnErr('/import_items', 'import_items'); - $data = null; + $data = null; $src = $_FILES['filename']['tmp_name']; $filename = basename($_FILES['filename']['name']); $filesize = intval($_FILES['filename']['size']); $filetype = $_FILES['filename']['type']; - if($src) { + $channel = App::get_channel(); + + if ($src) { + + if ($filetype === 'application/zip') { + $zip = new ZipArchive; + + $r = $zip->open($src); + if ($r === true) { + for ($i = 0; $i < $zip->count(); $i++) { + $data = $zip->getFromIndex($i); + self::import($channel, $data); + } + $zip->close(); + unlink($src); + return; + } + + notice(t('Not a zip file or zip file corrupted.') . EOL); + unlink($src); + return; + } + // This is OS specific and could also fail if your tmpdir isn't very large // mostly used for Diaspora which exports gzipped files. - if(strpos($filename,'.gz')){ - @rename($src,$src . '.gz'); - @system('gunzip ' . escapeshellarg($src . '.gz')); - } + //if(strpos($filename,'.gz')){ + //@rename($src,$src . '.gz'); + //@system('gunzip ' . escapeshellarg($src . '.gz')); + //} - if($filesize) { + if ($filesize) { $data = @file_get_contents($src); + self::import($channel, $data); } unlink($src); + return; } + /* + if(! $src) { + + $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); + + if(! $old_address) { + logger('Nothing to import.'); + notice( t('Nothing to import.') . EOL); + return; + } + + $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); + $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); + + $year = ((x($_REQUEST,'year')) ? $_REQUEST['year'] : ''); + + $channelname = substr($old_address,0,strpos($old_address,'@')); + $servername = substr($old_address,strpos($old_address,'@')+1); + + $scheme = 'https://'; + $api_path = '/api/red/channel/export/items?f=&channel=' . $channelname . '&year=' . intval($year); + $binary = false; + $redirects = 0; + $opts = array('http_auth' => $email . ':' . $password); + $url = $scheme . $servername . $api_path; + $ret = z_fetch_url($url, $binary, $redirects, $opts); + if(! $ret['success']) + $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); + if($ret['success']) + $data = $ret['body']; + else + notice( t('Unable to download data from old server') . EOL); + } + */ - if(! $src) { + } - $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); - if(! $old_address) { - logger('Nothing to import.'); - notice( t('Nothing to import.') . EOL); - return; - } + /** + * @brief Generate item import page. + * + * @return string with parsed HTML. + */ + function get() { - $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); - $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); - - $year = ((x($_REQUEST,'year')) ? $_REQUEST['year'] : ''); - - $channelname = substr($old_address,0,strpos($old_address,'@')); - $servername = substr($old_address,strpos($old_address,'@')+1); - - $scheme = 'https://'; - $api_path = '/api/red/channel/export/items?f=&channel=' . $channelname . '&year=' . intval($year); - $binary = false; - $redirects = 0; - $opts = array('http_auth' => $email . ':' . $password); - $url = $scheme . $servername . $api_path; - $ret = z_fetch_url($url, $binary, $redirects, $opts); - if(! $ret['success']) - $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); - if($ret['success']) - $data = $ret['body']; - else - notice( t('Unable to download data from old server') . EOL); + if (!local_channel()) { + notice(t('Permission denied') . EOL); + return login(); } - if(! $data) { + $o = replace_macros(get_markup_template('item_import.tpl'), [ + '$title' => t('Import Items'), + '$desc' => t('Use this form to import existing posts and content from an export file.'), + '$label_filename' => t('File to Upload'), + '$form_security_token' => get_form_security_token('import_items'), + '$submit' => t('Submit') + ]); + + return $o; + } + + + public static function import($channel, $data) { + + if (!$data) { logger('Empty file.'); - notice( t('Imported file is empty.') . EOL); + notice(t('Imported file is empty.') . EOL); return; } $data = json_decode($data, true); - //logger('import: data: ' . print_r($data,true)); //print_r($data); - if(! is_array($data)) + if (!is_array($data)) { return; + } - if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { - $v1 = substr($data['compatibility']['database'],-4); - $v2 = substr(DB_UPDATE_VERSION,-4); - if($v2 > $v1) { - $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); - notice($t . EOL); - } + //if (array_key_exists('compatibility', $data) && array_key_exists('database', $data['compatibility'])) { + //$v1 = substr($data['compatibility']['database'], -4); + //$v2 = substr(DB_UPDATE_VERSION, -4); + //if ($v2 > $v1) { + //$t = sprintf(t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1); + //notice($t . EOL); + //} + //} + + if (array_key_exists('item', $data) && is_array($data['item'])) { + import_items($channel, $data['item'], false, ((array_key_exists('relocate', $data)) ? $data['relocate'] : null)); + info(t('Content import completed') . EOL); } - $channel = \App::get_channel(); + if (array_key_exists('chatroom', $data) && is_array($data['chatroom'])) { + import_chatrooms($channel, $data['chatroom']); + info(t('Chatroom import completed') . EOL); - if(array_key_exists('item',$data) && $data['item']) { - import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); } - if(array_key_exists('item_id',$data) && $data['item_id']) { - import_item_ids($channel,$data['item_id']); - } + if (array_key_exists('event', $data) && is_array($data['event'])) { + import_events($channel, $data['event']); + info(t('Channel calendar import 1/2 completed') . EOL); - info( t('Import completed') . EOL); - } + } + if (array_key_exists('event_item', $data) && is_array($data['event_item'])) { + import_items($channel, $data['event_item'], false, ((array_key_exists('relocate', $data)) ? $data['relocate'] : null)); + info(t('Channel calendar import 2/2 completed') . EOL); + } - /** - * @brief Generate item import page. - * - * @return string with parsed HTML. - */ - function get() { + if (array_key_exists('menu', $data) && is_array($data['menu'])) { + import_menus($channel, $data['menu']); + info(t('Menu import completed') . EOL); + } - if(! local_channel()) { - notice( t('Permission denied') . EOL); - return login(); + if (array_key_exists('wiki', $data) && is_array($data['wiki'])) { + import_items($channel, $data['wiki'], false, ((array_key_exists('relocate', $data)) ? $data['relocate'] : null)); + info(t('Wiki import completed') . EOL); } - $o = replace_macros(get_markup_template('item_import.tpl'), array( - '$title' => t('Import Items'), - '$desc' => t('Use this form to import existing posts and content from an export file.'), - '$label_filename' => t('File to Upload'), - '$form_security_token' => get_form_security_token('import_items'), - '$submit' => t('Submit') - )); + if (array_key_exists('webpages', $data) && is_array($data['webpages'])) { + import_items($channel, $data['webpages'], false, ((array_key_exists('relocate', $data)) ? $data['relocate'] : null)); + info(t('Webpages import completed') . EOL); + } - return $o; } } diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index 40f972385..2a126ac27 100644 --- a/Zotlabs/Module/Invite.php +++ b/Zotlabs/Module/Invite.php @@ -129,11 +129,11 @@ class Invite extends Controller { if(! $recip) continue; // see if we have an email address who@domain.tld - if (!preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $recip)) { - $feedbk .= 'ZAI0203E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a valid email address'), $recip) . $eol; - $ko++; - continue; - } + //if (!preg_match('/^.{2,64}\@[a-z0-9.-]{2,32}\.[a-z]{2,12}$/', $recip)) { + //$feedbk .= 'ZAI0203E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a valid email address'), $recip) . $eol; + //$ko++; + //continue; + //} if(! validate_email($recip)) { $feedbk .= 'ZAI0204E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a real email address'), $recip) . $eol; $ko++; @@ -225,7 +225,7 @@ class Invite extends Controller { '$projectname' => t('$Projectname'), '$invite_code' => $invite_code, '$invite_where' => z_root() . '/register', - '$invite_whereami' => str_replace('@', '@+', $reonar['whereami']), + '$invite_whereami' => $reonar['whereami'], '$invite_whoami' => z_root() . '/channel/' . $reonar['whoami'], '$invite_anywhere' => z_root() . '/pubsites' ) @@ -422,8 +422,6 @@ class Invite extends Controller { // let take one descriptive for template (as said is never used) $invite_code = 'INVITATE2020'; - // what languages we use now - $lccmy = ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en'); // and all the localized templates belonging to invite $tpls = glob('view/*/invite.*.tpl'); @@ -444,6 +442,9 @@ class Invite extends Controller { $langs = array_keys($tpla); asort($langs); + // Use the current language if we have a template for it. Otherwise fall back to 'en'. + $lccmy = ((in_array(App::$language, $langs)) ? App::$language : 'en'); + $tplx = array_unique($tplx); asort($tplx); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 7099a54e5..41979006e 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -2,6 +2,8 @@ namespace Zotlabs\Module; +use App; +use URLify; use Zotlabs\Lib\Config; use Zotlabs\Lib\IConfig; use Zotlabs\Lib\Enotify; @@ -15,7 +17,6 @@ use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libsync; use Zotlabs\Lib\ThreadListener; use Zotlabs\Access\PermissionRoles; -use App; require_once('include/crypto.php'); require_once('include/items.php'); @@ -37,8 +38,6 @@ require_once('include/conversation.php'); * posting categories go through item_store() instead of this function. * */ - - class Item extends Controller { @@ -46,11 +45,9 @@ class Item extends Controller { if (Libzot::is_zot_request()) { - $conversation = false; - $item_id = argv(1); - if(! $item_id) + if (!$item_id) http_status_exit(404, 'Not found'); $portable_id = EMPTY_STR; @@ -70,8 +67,8 @@ class Item extends Controller { dbesc(z_root() . '/item/' . $item_id) ); - if (! $r) { - http_status_exit(404,'Not found'); + if (!$r) { + http_status_exit(404, 'Not found'); } // process an authenticated fetch @@ -79,10 +76,10 @@ class Item extends Controller { $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR); if ($sigdata['portable_id'] && $sigdata['header_valid']) { $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { + if (!check_channelallowed($portable_id)) { http_status_exit(403, 'Permission denied'); } - if (! check_siteallowed($sigdata['signer'])) { + if (!check_siteallowed($sigdata['signer'])) { http_status_exit(403, 'Permission denied'); } observer_auth($portable_id); @@ -92,8 +89,8 @@ class Item extends Controller { dbesc($portable_id) ); } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); + elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); } // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access @@ -101,47 +98,47 @@ class Item extends Controller { $sql_extra = item_permissions_sql(0); - if (! $i) { + if (!$i) { $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", dbesc($r[0]['parent_mid']) ); } - if(! $i) { - http_status_exit(403,'Forbidden'); + if (!$i) { + http_status_exit(403, 'Forbidden'); } - $parents_str = ids_to_querystr($i,'item_id'); + $parents_str = ids_to_querystr($i, 'item_id'); $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal order by item.id asc", dbesc($parents_str) ); - if(! $items) { + if (!$items) { http_status_exit(404, 'Not found'); } - xchan_query($items,true); - $items = fetch_post_tags($items,true); + xchan_query($items, true); + $items = fetch_post_tags($items, true); - if(! $items) + if (!$items) http_status_exit(404, 'Not found'); $chan = channelx_by_n($items[0]['uid']); - if(! $chan) + if (!$chan) http_status_exit(404, 'Not found'); - if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) http_status_exit(403, 'Forbidden'); $i = Activity::encode_item_collection($items, 'conversation/' . $item_id, 'OrderedCollection'); - if(! $i) + if (!$i) http_status_exit(404, 'Not found'); - if($portable_id && (! intval($items[0]['item_private']))) { + if ($portable_id && (!intval($items[0]['item_private']))) { ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id); } @@ -149,25 +146,25 @@ class Item extends Controller { ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], $i); + ]], $i); - $headers = []; - $headers['Content-Type'] = 'application/x-zot+json' ; - $x['signature'] = LDSignatures::sign($x,$chan); - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers = []; + $headers['Content-Type'] = 'application/x-zot+json'; + $x['signature'] = LDSignatures::sign($x, $chan); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan)); + $h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan)); HTTPSig::set_headers($h); echo $ret; killme(); } - if(ActivityStreams::is_as_request()) { + if (ActivityStreams::is_as_request()) { $item_id = argv(1); - if(! $item_id) + if (!$item_id) http_status_exit(404, 'Not found'); $portable_id = EMPTY_STR; @@ -189,8 +186,8 @@ class Item extends Controller { dbesc($item_id) ); - if (! $r) { - http_status_exit(404,'Not found'); + if (!$r) { + http_status_exit(404, 'Not found'); } // process an authenticated fetch @@ -198,10 +195,10 @@ class Item extends Controller { $sigdata = HTTPSig::verify(EMPTY_STR); if ($sigdata['portable_id'] && $sigdata['header_valid']) { $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { + if (!check_channelallowed($portable_id)) { http_status_exit(403, 'Permission denied'); } - if (! check_siteallowed($sigdata['signer'])) { + if (!check_siteallowed($sigdata['signer'])) { http_status_exit(403, 'Permission denied'); } observer_auth($portable_id); @@ -211,8 +208,8 @@ class Item extends Controller { dbesc($portable_id) ); } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); + elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); } // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access @@ -220,40 +217,40 @@ class Item extends Controller { $sql_extra = item_permissions_sql(0); - if (! $i) { + if (!$i) { $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", dbesc($r[0]['parent_mid']) ); } - if(! $i) { - http_status_exit(403,'Forbidden'); + if (!$i) { + http_status_exit(403, 'Forbidden'); } // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it. - xchan_query($r,true); - $items = fetch_post_tags($r,false); + xchan_query($r, true); + $items = fetch_post_tags($r, false); $chan = channelx_by_n($items[0]['uid']); - if(! $chan) + if (!$chan) http_status_exit(404, 'Not found'); - if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) http_status_exit(403, 'Forbidden'); - $i = Activity::encode_item($items[0],true); + $i = Activity::encode_item($items[0]); - if(! $i) + if (!$i) http_status_exit(404, 'Not found'); - if ($portable_id && (! intval($items[0]['item_private']))) { + if ($portable_id && (!intval($items[0]['item_private']))) { $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", intval($items[0]['uid']), dbesc($portable_id) ); - if (! $c) { + if (!$c) { ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id); } } @@ -262,16 +259,16 @@ class Item extends Controller { ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], $i); - - $headers = []; - $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; - $x['signature'] = LDSignatures::sign($x,$chan); - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); + ]], $i); + + $headers = []; + $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; + $x['signature'] = LDSignatures::sign($x, $chan); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $headers['Date'] = datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan)); + $h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan)); HTTPSig::set_headers($h); echo $ret; killme(); @@ -279,14 +276,14 @@ class Item extends Controller { } - if(argc() > 1 && argv(1) !== 'drop') { + if (argc() > 1 && argv(1) !== 'drop') { $x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' or uuid = '%s'", dbesc(z_root() . '/item/' . argv(1)), dbesc(z_root() . '/activity/' . argv(1)), dbesc(argv(1)) ); - if($x) { - foreach($x as $xv) { + if ($x) { + foreach ($x as $xv) { if (intval($xv['item_wall'])) { $c = channelx_by_n($xv['uid']); if ($c) { @@ -302,17 +299,16 @@ class Item extends Controller { } - function post() { // This will change. Figure out who the observer is and whether or not // they have permission to post here. Else ignore the post. - if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'anonname'))) + if ((!local_channel()) && (!remote_channel()) && (!x($_REQUEST, 'anonname'))) return; - $uid = local_channel(); - $channel = null; + $uid = local_channel(); + $channel = null; $observer = null; $datarray = []; @@ -321,34 +317,34 @@ class Item extends Controller { * Is this a reply to something? */ - $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); - $parent_mid = ((x($_REQUEST,'parent_mid')) ? trim($_REQUEST['parent_mid']) : ''); - $mode = (($_REQUEST['conv_mode'] === 'channel') ? 'channel' : 'network'); + $parent = ((x($_REQUEST, 'parent')) ? intval($_REQUEST['parent']) : 0); + $parent_mid = ((x($_REQUEST, 'parent_mid')) ? trim($_REQUEST['parent_mid']) : ''); + $mode = (($_REQUEST['conv_mode'] === 'channel') ? 'channel' : 'network'); - $remote_xchan = ((x($_REQUEST,'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false); - $r = q("select * from xchan where xchan_hash = '%s' limit 1", + $remote_xchan = ((x($_REQUEST, 'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false); + $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($remote_xchan) ); - if($r) + if ($r) $remote_observer = $r[0]; else $remote_xchan = $remote_observer = false; - $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); + $profile_uid = ((x($_REQUEST, 'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); require_once('include/channel.php'); $sys = get_sys_channel(); - if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) { - $uid = intval($sys['channel_id']); - $channel = $sys; + if ($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) { + $uid = intval($sys['channel_id']); + $channel = $sys; $observer = $sys; } - if(x($_REQUEST,'dropitems')) { + if (x($_REQUEST, 'dropitems')) { require_once('include/items.php'); - $arr_drop = explode(',',$_REQUEST['dropitems']); + $arr_drop = explode(',', $_REQUEST['dropitems']); drop_items($arr_drop); - $json = array('success' => 1); + $json = ['success' => 1]; echo json_encode($json); killme(); } @@ -357,7 +353,7 @@ class Item extends Controller { // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); - $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); + $api_source = ((x($_REQUEST, 'api_source') && $_REQUEST['api_source']) ? true : false); $consensus = intval($_REQUEST['consensus']); $nocomment = intval($_REQUEST['nocomment']); @@ -373,77 +369,75 @@ class Item extends Controller { // If you are unsure, it is prudent (and important) to leave it unset. - $origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); + $origin = (($api_source && array_key_exists('origin', $_REQUEST)) ? intval($_REQUEST['origin']) : 1); // To represent message-ids on other networks - this will create an iconfig record - $namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); - $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); + $namespace = (($api_source && array_key_exists('namespace', $_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); + $remote_id = (($api_source && array_key_exists('remote_id', $_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); $owner_hash = null; - $message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); - $created = ((x($_REQUEST,'created')) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['created']) : datetime_convert()); - $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); - $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''); - $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); - $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); - $categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : ''); - $webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0); - $item_obscured = ((x($_REQUEST,'obscured')) ? intval($_REQUEST['obscured']) : 0); - $pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : ''); - $layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): ''); - $plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); - $obj_type = ((x($_REQUEST,'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); + $message_id = ((x($_REQUEST, 'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); + $created = ((x($_REQUEST, 'created')) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['created']) : datetime_convert()); + $post_id = ((x($_REQUEST, 'post_id')) ? intval($_REQUEST['post_id']) : 0); + $app = ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : ''); + $return_path = ((x($_REQUEST, 'return')) ? $_REQUEST['return'] : ''); + $preview = ((x($_REQUEST, 'preview')) ? intval($_REQUEST['preview']) : 0); + $categories = ((x($_REQUEST, 'category')) ? escape_tags($_REQUEST['category']) : ''); + $webpage = ((x($_REQUEST, 'webpage')) ? intval($_REQUEST['webpage']) : 0); + $item_obscured = ((x($_REQUEST, 'obscured')) ? intval($_REQUEST['obscured']) : 0); + $pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : ''); + $layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : ''); + $plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); + $obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); // allow API to bulk load a bunch of imported items with sending out a bunch of posts. - $nopush = ((x($_REQUEST,'nopush')) ? intval($_REQUEST['nopush']) : 0); + $nopush = ((x($_REQUEST, 'nopush')) ? intval($_REQUEST['nopush']) : 0); /* * Check service class limits */ - if ($uid && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) { - $ret = $this->item_check_service_class($uid,(($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); + if ($uid && !(x($_REQUEST, 'parent')) && !(x($_REQUEST, 'post_id'))) { + $ret = $this->item_check_service_class($uid, (($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); if (!$ret['success']) { - notice( t($ret['message']) . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'service class exception' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + notice(t($ret['message']) . EOL); + if ($api_source) + return (['success' => false, 'message' => 'service class exception']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } } - if($pagetitle) { - require_once('library/urlify/URLify.php'); - $pagetitle = strtolower(\URLify::transliterate($pagetitle)); + if ($pagetitle) { + $pagetitle = strtolower(URLify::transliterate($pagetitle)); } - $item_flags = $item_restrict = 0; $expires = NULL_DATE; + $comments_closed = NULL_DATE; - $route = ''; - $parent_item = null; + $route = ''; + $parent_item = null; $parent_contact = null; - $thr_parent = ''; - $parid = 0; - $r = false; + $thr_parent = ''; + $r = false; - if($parent || $parent_mid) { + if ($parent || $parent_mid) { - if(! x($_REQUEST,'type')) + if (!x($_REQUEST, 'type')) $_REQUEST['type'] = 'net-comment'; - if($obj_type == ACTIVITY_OBJ_NOTE) + if ($obj_type == ACTIVITY_OBJ_NOTE) $obj_type = ACTIVITY_OBJ_COMMENT; - if($parent) { + if ($parent) { $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", intval($parent) ); } - elseif($parent_mid && $uid) { + elseif ($parent_mid && $uid) { // This is coming from an API source, and we are logged in $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($parent_mid), @@ -451,10 +445,10 @@ class Item extends Controller { ); } // if this isn't the real parent of the conversation, find it - if($r) { - $parid = $r[0]['parent']; + if ($r) { + $parid = $r[0]['parent']; $parent_mid = $r[0]['mid']; - if($r[0]['id'] != $r[0]['parent']) { + if ($r[0]['id'] != $r[0]['parent']) { $r = q("SELECT * FROM item WHERE id = parent AND parent = %d LIMIT 1", intval($parid) ); @@ -463,24 +457,24 @@ class Item extends Controller { // if interacting with a pubstream item, // create a copy of the parent in your stream - if($r[0]['uid'] === $sys['channel_id'] && local_channel()) { - $r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ]; + if ($r[0]['uid'] === $sys['channel_id'] && local_channel()) { + $r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])]; } } - if(! $r) { - notice( t('Unable to locate original post.') . EOL); - if($api_source) - return ( [ 'success' => false, 'message' => 'invalid post id' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + if (!$r) { + notice(t('Unable to locate original post.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'invalid post id']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } - xchan_query($r,true); + xchan_query($r, true); $parent_item = $r[0]; - $parent = $r[0]['id']; + $parent = $r[0]['id']; // multi-level threading - preserve the info but re-parent to our single level threading @@ -492,52 +486,52 @@ class Item extends Controller { $moderated = false; - if(! $observer) { - $observer = \App::get_observer(); - if(! $observer) { + if (!$observer) { + $observer = App::get_observer(); + if (!$observer) { $observer = anon_identity_init($_REQUEST); - if($observer) { - $moderated = true; + if ($observer) { + $moderated = true; $remote_xchan = $remote_observer = $observer; } } } - if(! $observer) { - notice( t('Permission denied.') . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + if (!$observer) { + notice(t('Permission denied.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'permission denied']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } - if($parent) { + if ($parent) { logger('mod_item: item_post parent=' . $parent); $can_comment = false; - $can_comment = can_comment_on_post($observer['xchan_hash'],$parent_item); - if (!$can_comment) { - if((array_key_exists('owner',$parent_item)) && intval($parent_item['owner']['abook_self'])==1 ) - $can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments'); - } - - if(! $can_comment) { - notice( t('Permission denied.') . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + $can_comment = can_comment_on_post($observer['xchan_hash'], $parent_item); + if (!$can_comment) { + if ((array_key_exists('owner', $parent_item)) && intval($parent_item['owner']['abook_self']) == 1) + $can_comment = perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_comments'); + } + + if (!$can_comment) { + notice(t('Permission denied.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'permission denied']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } } else { - if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],($webpage) ? 'write_pages' : 'post_wall')) { - notice( t('Permission denied.') . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], ($webpage) ? 'write_pages' : 'post_wall')) { + notice(t('Permission denied.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'permission denied']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } } @@ -547,53 +541,53 @@ class Item extends Controller { $orig_post = null; - if($namespace && $remote_id) { + if ($namespace && $remote_id) { // It wasn't an internally generated post - see if we've got an item matching this remote service id $i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1", dbesc($namespace), dbesc($remote_id) ); - if($i) + if ($i) $post_id = $i[0]['iid']; } $iconfig = null; - if($post_id) { + if ($post_id) { $i = q("SELECT * FROM item WHERE uid = %d AND id = %d LIMIT 1", intval($profile_uid), intval($post_id) ); - if(! count($i)) + if (!count($i)) killme(); $orig_post = $i[0]; - $iconfig = q("select * from iconfig where iid = %d", + $iconfig = q("select * from iconfig where iid = %d", intval($post_id) ); } - if(! $channel) { - if($uid && $uid == $profile_uid) { - $channel = \App::get_channel(); + if (!$channel) { + if ($uid && $uid == $profile_uid) { + $channel = App::get_channel(); } else { // posting as yourself but not necessarily to a channel you control $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", intval($profile_uid) ); - if($r) + if ($r) $channel = $r[0]; } } - if(! $channel) { + if (!$channel) { logger("mod_item: no channel."); - if($api_source) - return ( [ 'success' => false, 'message' => 'no channel' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + if ($api_source) + return (['success' => false, 'message' => 'no channel']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } @@ -602,37 +596,37 @@ class Item extends Controller { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($channel['channel_hash']) ); - if($r && count($r)) { + if ($r && count($r)) { $owner_xchan = $r[0]; } else { logger("mod_item: no owner."); - if($api_source) - return ( [ 'success' => false, 'message' => 'no owner' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + if ($api_source) + return (['success' => false, 'message' => 'no owner']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } - $walltowall = false; + $walltowall = false; $walltowall_comment = false; - if($remote_xchan && ! $moderated) + if ($remote_xchan && !$moderated) $observer = $remote_observer; - if($observer) { + if ($observer) { logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); // wall-to-wall detection. // For top-level posts, if the author and owner are different it's a wall-to-wall // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally. - if($observer['xchan_name'] != $owner_xchan['xchan_name']) { - if(($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { + if ($observer['xchan_name'] != $owner_xchan['xchan_name']) { + if (($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { $walltowall_comment = true; - $walltowall = true; + $walltowall = true; } - if(! $parent) { + if (!$parent) { $walltowall = true; } } @@ -640,83 +634,79 @@ class Item extends Controller { $acl = new \Zotlabs\Access\AccessList($channel); - $view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'); - $comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'); + $view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream'); + $comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments'); - $public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy,true)); - if($webpage) + $public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true)); + if ($webpage) $public_policy = ''; - if($public_policy) + if ($public_policy) $private = 1; - if($orig_post) { + if ($orig_post) { $private = 0; // webpages are allowed to change ACLs after the fact. Normal conversation items aren't. - if($webpage) { + if ($webpage) { $acl->set_from_array($_REQUEST); } else { $acl->set($orig_post); - $public_policy = $orig_post['public_policy']; - $private = $orig_post['item_private']; + $public_policy = $orig_post['public_policy']; + $private = $orig_post['item_private']; } - if($public_policy || $acl->is_private()) { + if ($public_policy || $acl->is_private()) { $private = (($private) ? $private : 1); } - $location = $orig_post['location']; - $coord = $orig_post['coord']; - $verb = $orig_post['verb']; - $app = $orig_post['app']; - $title = escape_tags(trim($_REQUEST['title'])); - $summary = trim($_REQUEST['summary']); - $body = trim($_REQUEST['body']); - $item_flags = $orig_post['item_flags']; - - $item_origin = $orig_post['item_origin']; - $item_unseen = $orig_post['item_unseen']; - $item_starred = $orig_post['item_starred']; - $item_uplink = $orig_post['item_uplink']; - $item_consensus = $orig_post['item_consensus']; - $item_wall = $orig_post['item_wall']; - $item_thread_top = $orig_post['item_thread_top']; - $item_notshown = $orig_post['item_notshown']; - $item_nsfw = $orig_post['item_nsfw']; - $item_relay = $orig_post['item_relay']; - $item_mentionsme = $orig_post['item_mentionsme']; - $item_nocomment = $orig_post['item_nocomment']; - $item_obscured = $orig_post['item_obscured']; - $item_verified = $orig_post['item_verified']; - $item_retained = $orig_post['item_retained']; - $item_rss = $orig_post['item_rss']; - $item_deleted = $orig_post['item_deleted']; - $item_type = $orig_post['item_type']; - $item_hidden = $orig_post['item_hidden']; - $item_unpublished = $orig_post['item_unpublished']; - $item_delayed = $orig_post['item_delayed']; - $item_pending_remove = $orig_post['item_pending_remove']; - $item_blocked = $orig_post['item_blocked']; - - - - $postopts = $orig_post['postopts']; - $created = $orig_post['created']; - $expires = $orig_post['expires']; - $mid = $orig_post['mid']; - $parent_mid = $orig_post['parent_mid']; - $plink = $orig_post['plink']; - + $location = $orig_post['location']; + $coord = $orig_post['coord']; + $verb = $orig_post['verb']; + $app = $orig_post['app']; + $title = escape_tags(trim($_REQUEST['title'])); + $summary = trim($_REQUEST['summary']); + $body = trim($_REQUEST['body']); + $item_flags = $orig_post['item_flags']; + $item_origin = $orig_post['item_origin']; + $item_unseen = $orig_post['item_unseen']; + $item_starred = $orig_post['item_starred']; + $item_uplink = $orig_post['item_uplink']; + $item_consensus = $orig_post['item_consensus']; + $item_wall = $orig_post['item_wall']; + $item_thread_top = $orig_post['item_thread_top']; + $item_notshown = $orig_post['item_notshown']; + $item_nsfw = $orig_post['item_nsfw']; + $item_relay = $orig_post['item_relay']; + $item_mentionsme = $orig_post['item_mentionsme']; + $item_nocomment = $orig_post['item_nocomment']; + $item_obscured = $orig_post['item_obscured']; + $item_verified = $orig_post['item_verified']; + $item_retained = $orig_post['item_retained']; + $item_rss = $orig_post['item_rss']; + $item_deleted = $orig_post['item_deleted']; + $item_type = $orig_post['item_type']; + $item_hidden = $orig_post['item_hidden']; + $item_unpublished = $orig_post['item_unpublished']; + $item_delayed = $orig_post['item_delayed']; + $item_pending_remove = $orig_post['item_pending_remove']; + $item_blocked = $orig_post['item_blocked']; + $postopts = $orig_post['postopts']; + $created = $orig_post['created']; + $expires = $orig_post['expires']; + $comments_closed = $orig_post['comments_closed']; + $mid = $orig_post['mid']; + $parent_mid = $orig_post['parent_mid']; + $plink = $orig_post['plink']; } else { - if(! $walltowall) { - if((array_key_exists('contact_allow',$_REQUEST)) - || (array_key_exists('group_allow',$_REQUEST)) - || (array_key_exists('contact_deny',$_REQUEST)) - || (array_key_exists('group_deny',$_REQUEST))) { + if (!$walltowall) { + if ((array_key_exists('contact_allow', $_REQUEST)) + || (array_key_exists('group_allow', $_REQUEST)) + || (array_key_exists('contact_deny', $_REQUEST)) + || (array_key_exists('group_deny', $_REQUEST))) { $acl->set_from_array($_REQUEST); } - elseif(! $api_source) { + elseif (!$api_source) { // if no ACL has been defined and we aren't using the API, the form // didn't send us any parameters. This means there's no ACL or it has @@ -724,27 +714,27 @@ class Item extends Controller { // If $api_source is set and there are no ACL parameters, we default // to the channel permissions which were set in the ACL contructor. - $acl->set(array('allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); + $acl->set(['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']); } } - $location = notags(trim($_REQUEST['location'])); - $coord = notags(trim($_REQUEST['coord'])); - $verb = notags(trim($_REQUEST['verb'])); - $title = escape_tags(trim($_REQUEST['title'])); - $summary = trim($_REQUEST['summary']); - $body = trim($_REQUEST['body']); - $body .= trim($_REQUEST['attachment']); - $postopts = ''; + $location = notags(trim($_REQUEST['location'])); + $coord = notags(trim($_REQUEST['coord'])); + $verb = notags(trim($_REQUEST['verb'])); + $title = escape_tags(trim($_REQUEST['title'])); + $summary = trim($_REQUEST['summary']); + $body = trim($_REQUEST['body']); + $body .= trim($_REQUEST['attachment']); + $postopts = ''; - $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); + $allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); $private = (($private) ? $private : intval($acl->is_private() || ($public_policy))); // If this is a comment, set the permissions from the parent. - if($parent_item) { + if ($parent_item) { $acl->set($parent_item); $private = intval($parent_item['item_private']); $public_policy = $parent_item['public_policy']; @@ -752,51 +742,50 @@ class Item extends Controller { $webpage = $parent_item['item_type']; } - if((! $allow_empty) && (! strlen($body))) { - if($preview) + if ((!$allow_empty) && (!strlen($body))) { + if ($preview) killme(); - info( t('Empty post discarded.') . EOL ); - if($api_source) - return ( [ 'success' => false, 'message' => 'no content' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); + info(t('Empty post discarded.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'no content']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); killme(); } } - - if(feature_enabled($profile_uid,'content_expire')) { - if(x($_REQUEST,'expire')) { - $expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']); - if($expires <= datetime_convert()) + if (feature_enabled($profile_uid, 'content_expire')) { + if (x($_REQUEST, 'expire')) { + $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']); + if ($expires <= datetime_convert()) $expires = NULL_DATE; } } $mimetype = notags(trim($_REQUEST['mimetype'])); - if(! $mimetype) + if (!$mimetype) $mimetype = 'text/bbcode'; $execflag = ((intval($uid) == intval($profile_uid) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); - if($preview) { - $summary = z_input_filter($summary,$mimetype,$execflag); - $body = z_input_filter($body,$mimetype,$execflag); + if ($preview) { + $summary = z_input_filter($summary, $mimetype, $execflag); + $body = z_input_filter($body, $mimetype, $execflag); } - $arr = [ 'profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype ]; - call_hooks('post_content',$arr); - $summary = $arr['summary']; - $body = $arr['content']; + $arr = ['profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype]; + call_hooks('post_content', $arr); + $summary = $arr['summary']; + $body = $arr['content']; $mimetype = $arr['mimetype']; - $gacl = $acl->get(); + $gacl = $acl->get(); $str_contact_allow = $gacl['allow_cid']; $str_group_allow = $gacl['allow_gid']; $str_contact_deny = $gacl['deny_cid']; @@ -807,25 +796,18 @@ class Item extends Controller { // if this is a wall-to-wall post to a group, turn it into a direct message - $role = get_pconfig($profile_uid,'system','permissions_role'); - - $rolesettings = PermissionRoles::role_perms($role); - - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; + $is_group = get_pconfig($profile_uid, 'system', 'group_actor'); - $is_group = (($channel_type === 'group') ? true : false); - - if (($is_group) && ($walltowall) && (! $walltowall_comment)) { - $groupww = true; + if (($is_group) && ($walltowall) && (!$walltowall_comment)) { + $groupww = true; $str_contact_allow = $owner_xchan['xchan_hash']; - $str_group_allow = ''; + $str_group_allow = ''; } $post_tags = []; - - if($mimetype === 'text/bbcode') { + if ($mimetype === 'text/bbcode') { require_once('include/text.php'); @@ -840,27 +822,27 @@ class Item extends Controller { $results = linkify_tags($body, ($uid) ? $uid : $profile_uid); - if($results) { + if ($results) { // Set permissions based on tag replacements set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $private, $parent_item); - foreach($results as $result) { + foreach ($results as $result) { $success = $result['success']; - if($success['replaced']) { - $post_tags[] = array( + if ($success['replaced']) { + $post_tags[] = [ 'uid' => $profile_uid, 'ttype' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url'] - ); + ]; } } } - if(($str_contact_allow) && (! $str_group_allow)) { + if (($str_contact_allow) && (!$str_group_allow)) { // direct message - private between individual channels but not groups $private = 2; } @@ -885,45 +867,45 @@ class Item extends Controller { * */ - if(! $preview) { - fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($summary,'[/crypt]')) ? $_POST['media_str'] : $summary),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + if (!$preview) { + fix_attached_photo_permissions($profile_uid, $owner_xchan['xchan_hash'], ((strpos($body, '[/crypt]')) ? $_POST['media_str'] : $body), $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + fix_attached_photo_permissions($profile_uid, $owner_xchan['xchan_hash'], ((strpos($summary, '[/crypt]')) ? $_POST['media_str'] : $summary), $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + fix_attached_file_permissions($channel, $observer['xchan_hash'], ((strpos($body, '[/crypt]')) ? $_POST['media_str'] : $body), $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); } $attachments = ''; - $match = false; + $match = false; - if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { - $attachments = array(); - $i = 0; - foreach($match[2] as $mtch) { + if (preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/', $body, $match)) { + $attachments = []; + $i = 0; + foreach ($match[2] as $mtch) { $attach_link = ''; - $hash = substr($mtch,0,strpos($mtch,',')); - $rev = intval(substr($mtch,strpos($mtch,','))); - $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev); - if($r['success']) { - $attachments[] = array( + $hash = substr($mtch, 0, strpos($mtch, ',')); + $rev = intval(substr($mtch, strpos($mtch, ','))); + $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev); + if ($r['success']) { + $attachments[] = [ 'href' => z_root() . '/attach/' . $r['data']['hash'], 'length' => $r['data']['filesize'], 'type' => $r['data']['filetype'], 'title' => urlencode($r['data']['filename']), 'revision' => $r['data']['revision'] - ); + ]; } - $body = str_replace($match[1][$i],$attach_link,$body); + $body = str_replace($match[1][$i], $attach_link, $body); $i++; } } - if(preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/',$body,$match)) { + if (preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/', $body, $match)) { // process share by id $i = 0; - foreach($match[2] as $mtch) { + foreach ($match[2] as $mtch) { $reshare = new \Zotlabs\Lib\Share($mtch); - $body = str_replace($match[1][$i],$reshare->bbcode(),$body); + $body = str_replace($match[1][$i], $reshare->bbcode(), $body); $i++; } } @@ -931,32 +913,32 @@ class Item extends Controller { // BBCODE end alert } - if(strlen($categories)) { + if (strlen($categories)) { - $cats = explode(',',$categories); - foreach($cats as $cat) { + $cats = explode(',', $categories); + foreach ($cats as $cat) { - if($webpage == ITEM_TYPE_CARD) { + if ($webpage == ITEM_TYPE_CARD) { $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); } - elseif($webpage == ITEM_TYPE_ARTICLE) { + elseif ($webpage == ITEM_TYPE_ARTICLE) { $catlink = z_root() . '/articles/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); } else { $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)); } - $post_tags[] = array( + $post_tags[] = [ 'uid' => $profile_uid, 'ttype' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), 'url' => $catlink - ); + ]; } } - if($orig_post) { + if ($orig_post) { // preserve original tags $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )", intval($orig_post['id']), @@ -966,120 +948,133 @@ class Item extends Controller { intval(TERM_FILE), intval(TERM_COMMUNITYTAG) ); - if($t) { - foreach($t as $t1) { - $post_tags[] = array( + if ($t) { + foreach ($t as $t1) { + $post_tags[] = [ 'uid' => $profile_uid, 'ttype' => $t1['ttype'], 'otype' => TERM_OBJ_POST, 'term' => $t1['term'], 'url' => $t1['url'], - ); + ]; } } } - $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); - $item_wall = (($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment') ? 1 : 0); - $item_origin = (($origin) ? 1 : 0); + $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); + $item_wall = (($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment') ? 1 : 0); + $item_origin = (($origin) ? 1 : 0); $item_consensus = (($consensus) ? 1 : 0); $item_nocomment = (($nocomment) ? 1 : 0); // determine if this is a wall post - if($parent) { + if ($parent) { $item_wall = $parent_item['item_wall']; } else { - if(! $webpage) { + if (!$webpage) { $item_wall = 1; } } - if($moderated) + if ($moderated) $item_blocked = ITEM_MODERATED; - if(! strlen($verb)) - $verb = ACTIVITY_POST ; + if (!strlen($verb)) + $verb = ACTIVITY_POST; - $notify_type = (($parent) ? 'comment-new' : 'wall-new' ); + $notify_type = (($parent) ? 'comment-new' : 'wall-new'); - if(! $mid) { - $uuid = (($message_id) ? $message_id : item_message_id()); - $mid = z_root() . '/item/' . $uuid; + $uuid = (($message_id) ? $message_id : item_message_id()); + + if (!$mid) { + $mid = z_root() . '/item/' . $uuid; } - if($is_poll) { + if ($is_poll) { $poll = [ - 'question' => $body, - 'answers' => $_REQUEST['poll_answers'], + 'question' => $body, + 'answers' => $_REQUEST['poll_answers'], 'multiple_answers' => $_REQUEST['poll_multiple_answers'], - 'expire_value' => $_REQUEST['poll_expire_value'], - 'expire_unit' => $_REQUEST['poll_expire_unit'] + 'expire_value' => $_REQUEST['poll_expire_value'], + 'expire_unit' => $_REQUEST['poll_expire_unit'] ]; - $obj = $this->extract_poll_data($poll, [ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + $obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]); } else { - $obj = $this->extract_bb_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + $obj = $this->extract_bb_poll_data($body, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]); } if ($obj) { - $obj['url'] = $mid; - $obj['attributedTo'] = channel_url($channel); - $datarray['obj'] = $obj; + $obj['url'] = $mid; + $obj['id'] = $mid; + $obj['diaspora:guid'] = $uuid; + $obj['attributedTo'] = channel_url($channel); + $obj['published'] = $created; + $obj['name'] = $title; + + $datarray['obj'] = $obj; + + if ($obj['endTime']) { + $d = datetime_convert('UTC','UTC', $obj['endTime']); + if ($d > NULL_DATE) { + $comments_closed = $d; + } + } + $obj_type = 'Question'; } - if(! $parent_mid) { + if (!$parent_mid) { $parent_mid = $mid; } - if($parent_item) + if ($parent_item) $parent_mid = $parent_item['mid']; - // Fallback so that we alway have a thr_parent - if(!$thr_parent) + if (!$thr_parent) $thr_parent = $mid; - $item_thread_top = ((! $parent) ? 1 : 0); + $item_thread_top = ((!$parent) ? 1 : 0); // fix permalinks for cards - if($webpage == ITEM_TYPE_CARD) { + if ($webpage == ITEM_TYPE_CARD) { $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); } - if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) { + if (($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) { $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1", intval($parent_item['id']) ); - if($r) { + if ($r) { $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . $r[0]['v']; } } - if($webpage == ITEM_TYPE_ARTICLE) { + if ($webpage == ITEM_TYPE_ARTICLE) { $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); } - if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) { + if (($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) { $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1", intval($parent_item['id']) ); - if($r) { + if ($r) { $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . $r[0]['v']; } } - if ((! $plink) && ($item_thread_top)) { + if ((!$plink) && ($item_thread_top)) { // $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid); // $plink = substr($plink,0,190); $plink = $mid; @@ -1097,6 +1092,7 @@ class Item extends Controller { $datarray['created'] = $created; $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); $datarray['expires'] = $expires; + $datarray['comments_closed'] = $comments_closed; $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); $datarray['received'] = (($orig_post) ? datetime_convert() : $created); $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); @@ -1152,33 +1148,33 @@ class Item extends Controller { // A specific ACL over-rides public_policy completely - if(! empty_acl($datarray)) + if (!empty_acl($datarray)) $datarray['public_policy'] = ''; - if($iconfig) + if ($iconfig) $datarray['iconfig'] = $iconfig; // preview mode - prepare the body for display and send it via json - if($preview) { + if ($preview) { require_once('include/conversation.php'); - $datarray['owner'] = $owner_xchan; + $datarray['owner'] = $owner_xchan; $datarray['author'] = $observer; $datarray['attach'] = json_encode($datarray['attach']); - $o = conversation(array($datarray),'search',false,'preview'); - // logger('preview: ' . $o, LOGGER_DEBUG); - echo json_encode(array('preview' => $o)); + $o = conversation([$datarray], 'search', false, 'preview'); + // logger('preview: ' . $o, LOGGER_DEBUG); + echo json_encode(['preview' => $o]); killme(); } - if($orig_post) + if ($orig_post) $datarray['edit'] = true; // suppress duplicates, *unless* you're editing an existing post. This could get picked up // as a duplicate if you're editing it very soon after posting it initially and you edited // some attribute besides the content, such as title or categories. - if(feature_enabled($profile_uid,'suppress_duplicates') && (! $orig_post)) { + if (feature_enabled($profile_uid, 'suppress_duplicates') && (!$orig_post)) { $z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1", intval($profile_uid), @@ -1187,45 +1183,45 @@ class Item extends Controller { dbesc($body) ); - if($z) { + if ($z) { $datarray['cancel'] = 1; - notice( t('Duplicate post suppressed.') . EOL); + notice(t('Duplicate post suppressed.') . EOL); logger('Duplicate post. Faking plugin cancel.'); } } - call_hooks('post_local',$datarray); + call_hooks('post_local', $datarray); - if(x($datarray,'cancel')) { + if (x($datarray, 'cancel')) { logger('mod_item: post cancelled by plugin or duplicate suppressed.'); - if($return_path) + if ($return_path) goaway(z_root() . "/" . $return_path); - if($api_source) - return ( [ 'success' => false, 'message' => 'operation cancelled' ] ); - $json = array('cancel' => 1); + if ($api_source) + return (['success' => false, 'message' => 'operation cancelled']); + $json = ['cancel' => 1]; $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; echo json_encode($json); killme(); } - if(mb_strlen($datarray['title']) > 191) - $datarray['title'] = mb_substr($datarray['title'],0,191); + if (mb_strlen($datarray['title']) > 191) + $datarray['title'] = mb_substr($datarray['title'], 0, 191); - if($webpage) { - IConfig::Set($datarray,'system', webpage_to_namespace($webpage), + if ($webpage) { + IConfig::Set($datarray, 'system', webpage_to_namespace($webpage), (($pagetitle) ? $pagetitle : basename($datarray['mid'])), true); } - elseif($namespace) { - IConfig::Set($datarray,'system', $namespace, + elseif ($namespace) { + IConfig::Set($datarray, 'system', $namespace, (($remote_id) ? $remote_id : basename($datarray['mid'])), true); } - if($orig_post) { + if ($orig_post) { $datarray['id'] = $post_id; - $x = item_store_update($datarray,$execflag); + $x = item_store_update($datarray, $execflag); // We only need edit activities for other federated protocols // which do not support edits natively. While this does federate @@ -1239,82 +1235,80 @@ class Item extends Controller { // item_create_edit_activity($x); - if(! $parent) { + if (!$parent) { $r = q("select * from item where id = %d", intval($post_id) ); - if($r) { + if ($r) { xchan_query($r); $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true)))); + Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]); } } - if(! $nopush) - Master::Summon([ 'Notifier', 'edit_post', $post_id ]); + if (!$nopush) + Master::Summon(['Notifier', 'edit_post', $post_id]); - if($api_source) - return($x); + if ($api_source) + return ($x); - if((x($_REQUEST,'return')) && strlen($return_path)) { + if ((x($_REQUEST, 'return')) && strlen($return_path)) { logger('return: ' . $return_path); - goaway(z_root() . "/" . $return_path ); + goaway(z_root() . "/" . $return_path); } killme(); } - else - $post_id = 0; - $post = item_store($datarray,$execflag); + $post = item_store($datarray, $execflag); $post_id = $post['item_id']; $datarray = $post['item']; - if($post_id) { + if ($post_id) { logger('mod_item: saved item ' . $post_id); - if($parent) { + if ($parent) { // prevent conversations which you are involved from being expired - if(local_channel()) + if (local_channel()) retain_item($parent); // only send comment notification if this is a wall-to-wall comment, // otherwise it will happen during delivery - if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) { - Enotify::submit(array( - 'type' => NOTIFY_COMMENT, - 'from_xchan' => $datarray['author_xchan'], - 'to_xchan' => $datarray['owner_xchan'], - 'item' => $datarray, - 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), - 'verb' => ACTIVITY_POST, - 'otype' => 'item', - 'parent' => $parent, - 'parent_mid' => $parent_item['mid'] - )); + if (($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) { + Enotify::submit([ + 'type' => NOTIFY_COMMENT, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), + 'verb' => ACTIVITY_POST, + 'otype' => 'item', + 'parent' => $parent, + 'parent_mid' => $parent_item['mid'] + ]); } } else { $parent = $post_id; - if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) { - Enotify::submit(array( - 'type' => NOTIFY_WALL, - 'from_xchan' => $datarray['author_xchan'], - 'to_xchan' => $datarray['owner_xchan'], - 'item' => $datarray, - 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), - 'verb' => ACTIVITY_POST, - 'otype' => 'item' - )); + if (($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) { + Enotify::submit([ + 'type' => NOTIFY_WALL, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), + 'verb' => ACTIVITY_POST, + 'otype' => 'item' + ]); } - if($uid && $uid == $profile_uid && (is_item_normal($datarray))) { + if ($uid && $uid == $profile_uid && (is_item_normal($datarray))) { q("update channel set channel_lastpost = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($uid) @@ -1326,7 +1320,7 @@ class Item extends Controller { // This way we don't see every picture in your new photo album posted to your wall at once. // They will show up as people comment on them. - if(intval($parent_item['item_hidden'])) { + if (intval($parent_item['item_hidden'])) { $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", intval($parent_item['id']) ); @@ -1334,22 +1328,22 @@ class Item extends Controller { } else { logger('mod_item: unable to retrieve post that was just stored.'); - notice( t('System error. Post not saved.') . EOL); - if($return_path) - goaway(z_root() . "/" . $return_path ); - if($api_source) - return ( [ 'success' => false, 'message' => 'system error' ] ); + notice(t('System error. Post not saved.') . EOL); + if ($return_path) + goaway(z_root() . "/" . $return_path); + if ($api_source) + return (['success' => false, 'message' => 'system error']); killme(); } - if($parent || $datarray['item_private'] == 1) { + if ($parent || $datarray['item_private'] == 1) { $r = q("select * from item where id = %d", intval($post_id) ); - if($r) { + if ($r) { xchan_query($r); $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true)))); + Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]); } } @@ -1362,46 +1356,46 @@ class Item extends Controller { $nopush = false; } - if(! $nopush) - Master::Summon([ 'Notifier', $notify_type, $post_id ]); + if (!$nopush) + Master::Summon(['Notifier', $notify_type, $post_id]); logger('post_complete'); - if($moderated) { + if ($moderated) { info(t('Your comment is awaiting approval.') . EOL); } // figure out how to return, depending on from whence we came - if($api_source) + if ($api_source) return $post; - if($return_path) { - if($return_path === 'hq') { + if ($return_path) { + if ($return_path === 'hq') { goaway(z_root() . '/hq/' . gen_link_id($datarray['mid'])); } goaway(z_root() . "/" . $return_path); } - if($mode === 'channel') + if ($mode === 'channel') profile_load($channel['channel_address']); - $item[] = $datarray; - $item[0]['owner'] = $owner_xchan; + $item[] = $datarray; + $item[0]['owner'] = $owner_xchan; $item[0]['author'] = $observer; $item[0]['attach'] = $datarray['attach']; $json = [ 'success' => 1, - 'id' => $post_id, - 'html' => conversation($item,$mode,true,'r_preview'), + 'id' => $post_id, + 'html' => conversation($item, $mode, true, 'r_preview'), ]; - if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload'])) + if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; - logger('post_json: ' . print_r($json,true), LOGGER_DEBUG); + logger('post_json: ' . print_r($json, true), LOGGER_DEBUG); echo json_encode($json); killme(); @@ -1411,10 +1405,10 @@ class Item extends Controller { function get() { - if((! local_channel()) && (! remote_channel())) + if ((!local_channel()) && (!remote_channel())) return; - if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { + if ((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { require_once('include/items.php'); @@ -1423,16 +1417,16 @@ class Item extends Controller { intval(argv(2)) ); - if($i) { - $can_delete = false; + if ($i) { + $can_delete = false; $local_delete = false; - if(local_channel() && local_channel() == $i[0]['uid']) { + if (local_channel() && local_channel() == $i[0]['uid']) { $local_delete = true; } $ob_hash = get_observer_hash(); - if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { + if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { $can_delete = true; } @@ -1440,15 +1434,15 @@ class Item extends Controller { // If the item originated on this site+channel the deletion will propagate downstream. // Otherwise just the local copy is removed. - if(is_site_admin()) { + if (is_site_admin()) { $local_delete = true; - if(intval($i[0]['item_origin'])) + if (intval($i[0]['item_origin'])) $can_delete = true; } - if(! ($can_delete || $local_delete)) { - notice( t('Permission denied.') . EOL); + if (!($can_delete || $local_delete)) { + notice(t('Permission denied.') . EOL); return; } @@ -1457,35 +1451,34 @@ class Item extends Controller { $complex = false; - if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { + if (intval($i[0]['item_type']) || ($local_delete && (!$can_delete))) { drop_item($i[0]['id']); } else { // complex deletion that needs to propagate and be performed in phases - drop_item($i[0]['id'],true,DROPITEM_PHASE1); + drop_item($i[0]['id'], true, DROPITEM_PHASE1); $complex = true; } $r = q("select * from item where id = %d", intval($i[0]['id']) ); - if($r) { + if ($r) { xchan_query($r); $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true)))); + Libsync::build_sync_packet($i[0]['uid'], ['item' => [encode_item($sync_item[0], true)]]); } - if($complex) { - tag_deliver($i[0]['uid'],$i[0]['id']); + if ($complex) { + tag_deliver($i[0]['uid'], $i[0]['id']); } } } } - - function item_check_service_class($channel_id,$iswebpage) { - $ret = array('success' => false, 'message' => ''); + function item_check_service_class($channel_id, $iswebpage) { + $ret = ['success' => false, 'message' => '']; if ($iswebpage) { $r = q("select count(i.id) as total from item i @@ -1501,23 +1494,23 @@ class Item extends Controller { ); } - if(! $r) { + if (!$r) { $ret['message'] = t('Unable to obtain post information from database.'); return $ret; } if (!$iswebpage) { - $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_items')); - if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) { - $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f top level posts.'),$max); - return $result; + $max = engr_units_to_bytes(service_class_fetch($channel_id, 'total_items')); + if (!service_class_allows($channel_id, 'total_items', $r[0]['total'])) { + $ret['message'] .= upgrade_message() . sprintf(t('You have reached your limit of %1$.0f top level posts.'), $max); + return $ret; } } else { - $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_pages')); - if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) { - $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f webpages.'),$max); - return $result; + $max = engr_units_to_bytes(service_class_fetch($channel_id, 'total_pages')); + if (!service_class_allows($channel_id, 'total_pages', $r[0]['total'])) { + $ret['message'] .= upgrade_message() . sprintf(t('You have reached your limit of %1$.0f webpages.'), $max); + return $ret; } } @@ -1525,51 +1518,51 @@ class Item extends Controller { return $ret; } - function extract_bb_poll_data(&$body,$item) { + function extract_bb_poll_data(&$body, $item) { $multiple = false; - if (strpos($body,'[/question]') === false && strpos($body,'[/answer]') === false) { + if (strpos($body, '[/question]') === false && strpos($body, '[/answer]') === false) { return false; } - if (strpos($body,'[nobb]') !== false) { + if (strpos($body, '[nobb]') !== false) { return false; } - $obj = []; - $ptr = []; - $matches = null; + $obj = []; + $ptr = []; + $matches = null; $obj['type'] = 'Question'; - if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism',$body,$matches,PREG_SET_ORDER)) { + if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism', $body, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { - $ptr[] = [ 'name' => $match[1], 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]]; - $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body); + $ptr[] = ['name' => $match[1], 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body); } } $matches = null; - if (preg_match('/\[question\](.*?)\[\/question\]/ism',$body,$matches)) { + if (preg_match('/\[question\](.*?)\[\/question\]/ism', $body, $matches)) { $obj['content'] = bbcode($matches[1]); - $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); - $obj['oneOf'] = $ptr; + $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['oneOf'] = $ptr; } $matches = null; - if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) { + if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism', $body, $matches)) { $obj['content'] = bbcode($matches[1]); - $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); - $obj['anyOf'] = $ptr; + $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['anyOf'] = $ptr; } $matches = null; - if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) { - $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); - $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); + if (preg_match('/\[ends\](.*?)\[\/ends\]/ism', $body, $matches)) { + $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', $matches[1], ATOM_TIME); + $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); } @@ -1577,7 +1570,7 @@ class Item extends Controller { $obj['to'] = Activity::map_acl($item); } else { - $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $obj['to'] = [ACTIVITY_PUBLIC_INBOX]; } return $obj; @@ -1587,23 +1580,23 @@ class Item extends Controller { function extract_poll_data($poll, $item) { - $multiple = intval($poll['multiple_answers']); + $multiple = intval($poll['multiple_answers']); $expire_value = intval($poll['expire_value']); - $expire_unit = $poll['expire_unit']; - $question = $poll['question']; - $answers = $poll['answers']; + $expire_unit = $poll['expire_unit']; + $question = $poll['question']; + $answers = $poll['answers']; - $obj = []; - $ptr = []; - $obj['type'] = 'Question'; + $obj = []; + $ptr = []; + $obj['type'] = 'Question'; $obj['content'] = bbcode($question); - foreach($answers as $answer) { - if(trim($answer)) - $ptr[] = [ 'name' => escape_tags($answer), 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]]; + foreach ($answers as $answer) { + if (trim($answer)) + $ptr[] = ['name' => escape_tags($answer), 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; } - if($multiple) { + if ($multiple) { $obj['anyOf'] = $ptr; } else { @@ -1612,11 +1605,13 @@ class Item extends Controller { $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME); + $obj['directMessage'] = (intval($item['item_private']) === 2); + if ($item['item_private']) { $obj['to'] = Activity::map_acl($item); } else { - $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $obj['to'] = [ACTIVITY_PUBLIC_INBOX]; } return $obj; @@ -1624,5 +1619,4 @@ class Item extends Controller { } - } diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index e3fe4a954..8b36e8396 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -91,6 +91,12 @@ class Like extends Controller { 'id' => $arr['item']['id'], 'html' => conversation($items, $conv_mode, true, $page_mode), ]; + + // mod photos + if (isset($_REQUEST['reload']) && $_REQUEST['reload']) { + $ret['reload'] = 1; + } + return $ret; } diff --git a/Zotlabs/Module/Lockview.php b/Zotlabs/Module/Lockview.php index 11c781df0..3637482c7 100644 --- a/Zotlabs/Module/Lockview.php +++ b/Zotlabs/Module/Lockview.php @@ -1,21 +1,30 @@ <?php + namespace Zotlabs\Module; +use Zotlabs\Lib\AccessList; +use Zotlabs\Web\Controller; + require_once('include/security.php'); -class Lockview extends \Zotlabs\Web\Controller { +class Lockview extends Controller { function get() { - $atokens = array(); + $atokens = []; + $atoken_xchans = []; + $access_list = []; + $guest_access_list = []; - if(local_channel()) { + if (local_channel()) { $at = q("select * from atoken where atoken_uid = %d", intval(local_channel()) ); - if($at) { - foreach($at as $t) { - $atokens[] = atoken_xchan($t); + if ($at) { + foreach ($at as $t) { + $atoken_xchan = atoken_xchan($t); + $atokens[] = array_merge($t, $atoken_xchan); + $atoken_xchans[] = $atoken_xchan['xchan_hash']; } } } @@ -23,20 +32,20 @@ class Lockview extends \Zotlabs\Web\Controller { $type = ((argc() > 1) ? argv(1) : 0); if (is_numeric($type)) { $item_id = intval($type); - $type='item'; + $type = 'item'; } else { $item_id = ((argc() > 2) ? intval(argv(2)) : 0); } - if(! $item_id) + if (!$item_id) killme(); - if (! in_array($type, array('item', 'photo', 'attach', 'event', 'menu_item', 'chatroom'))) + if (!in_array($type, ['item', 'photo', 'attach', 'menu_item', 'chatroom'])) killme(); // we have different naming in in menu_item table and chatroom table - switch($type) { + switch ($type) { case 'menu_item': $id = 'mitem_id'; break; @@ -53,134 +62,177 @@ class Lockview extends \Zotlabs\Web\Controller { intval($item_id) ); - if(! $r) + if (!$r) killme(); $item = $r[0]; + $uid = null; + $url = ''; - //we have different naming in in menu_item table and chatroom table - switch($type) { + switch ($type) { case 'menu_item': $uid = $item['mitem_channel_id']; break; case 'chatroom': - $uid = $item['cr_uid']; + $uid = $item['cr_uid']; + $channel = channelx_by_n($uid); + $url = z_root() . '/chat/' . $channel['channel_address'] . '/' . $item['cr_id']; break; - default: + case 'item': $uid = $item['uid']; + $url = $item['plink']; + break; + case 'photo': + $uid = $item['uid']; + $channel = channelx_by_n($uid); + $url = z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $item['resource_id']; + break; + case 'attach': + $uid = $item['uid']; + $channel = channelx_by_n($uid); + $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $item['display_path']; + break; + default: break; } - if($uid != local_channel()) { - echo '<div class="dropdown-item">' . t('Remote privacy information not available.') . '</div>'; + if (intval($uid) !== local_channel()) { + echo '<div class="dropdown-item-text">' . t('Remote privacy information not available') . '</div>'; killme(); } - if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) - && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { + if (intval($item['item_private']) && (!strlen($item['allow_cid'])) && (!strlen($item['allow_gid'])) + && (!strlen($item['deny_cid'])) && (!strlen($item['deny_gid']))) { // if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any // specific recipients, we're the recipient of a post with "bcc" or targeted recipients; so we'll just show it // as unknown specific recipients. The sender will have the visibility list and will fall through to the // next section. - echo '<div class="dropdown-item">' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>'; + echo '<div class="dropdown-item-text">' . translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>'; killme(); } - $allowed_users = expand_acl($item['allow_cid']); + $allowed_users = expand_acl($item['allow_cid']); $allowed_groups = expand_acl($item['allow_gid']); - $deny_users = expand_acl($item['deny_cid']); - $deny_groups = expand_acl($item['deny_gid']); - - $o = '<div class="dropdown-item">' . t('Visible to:') . '</div>'; - $l = array(); + $deny_users = expand_acl($item['deny_cid']); + $deny_groups = expand_acl($item['deny_gid']); - stringify_array_elms($allowed_groups,true); - stringify_array_elms($allowed_users,true); - stringify_array_elms($deny_groups,true); - stringify_array_elms($deny_users,true); + stringify_array_elms($allowed_groups, true); + stringify_array_elms($allowed_users, true); + stringify_array_elms($deny_groups, true); + stringify_array_elms($deny_users, true); + $allowed_xchans = []; $profile_groups = []; - if($allowed_groups) { - foreach($allowed_groups as $g) { - if(substr($g,0,4) === '\'vp.') { - $profile_groups[] = '\'' . substr($g,4); + if ($allowed_groups) { + foreach ($allowed_groups as $g) { + if (substr($g, 0, 4) === '\'vp.') { + $profile_groups[] = '\'' . substr($g, 4); } } } - if(count($profile_groups)) { - $r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item"><b>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</b></div>'; - } - - if(count($allowed_groups)) { - $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item"><b>' . $rr['gname'] . '</b></div>'; - } - if(count($allowed_users)) { - $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item">' . $rr['xchan_name'] . '</div>'; - if($atokens) { - foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) { - $l[] = '<div class="dropdown-item">' . $at['xchan_name'] . '</div>'; - } + + if ($profile_groups) { + $r = q("SELECT id, profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )"); + if ($r) { + foreach ($r as $rr) { + $pgrp_members = AccessList::profile_members_xchan($uid, $rr['id']); + $allowed_xchans = array_merge($allowed_xchans, $pgrp_members); + $access_list[] = '<div class="dropdown-item-text" title="' . t('Profile', 'acl') . '">' . $rr['profile_name'] . '</div>'; + } + } + } + + if ($allowed_groups) { + $r = q("SELECT id, gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); + if ($r) { + foreach ($r as $rr) { + $pgrp_members = AccessList::members_xchan($uid, $rr['id']); + $allowed_xchans = array_merge($allowed_xchans, $pgrp_members); + $access_list[] = '<div class="dropdown-item-text" title="' . t('Privacy group') . '">' . $rr['gname'] . '</div>'; } } } + if ($allowed_users) { + $r = q("SELECT xchan_name, xchan_hash FROM xchan WHERE xchan_hash IN ( " . implode(', ', $allowed_users) . " )"); + if ($r) { + foreach ($r as $rr) { + $allowed_xchans[] = $rr['xchan_hash']; + if (!in_array($rr['xchan_hash'], $atoken_xchans)) { + $access_list[] = '<div class="dropdown-item-text">' . $rr['xchan_name'] . '</div>'; + } + } + } + } $profile_groups = []; - if($deny_groups) { - foreach($deny_groups as $g) { - if(substr($g,0,4) === '\'vp.') { - $profile_groups[] = '\'' . substr($g,4); + if ($deny_groups) { + foreach ($deny_groups as $g) { + if (substr($g, 0, 4) === '\'vp.') { + $profile_groups[] = '\'' . substr($g, 4); } } } - if(count($profile_groups)) { + + if ($profile_groups) { $r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item"><b><strike>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</strike></b></div>'; + if ($r) { + foreach ($r as $rr) { + $access_list[] = '<div class="dropdown-item-text" title="' . t('Profile', 'acl') . '"><strike>' . $rr['profile_name'] . '</strike></b></div>'; + } + } } - - - if(count($deny_groups)) { + if ($deny_groups) { $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item"><b><strike>' . $rr['gname'] . '</strike></b></div>'; + if ($r) { + foreach ($r as $rr) { + $access_list[] = '<div class="dropdown-item-text" title="' . t('Privacy group') . '"><strike>' . $rr['gname'] . '</strike></b></div>'; + } + } } - if(count($deny_users)) { + + if ($deny_users) { $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); - if($r) - foreach($r as $rr) - $l[] = '<div class="dropdown-item"><strike>' . $rr['xchan_name'] . '</strike></div>'; - - if($atokens) { - foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) { - $l[] = '<div class="dropdown-item"><strike>' . $at['xchan_name'] . '</strike></div>'; - } + if ($r) { + foreach ($r as $rr) { + $access_list[] = '<div class="dropdown-item-text"><strike>' . $rr['xchan_name'] . '</strike></div>'; } } + } + + if ($atokens && $allowed_xchans && $url) { + $guest_access_list = []; + $allowed_xchans = array_unique($allowed_xchans); + foreach ($atokens as $atoken) { + if (in_array($atoken['xchan_hash'], $allowed_xchans)) { + $guest_access_list[] = '<div class="dropdown-item d-flex justify-content-between cursor-pointer" title="' . sprintf(t('Click to copy link to this ressource for guest %s to clipboard'), $atoken['xchan_name']) . '" data-token="' . $url . '?zat=' . $atoken['atoken_token'] . '" onclick="navigator.clipboard.writeText(this.dataset.token); $.jGrowl(\'' . t('Link copied') . '\', { sticky: false, theme: \'info\', life: 1000 });"><span>' . $atoken['xchan_name'] . '</span><i class="fa fa-copy p-1"></i></div>'; + } + } } - echo $o . implode($l); - killme(); + $access_list_header = ''; + if ($access_list) { + $access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Access') . '</div>'; + } + $guest_access_list_header = ''; + if ($guest_access_list) { + $guest_access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Guest access') . '</div>'; + } + + $divider = ''; + if ($access_list && $guest_access_list) { + $divider = '<div class="dropdown-divider"></div>'; + } + + echo $access_list_header . implode($access_list) . $divider . $guest_access_list_header . implode($guest_access_list); + killme(); } diff --git a/Zotlabs/Module/Manifest.php b/Zotlabs/Module/Manifest.php index 6fe468a14..4c418a56a 100644 --- a/Zotlabs/Module/Manifest.php +++ b/Zotlabs/Module/Manifest.php @@ -4,11 +4,15 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\System; +use Zotlabs\Render\Theme; class Manifest extends Controller { function init() { + // populate App::$theme_info + Theme::current(); + $ret = [ 'name' => ucfirst(System::get_platform_name()), 'short_name' => ucfirst(System::get_platform_name()), @@ -18,15 +22,16 @@ class Manifest extends Controller { [ 'src' => '/images/app/hz-128.png', 'sizes' => '128x128', 'type' => 'image/png' ], [ 'src' => '/images/app/hz-144.png', 'sizes' => '144x144', 'type' => 'image/png' ], [ 'src' => '/images/app/hz-152.png', 'sizes' => '152x152', 'type' => 'image/png' ], - [ 'src' => '/images/app/hz-192.png', 'sizes' => '192x192', 'type' => 'image/png' ], + [ 'src' => '/images/app/hz-192.png', 'sizes' => '192x192', 'type' => 'image/png', 'purpose' => 'any maskable' ], [ 'src' => '/images/app/hz-348.png', 'sizes' => '384x384', 'type' => 'image/png' ], [ 'src' => '/images/app/hz-512.png', 'sizes' => '512x512', 'type' => 'image/png' ], [ 'src' => '/images/app/hz.svg', 'sizes' => '64x64', 'type' => 'image/xml+svg' ] ], + 'theme_color' => App::$theme_info['theme_color'], + 'background_color' => App::$theme_info['background_color'], 'scope' => '/', 'start_url' => z_root(), 'display' => 'standalone', - 'orientation' => 'any', 'share_target' => [ 'action' => '/rpost', 'method' => 'POST', diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 03c56b9a2..016a0a309 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -1,12 +1,11 @@ <?php namespace Zotlabs\Module; -use Zotlabs\Lib\Group; +use Zotlabs\Lib\AccessList; use Zotlabs\Lib\Apps; use App; require_once('include/items.php'); -require_once('include/group.php'); require_once('include/contact_widgets.php'); require_once('include/conversation.php'); require_once('include/acl_selectors.php'); @@ -233,7 +232,7 @@ class Network extends \Zotlabs\Web\Controller { if($group) { $contact_str = ''; - $contacts = group_get_members($group); + $contacts = AccessList::members(local_channel(), $group); if($contacts) { $contact_str = ids_to_querystr($contacts, 'xchan', true); } @@ -246,7 +245,7 @@ class Network extends \Zotlabs\Web\Controller { $item_thread_top = ''; $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) "; - $x = group_rec_byhash(local_channel(), $group_hash); + $x = AccessList::by_hash(local_channel(), $group_hash); if($x) { $title = replace_macros(get_markup_template('section_title.tpl'), array( diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php index 84d492f8f..5989e3da6 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -1,6 +1,8 @@ <?php namespace Zotlabs\Module; +use URLify; + require_once('include/channel.php'); require_once('include/permissions.php'); @@ -13,7 +15,6 @@ class New_channel extends \Zotlabs\Web\Controller { $cmd = ((argc() > 1) ? argv(1) : ''); if($cmd === 'autofill.json') { - require_once('library/urlify/URLify.php'); $result = array('error' => false, 'message' => ''); $n = trim($_REQUEST['name']); @@ -24,7 +25,7 @@ class New_channel extends \Zotlabs\Web\Controller { } if((! $x) || strlen($x) > 64) - $x = strtolower(\URLify::transliterate($n)); + $x = strtolower(URLify::transliterate($n)); $test = array(); @@ -46,7 +47,6 @@ class New_channel extends \Zotlabs\Web\Controller { } if($cmd === 'checkaddr.json') { - require_once('library/urlify/URLify.php'); $result = array('error' => false, 'message' => ''); $n = trim($_REQUEST['nick']); if(! $n) { @@ -60,7 +60,7 @@ class New_channel extends \Zotlabs\Web\Controller { } if((! $x) || strlen($x) > 64) - $x = strtolower(\URLify::transliterate($n)); + $x = strtolower(URLify::transliterate($n)); $test = array(); @@ -170,12 +170,12 @@ class New_channel extends \Zotlabs\Web\Controller { $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" ); - $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + $perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles(); $name = array('name', t('Channel name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), $name_help, "*"); $nickhub = '@' . \App::get_hostname(); $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*"); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.') . '<br>' . '<a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles); + $role = array('permissions_role' , t('Channel role'), ($privacy_role) ? $privacy_role : 'personal', '', $perm_roles); $o = replace_macros(get_markup_template('new_channel.tpl'), array( '$title' => t('Create a Channel'), diff --git a/Zotlabs/Module/Permcats.php b/Zotlabs/Module/Permcats.php index 58566373a..8be5bba88 100644 --- a/Zotlabs/Module/Permcats.php +++ b/Zotlabs/Module/Permcats.php @@ -6,6 +6,7 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; +use Zotlabs\Lib\AccessList; class Permcats extends Controller { @@ -14,24 +15,94 @@ class Permcats extends Controller { if(! local_channel()) return; - if(! Apps::system_app_installed(local_channel(), 'Permission Categories')) - return; - $channel = App::get_channel(); check_form_security_token_redirectOnErr('/permcats', 'permcats'); + $name = escape_tags(trim($_REQUEST['name'])); + $is_system_role = isset($_REQUEST['is_system_role']); + $return_path = z_root() . '/permcats/' . $_REQUEST['return_path']; + $group_hash = $_REQUEST['group_select'] ?? ''; + $deleted_role = $_REQUEST['deleted_role'] ?? ''; + $new_role = $_REQUEST['new_role'] ?? ''; + $contacts = []; - $all_perms = \Zotlabs\Access\Permissions::Perms(); + if (argv(1) && hex2bin(argv(1)) !== $name) { + $return_path = z_root() . '/permcats/' . bin2hex($name); + } + + if($deleted_role && $new_role) { + $r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_role = '%s' AND abook_self = 0 AND abook_pending = 0", + intval(local_channel()), + dbesc($deleted_role) + ); + + if ($r) { + $contacts = ids_to_array($r, 'abook_xchan'); + } + + if ($contacts) { + \Zotlabs\Lib\Permcat::assign($channel, $new_role, $contacts); + } + + \Zotlabs\Lib\Permcat::delete(local_channel(), $deleted_role); + + $default_role = get_pconfig(local_channel(), 'system', 'default_permcat', 'default'); + if($deleted_role === $default_role) { + set_pconfig(local_channel(), 'system', 'default_permcat', $new_role); + } + + Libsync::build_sync_packet(); + info(t('Contact role deleted.') . EOL); - $name = escape_tags(trim($_POST['name'])); - if(! $name) { + goaway(z_root() . '/permcats/' . bin2hex($new_role)); + + return; + } + + if ($group_hash === 'all_contacts') { + $r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d and abook_self = 0 and abook_pending = 0", + intval(local_channel()) + ); + + if ($r) { + $contacts = ids_to_array($r, 'abook_xchan'); + } + } + + if (!$contacts && $group_hash) { + $group = AccessList::by_hash(local_channel(), $group_hash); + } + + if ($group) { + $contacts = AccessList::members_xchan(local_channel(), $group['id']); + } + + if(! $name ) { notice( t('Permission category name is required.') . EOL); return; } + set_pconfig(local_channel(), 'system', 'default_permcat', 'default'); + + if (isset($_REQUEST['default_role'])) { + set_pconfig(local_channel(), 'system', 'default_permcat', $name); + } + + if ($is_system_role) { + // if we have a system role just set the default and assign if aplicable and be done with it + if ($contacts) { + \Zotlabs\Lib\Permcat::assign($channel, $name, $contacts); + } + + info( t('Contact role saved.') . EOL); + Libsync::build_sync_packet(); + goaway($return_path); + return; + } $pcarr = []; + $all_perms = \Zotlabs\Access\Permissions::Perms(); if($all_perms) { foreach($all_perms as $perm => $desc) { @@ -41,11 +112,16 @@ class Permcats extends Controller { } } - \Zotlabs\Lib\Permcat::update(local_channel(),$name,$pcarr); + \Zotlabs\Lib\Permcat::update(local_channel(), $name, $pcarr); + + if ($contacts) { + \Zotlabs\Lib\Permcat::assign($channel, $name, $contacts); + } Libsync::build_sync_packet(); - info( t('Permission category saved.') . EOL); + info( t('Contact role saved.') . EOL); + goaway($return_path); return; } @@ -56,41 +132,51 @@ class Permcats extends Controller { if(! local_channel()) return; - if(! Apps::system_app_installed(local_channel(), 'Permission Categories')) { - //Do not display any associated widgets at this point - App::$pdl = ''; - $papp = Apps::get_papp('Permission Categories'); - return Apps::app_render($papp, 'module'); - } + nav_set_selected('Contact Roles'); $channel = App::get_channel(); - if(argc() > 1) + if(argc() > 1) { $name = hex2bin(argv(1)); - - if(argc() > 2 && argv(2) === 'drop') { - \Zotlabs\Lib\Permcat::delete(local_channel(),$name); - Libsync::build_sync_packet(); - json_return_and_die([ 'success' => true ]); } - - $desc = t('Use this form to create permission rules for various classes of people or connections.'); - $existing = []; $pcat = new \Zotlabs\Lib\Permcat(local_channel()); $pcatlist = $pcat->listing(); - $permcats = []; + + $is_system_role = false; + $delete_role_select_options = []; + $is_default_role = (get_pconfig(local_channel(),'system','default_permcat','default') === $name); + if($pcatlist) { foreach($pcatlist as $pc) { - if(($pc['name']) && ($name) && ($pc['name'] == $name)) + if(($pc['name']) && ($name) && ($pc['name'] == $name)) { $existing = $pc['perms']; - if(! $pc['system']) - $permcats[bin2hex($pc['name'])] = $pc['localname']; + if (isset($pc['system']) && intval($pc['system'])) + $is_system_role = $pc['name']; + } + + if($pc['name'] == $name) { + $localname = $pc['localname']; + } + + if ($pc['name'] !== $name) { + $delete_role_select_options[$pc['name']] = $pc['localname']; + } + } } + // select for delete action + $delete_role_select = [ + 'new_role', + (($is_default_role) ? t('Role to assign affected contacts and default role to') : t('Role to assign affected contacts to')), + '', + '', + $delete_role_select_options + ]; + $global_perms = \Zotlabs\Access\Permissions::Perms(); foreach($global_perms as $k => $v) { @@ -98,33 +184,53 @@ class Permcats extends Controller { $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k); if($existing[$k]) - $thisperm = "1"; - - $perms[] = array('perms_' . $k, $v, '',$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + $thisperm = 1; + + $perms[] = [ + 'perms_' . $k, + $v, + '', + $thisperm, + 1, + (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), + '', + $checkinherited + ]; } + $group_select_options = [ + 'selected' => '', + 'form_id' => 'group_select', + 'label' => t('Assign this role to'), + 'after' => [ + 'name' => t('All my contacts'), + 'id' => 'all_contacts', + 'selected' => false + ] + ]; + + $group_select = AccessList::select(local_channel(), $group_select_options); $tpl = get_markup_template("permcats.tpl"); $o .= replace_macros($tpl, array( '$form_security_token' => get_form_security_token("permcats"), - '$title' => t('Permission Categories'), - '$desc' => $desc, - '$desc2' => $desc2, - '$tokens' => $t, - '$permcats' => $permcats, - '$atoken' => $atoken, - '$url1' => z_root() . '/channel/' . $channel['channel_address'], - '$url2' => z_root() . '/photos/' . $channel['channel_address'], - '$name' => array('name', t('Permission category name') . ' <span class="required">*</span>', (($name) ? $name : ''), ''), - '$me' => t('My Settings'), + '$default_role' => array('default_role', t('Automatically assign this role to new contacts'), intval($is_default_role), '', [t('No'), t('Yes')]), + '$title' => t('Contact Roles'), + '$name' => ['name', t('Role name') . ' <span class="required">*</span>', (($localname) ? $localname : ''), (($is_system_role) ? t('System role - not editable') : '') , '', (($is_system_role) ? 'disabled' : '')], + '$delete_label' => t('Deleting') . ' ' . $localname, + '$current_role' => $name, '$perms' => $perms, '$inherited' => t('inherited'), - '$notself' => 0, - '$self' => 1, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), - '$submit' => t('Submit') + '$is_system_role' => $is_system_role, + '$permlbl' => t('Role Permissions'), + '$permnote' => t('Some permissions may be inherited from your <a href="settings">channel role</a>, which have higher priority than contact role settings.'), + '$submit' => t('Submit'), + '$return_path' => argv(1), + '$group_select' => $group_select, + '$delete_role_select' => $delete_role_select, + '$delet_role_button' => t('Delete') + )); return $o; } diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index d6c80b653..661694d18 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -1,7 +1,11 @@ <?php + namespace Zotlabs\Module; +use App; +use Zotlabs\Daemon\Master; use Zotlabs\Lib\Libsync; +use Zotlabs\Web\Controller; /* * @file Profile_photo.php @@ -15,109 +19,123 @@ require_once('include/photos.php'); require_once('include/channel.php'); /* @brief Function for sync'ing permissions of profile-photos and their profile -* -* @param $profileid The id number of the profile to sync -* @return void -*/ - + * + */ +class Profile_photo extends Controller { -class Profile_photo extends \Zotlabs\Web\Controller { - /* @brief Initalize the profile-photo edit view * - * @return void - * */ - + function init() { - - if(! local_channel()) { + + if (!local_channel()) { return; } - - $channel = \App::get_channel(); - profile_load($channel['channel_address']); - + + $channel = App::get_channel(); + $profile = App::$argv[1]; + + profile_load($channel['channel_address'], $profile); + + } - + /* @brief Evaluate posted values * - * @param $a Current application - * @return void - * */ - + function post() { - - if(! local_channel()) { + + if (!local_channel()) { return; } - - $channel = \App::get_channel(); - + + $channel = App::get_channel(); + check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); - - // Remove cover photo - if(isset($_POST['remove'])) { - - $r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1", - intval(PHOTO_PROFILE), - intval(local_channel()) - ); - - if($r) { - q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - intval(local_channel()) - ); - - $sync = attach_export_data($channel,$r[0]['resource_id']); - if($sync) - Libsync:: build_sync_packet($channel['channel_id'],array('file' => array($sync))); + + $r = q("select id, profile_guid, is_default, gender from profile where uid = %d", + intval(local_channel()) + ); + + $profile_id = intval($_POST['profile']); + $default_profile_id = null; + $profile = []; + + foreach ($r as $rr) { + if ($rr['is_default']) { + $default_profile_id = intval($rr['id']); } - + + if ($profile_id === intval($rr['id'])) { + $profile = $rr; + } + } + + $is_default_profile = ($profile_id === $default_profile_id); + + // Remove profile photo + if (isset($_POST['remove'])) { + + if ($is_default_profile) { + + $r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1", + intval(PHOTO_PROFILE), + intval(local_channel()) + ); + + if ($r) { + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval(local_channel()) + ); + + q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d", + dbesc(z_root() . '/photo/profile/l/' . local_channel()), + dbesc(z_root() . '/photo/profile/m/' . local_channel()), + intval(local_channel()) + ); + } + } + else { + q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", + dbesc(z_root() . '/' . get_default_profile_photo(300)), + dbesc(z_root() . '/' . get_default_profile_photo(80)), + intval($profile_id), + intval(local_channel()) + ); + } + + $sync = attach_export_data($channel, $r[0]['resource_id']); + if ($sync) + Libsync:: build_sync_packet($channel['channel_id'], ['file' => [$sync]]); + $_SESSION['reload_avatar'] = true; - - goaway(z_root() . '/profiles'); + + goaway(z_root() . '/profiles/' . $profile_id); } - - if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) { - + + if ((array_key_exists('cropfinal', $_POST)) && (intval($_POST['cropfinal']) == 1)) { + // logger('crop: ' . print_r($_POST,true)); // phase 2 - we have finished cropping - - if(argc() != 2) { - notice( t('Image uploaded but image cropping failed.') . EOL ); + + if (argc() != 2) { + notice(t('Image uploaded but image cropping failed.') . EOL); return; } - - $image_id = argv(1); - - if(substr($image_id,-2,1) == '-') { - $scale = substr($image_id,-1,1); - $image_id = substr($image_id,0,-2); - } + $image_id = argv(1); - // unless proven otherwise - $is_default_profile = 1; - - if($_REQUEST['profile']) { - $r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1", - intval($_REQUEST['profile']), - intval(local_channel()) - ); - if($r) { - $profile = $r[0]; - if(! intval($profile['is_default'])) - $is_default_profile = 0; - } - } + if (substr($image_id, -2, 1) == '-') { + $scale = substr($image_id, -1, 1); + $image_id = substr($image_id, 0, -2); + } - $srcX = intval($_POST['xstart']); $srcY = intval($_POST['ystart']); $srcW = intval($_POST['xfinal']) - $srcX; @@ -126,45 +144,45 @@ class Profile_photo extends \Zotlabs\Web\Controller { $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1", dbesc($image_id), dbesc(local_channel()), - intval($scale)); - if($r) { - - $base_image = $r[0]; + intval($scale) + ); + + if ($r) { + + $base_image = $r[0]; $base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); - + $im = photo_factory($base_image['content'], $base_image['mimetype']); - if($im->is_valid()) { - - $im->cropImage(300,$srcX,$srcY,$srcW,$srcH); - + if ($im->is_valid()) { + + $im->cropImage(300, $srcX, $srcY, $srcW, $srcH); + $aid = get_account_id(); - - $p = [ - 'aid' => $aid, - 'uid' => local_channel(), + + $p = [ + 'aid' => $aid, + 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'], - 'filename' => $base_image['filename'], + 'filename' => $base_image['filename'], 'album' => t('Profile Photos'), 'os_path' => $base_image['os_path'], 'display_path' => $base_image['display_path'], - 'photo_usage' => PHOTO_PROFILE, - 'edited' => dbescdate($base_image['edited']) + 'photo_usage' => (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL), + 'edited' => dbescdate($base_image['edited']) ]; - - $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); - + $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300); - + $im->scaleImage(80); $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80); - + $im->scaleImage(48); $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48); - if($r1 === false || $r2 === false || $r3 === false) { + if ($r1 === false || $r2 === false || $r3 === false) { // if one failed, delete them all so we can start over. - notice( t('Image resize failed.') . EOL ); - $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d )", + notice(t('Image resize failed.') . EOL); + q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d )", dbesc($base_image['resource_id']), local_channel(), intval(PHOTO_RES_PROFILE_300), @@ -179,59 +197,55 @@ class Profile_photo extends \Zotlabs\Web\Controller { intval(PHOTO_RES_PROFILE_80), intval(PHOTO_RES_PROFILE_48) ); - if($x) { - foreach($x as $xx) { + if ($x) { + foreach ($x as $xx) { @unlink(dbunescbin($xx['content'])); } } - + return; } - + // If setting for the default profile, unset the profile photo flag from any other photos I own - - if($is_default_profile) { - $r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d", + if ($is_default_profile) { + q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d", dbesc(z_root() . '/photo/profile/l/' . local_channel()), dbesc(z_root() . '/photo/profile/m/' . local_channel()), intval(local_channel()) ); - - $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d + q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND uid = %d", intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), dbesc($base_image['resource_id']), intval(local_channel()) ); - - send_profile_photo_activity($channel,$base_image,$profile); - + send_profile_photo_activity($channel, $base_image, $profile); } else { - $r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", + q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-4'), dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-5'), - intval($_REQUEST['profile']), + intval($profile_id), intval(local_channel()) ); } - + // set $send to false in profiles_build_sync() to return the data - // so that we only send one sync packet. + // so that we only send one sync packet. + + $sync_profiles = profiles_build_sync(local_channel(), false); - $sync_profiles = profiles_build_sync(local_channel(),false); - // We'll set the updated profile-photo timestamp even if it isn't the default profile, // so that browsers will do a cache update unconditionally // Also set links back to site-specific profile photo url in case it was - // changed to a generic URL by a clone operation. Otherwise the new photo may + // changed to a generic URL by a clone operation. Otherwise the new photo may // not get pushed to other sites correctly. - - $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' + + q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", dbesc($im->getType()), dbescdate($base_image['edited']), @@ -241,341 +255,372 @@ class Profile_photo extends \Zotlabs\Web\Controller { dbesc($channel['xchan_hash']) ); - photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']); + photo_profile_setperms(local_channel(), $base_image['resource_id'], $profile_id); - $sync = attach_export_data($channel,$base_image['resource_id']); - if($sync) - Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles)); + $sync = attach_export_data($channel, $base_image['resource_id']); + if ($sync) + Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync], 'profile' => $sync_profiles]); // Similarly, tell the nav bar to bypass the cache and update the avatar image. $_SESSION['reload_avatar'] = true; - - info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - + + info(t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); + // Update directory in background - \Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id'])); - + Master::Summon(['Directory', $channel['channel_id']]); + } else - notice( t('Unable to process image') . EOL); + notice(t('Unable to process image') . EOL); } - - goaway(z_root() . '/profiles'); + + goaway(z_root() . '/profiles/' . $profile_id); return; // NOTREACHED } - + // A new photo was uploaded. Store it and save some important details // in App::$data for use in the cropping function - - - $hash = photo_new_resource(); + + $hash = photo_new_resource(); $importing = false; - $smallest = 0; - + $smallest = 0; - if($_REQUEST['importfile']) { - $hash = $_REQUEST['importfile']; + if ($_REQUEST['importfile']) { + $hash = $_REQUEST['importfile']; $importing = true; } else { - require_once('include/attach.php'); - - $res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash, 'nosync' => true)); - - logger('attach_store: ' . print_r($res,true)); + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true)); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store(App::get_channel(), get_observer_hash(), '', ['album' => t('Profile Photos'), 'hash' => $hash, 'nosync' => true, 'source' => 'photos']); + + json_return_and_die(['message' => $hash]); + } - - if(($res && intval($res['data']['is_photo'])) || $importing) { + + if (($res && intval($res['data']['is_photo'])) || $importing) { $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", dbesc($hash), intval(local_channel()) ); - - if(! $i) { - notice( t('Image upload failed.') . EOL ); + + if (!$i) { + notice(t('Image upload failed.') . EOL); return; } + $os_storage = false; - - foreach($i as $ii) { - if(intval($ii['imgscale']) < PHOTO_RES_640) { - $smallest = intval($ii['imgscale']); + + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); $os_storage = intval($ii['os_storage']); - $imagedata = $ii['content']; - $filetype = $ii['mimetype']; + $imagedata = $ii['content']; + $filetype = $ii['mimetype']; } } } - + $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); - $ph = photo_factory($imagedata, $filetype); - - if(! $ph->is_valid()) { - notice( t('Unable to process image.') . EOL ); + $ph = photo_factory($imagedata, $filetype); + + if (!$ph->is_valid()) { + notice(t('Unable to process image.') . EOL); return; } - - return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest); + + return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); // This will "fall through" to the get() method, and since - // App::$data['imagecrop'] is set, it will proceed to cropping - // rather than present the upload form + // App::$data['imagecrop'] is set, it will proceed to cropping + // rather than present the upload form } - - + + /* @brief Generate content of profile-photo view * - * @param $a Current application - * @return void - * */ - - + + function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL ); + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); return; } - - $channel = \App::get_channel(); - $pf = 0; - $newuser = false; - - if(argc() == 2 && argv(1) === 'new') - $newuser = true; - - if(argv(1) === 'use') { - if (argc() < 3) { - notice( t('Permission denied.') . EOL ); - return; - }; - - $resource_id = argv(2); - - $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); + $channel = App::get_channel(); + $profile_id = (($_REQUEST['profile']) ? intval($_REQUEST['profile']) : intval(argv(1))); + $default_profile_id = null; - $c = q("select id, is_default from profile where uid = %d", - intval(local_channel()) - ); + $r = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", + intval(local_channel()) + ); - $multi_profiles = true; - if(($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { - $_REQUEST['profile'] = $c[0]['id']; - $multi_profiles = false; + foreach ($r as $rr) { + if ($rr['is_default']) { + $default_profile_id = intval($rr['id']); } - else { - $_REQUEST['profile'] = $pf; + + if ($profile_id === intval($rr['id'])) { + $profile = $rr; } + } + + $is_default_profile = ($profile_id === $default_profile_id); + + if (argv(1) === 'use') { + if (argc() < 3) { + notice(t('Permission denied.') . EOL); + return; + }; + + $resource_id = argv(2); $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", intval(local_channel()), dbesc($resource_id) ); - if(! $r) { - notice( t('Photo not available.') . EOL ); + if (!$r) { + notice(t('Photo not available.') . EOL); return; } $havescale = false; - foreach($r as $rr) { - if($rr['imgscale'] == PHOTO_RES_PROFILE_80) + foreach ($r as $rr) { + if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) $havescale = true; } - + // set an already loaded and cropped photo as profile photo - - if($havescale) { - // unset any existing profile photos - $x = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), + + if ($havescale) { + + if ($is_default_profile) { + + // unset any existing profile photos + q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval(local_channel()) + ); + + $edited = datetime_convert(); + + q("UPDATE photo SET photo_usage = %d, edited = '%s' WHERE uid = %d AND resource_id = '%s' AND imgscale > 0", + intval(PHOTO_PROFILE), + dbescdate($edited), + intval(local_channel()), + dbesc($resource_id) + ); + + q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'", + dbescdate($edited), + dbesc($channel['xchan_hash']) + + ); + + } + + q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", + dbesc(z_root() . '/photo/' . $resource_id . '-4'), + dbesc(z_root() . '/photo/' . $resource_id . '-5'), + intval($profile_id), intval(local_channel()) ); - $edited = datetime_convert(); - - $x = q("UPDATE photo SET photo_usage = %d, edited = '%s' WHERE uid = %d AND resource_id = '%s' AND imgscale > 0", - intval(PHOTO_PROFILE), - dbescdate($edited), - intval(local_channel()), - dbesc($resource_id) - ); - - $x = q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'", - dbescdate($edited), - dbesc($channel['xchan_hash']) - ); - - photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']); + photo_profile_setperms(local_channel(), $resource_id, $profile_id); - $sync = attach_export_data($channel,$resource_id); - if($sync) - Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync))); + $sync = attach_export_data($channel, $resource_id); + if ($sync) + Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]); $_SESSION['reload_avatar'] = true; - \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); - - goaway(z_root() . '/profiles'); + Master::Summon(['Directory', local_channel()]); + + goaway(z_root() . '/profiles/' . $profile_id); } - + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", intval($r[0]['id']), intval(local_channel()) - + ); - if(! $r) { - notice( t('Photo not available.') . EOL ); + if (!$r) { + notice(t('Photo not available.') . EOL); return; } - - if(intval($r[0]['os_storage'])) - $data = @file_get_contents(dbunescbin($r[0]['content'])); - else - $data = dbunescbin($r[0]['content']); - - $ph = photo_factory($data, $r[0]['mimetype']); + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents($r[0]['content']); + } + else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); $smallest = 0; - if($ph->is_valid()) { + + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", dbesc($r[0]['resource_id']), intval(local_channel()) ); - - if($i) { + + if ($i) { $hash = $i[0]['resource_id']; - foreach($i as $ii) { - if(intval($ii['imgscale']) < PHOTO_RES_640) { + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { $smallest = intval($ii['imgscale']); } } - } - } - - if($multi_profiles) { - \App::$data['importfile'] = $resource_id; - } - else { - $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest); + } } + $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + // falls through with App::$data['imagecrop'] set so we go straight to the cropping section } - - // present an upload form - $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", - intval(local_channel()) - ); + $importing = ((array_key_exists('importfile', App::$data)) ? true : false); - if($profiles) { - for($x = 0; $x < count($profiles); $x ++) { - $profiles[$x]['selected'] = false; - if($pf && $profiles[$x]['id'] == $pf) - $profiles[$x]['selected'] = true; - if((! $pf) && $profiles[$x]['is_default']) - $profiles[$x]['selected'] = true; - } - } + if (!x(App::$data, 'imagecrop')) { - $importing = ((array_key_exists('importfile',\App::$data)) ? true : false); - - if(! x(\App::$data,'imagecrop')) { - $tpl = get_markup_template('profile_photo.tpl'); - - $o .= replace_macros($tpl,array( - '$user' => \App::$channel['channel_address'], - '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')), - '$importfile' => (($importing) ? \App::$data['importfile'] : ''), - '$lbl_upfile' => t('Upload File:'), - '$lbl_profiles' => t('Select a profile:'), - '$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')), - '$submit' => (($importing) ? t('Use') : t('Upload')), - '$remove' => t('Remove'), - '$profiles' => $profiles, - '$single' => ((count($profiles) == 1) ? true : false), - '$profile0' => $profiles[0], - '$embedPhotos' => t('Use a photo from your albums'), - '$embedPhotosModalTitle' => t('Use a photo from your albums'), + + $o = replace_macros($tpl, [ + '$user' => App::$channel['channel_address'], + '$info' => (($is_default_profile) ? t('This profile photo will be visible to anybody on the internet and may be distributed to other websites.') : t('This profile photo will be visible only to channels with permission to view this profile.')), + '$importfile' => (($importing) ? App::$data['importfile'] : ''), + '$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')), + '$submit' => t('Upload'), + '$remove' => t('Reset to default'), + '$profile_id' => $profile_id, + '$profile' => $profile, + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), '$embedPhotosModalCancel' => t('Cancel'), - '$embedPhotosModalOK' => t('OK'), - '$modalchooseimages' => t('Choose images to embed'), - '$modalchoosealbum' => t('Choose an album'), - '$modaldiffalbum' => t('Choose a different album'), - '$modalerrorlist' => t('Error getting album list'), - '$modalerrorlink' => t('Error getting photo link'), - '$modalerroralbum' => t('Error getting album'), - '$form_security_token' => get_form_security_token("profile_photo"), - '$select' => t('Select existing photo'), - )); - + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$select' => t('Select existing'), + ]); + call_hooks('profile_photo_content_end', $o); - + return $o; } else { // present a cropping form - $filename = \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution']; - $resolution = \App::$data['imagecrop_resolution']; - $tpl = get_markup_template("cropbody.tpl"); - $o .= replace_macros($tpl,array( - '$filename' => $filename, - '$profile' => intval($_REQUEST['profile']), - '$resource' => \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'], - '$image_url' => z_root() . '/photo/' . $filename, - '$title' => t('Crop Image'), - '$desc' => t('Please adjust the image cropping for optimum viewing.'), + $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; + $tpl = get_markup_template("cropbody.tpl"); + + $o = replace_macros($tpl, [ + '$filename' => $filename, + '$profile' => $profile_id, + '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), '$form_security_token' => get_form_security_token("profile_photo"), - '$done' => t('Done Editing') - )); + '$done' => t('Done editing') + ]); + return $o; } - + return; // NOTREACHED } - + /* @brief Generate the UI for photo-cropping * - * @param $a Current application - * @param $ph Photo-Factory - * @return void + * @param $ph + * @param $hash + * @param $smallest * */ - - - - function profile_photo_crop_ui_head(&$a, $ph, $hash, $smallest){ - - $max_length = get_config('system','max_image_length'); - if(! $max_length) + + + function profile_photo_crop_ui_head($ph, $hash, $smallest) { + + $max_length = get_config('system', 'max_image_length'); + + if (!$max_length) { $max_length = MAX_IMAGE_LENGTH; - if($max_length > 0) + } + if ($max_length > 0) { $ph->scaleImage($max_length); - - \App::$data['width'] = $ph->getWidth(); - \App::$data['height'] = $ph->getHeight(); - - if(\App::$data['width'] < 500 || \App::$data['height'] < 500) { + } + + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + + if (App::$data['width'] < 500 || App::$data['height'] < 500) { $ph->scaleImageUp(400); - \App::$data['width'] = $ph->getWidth(); - \App::$data['height'] = $ph->getHeight(); + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); } - - - \App::$data['imagecrop'] = $hash; - \App::$data['imagecrop_resolution'] = $smallest; - \App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array()); + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), []); + return; } - - + + } diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 73bae45e8..70f6b1125 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -163,35 +163,6 @@ class Profiles extends \Zotlabs\Web\Controller { killme(); } - - - - // Run profile_load() here to make sure the theme is set before - // we start loading content - if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { - if(feature_enabled(local_channel(),'multi_profiles')) - $id = \App::$argv[1]; - else { - $x = q("select id from profile where uid = %d and is_default = 1", - intval(local_channel()) - ); - if($x) - $id = $x[0]['id']; - } - $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", - intval($id), - intval(local_channel()) - ); - if(! count($r)) { - notice( t('Profile not found.') . EOL); - \App::$error = 404; - return; - } - - $chan = \App::get_channel(); - - profile_load($chan['channel_address'],$r[0]['id']); - } } function post() { @@ -317,8 +288,6 @@ class Profiles extends \Zotlabs\Web\Controller { $work = fix_mce_lf(escape_tags(trim($_POST['work']))); $education = fix_mce_lf(escape_tags(trim($_POST['education']))); - $hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0); - // start fresh and create a new vcard. TODO: preserve the original guid or whatever else needs saving // $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null); @@ -514,6 +483,16 @@ class Profiles extends \Zotlabs\Web\Controller { $value = $locality . $comma1 . $region . $comma2 . $country_name; } + $hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0); + + $suggestme = ((x($_POST, 'suggestme')) ? intval($_POST['suggestme']) : 0); + set_pconfig(local_channel(), 'system', 'suggestme', $suggestme); + + $show_presence = (((x($_POST, 'show_presence')) && (intval($_POST['show_presence']) == 1)) ? 1 : 0); + set_pconfig(local_channel(), 'system', 'show_online_status', $show_presence); + + $publish = ((x($_POST, 'profile_in_directory') && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0); + profile_activity($changes,$value); } @@ -552,7 +531,8 @@ class Profiles extends \Zotlabs\Web\Controller { employment = '%s', education = '%s', hide_friends = %d, - profile_vcard = '%s' + profile_vcard = '%s', + publish = %d WHERE id = %d AND uid = %d", dbesc($profile_name), dbesc($name), @@ -588,6 +568,7 @@ class Profiles extends \Zotlabs\Web\Controller { dbesc($education), intval($hide_friends), dbesc($profile_vcard), + intval($publish), intval(argv(1)), intval(local_channel()) ); @@ -619,8 +600,6 @@ class Profiles extends \Zotlabs\Web\Controller { } if($is_default) { - // reload the info for the sidebar widget - profile_load($channel['channel_address']); \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); } } @@ -631,13 +610,13 @@ class Profiles extends \Zotlabs\Web\Controller { $o = ''; - $channel = \App::get_channel(); - if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } + $channel = \App::get_channel(); + require_once('include/channel.php'); $profile_fields_basic = get_profile_fields_basic(); @@ -653,15 +632,20 @@ class Profiles extends \Zotlabs\Web\Controller { if($x) $id = $x[0]['id']; } + $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", intval($id), intval(local_channel()) ); + if(! $r) { notice( t('Profile not found.') . EOL); return; } + // make sure we got uptodate data + profile_load($channel['channel_address'], $id); + $editselect = 'none'; \App::$page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array( @@ -675,13 +659,43 @@ class Profiles extends \Zotlabs\Web\Controller { else $fields = $profile_fields_basic; - $hide_friends = array( - 'hide_friends', - t('Hide your connections list from viewers of this profile'), - $r[0]['hide_friends'], - '', - array(t('No'),t('Yes')) - ); + $show_presence = []; + $profile_in_dir = ''; + $suggestme = ''; + $hide_friends = []; + $is_default = (($r[0]['is_default']) ? 1 : 0); + + if ($is_default) { + + $hide_friends = array( + 'hide_friends', + t('Hide my connections from viewers of this profile'), + $r[0]['hide_friends'], + '', + [t('No'), t('Yes')] + ); + + + $opt_tpl = get_markup_template("field_checkbox.tpl"); + if (get_config('system', 'publish_all')) { + $profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />'; + } + else { + $profile_in_dir = replace_macros($opt_tpl, [ + '$field' => ['profile_in_directory', t('Publish my default profile in the network directory'), $r[0]['publish'], '', [t('No'), t('Yes')]], + ]); + } + + $suggestme = get_pconfig(local_channel(), 'system', 'suggestme'); + $suggestme = (($suggestme === false) ? '0' : $suggestme); // default if not set: 0 + + $suggestme = replace_macros($opt_tpl, [ + '$field' => ['suggestme', t('Suggest me as a potential contact to new members'), $suggestme, '', [t('No'), t('Yes')]], + ]); + + $show_presence_val = intval(get_pconfig(local_channel(), 'system', 'show_online_status')); + $show_presence = ['show_presence', t('Reveal my online status'), $show_presence_val, '', [t('No'), t('Yes')]]; + } $q = q("select * from profdef where true"); if($q) { @@ -710,7 +724,7 @@ class Profiles extends \Zotlabs\Web\Controller { if(! $f) $f = 'ymd'; - $is_default = (($r[0]['is_default']) ? 1 : 0); + $tpl = get_markup_template("profile_edit.tpl"); $o .= replace_macros($tpl,array( @@ -724,7 +738,7 @@ class Profiles extends \Zotlabs\Web\Controller { '$banner' => t('Edit Profile Details'), '$submit' => t('Submit'), '$viewprof' => t('View this profile'), - '$editvis' => t('Edit visibility'), + '$editvis' => t('Edit visibility'), '$tools_label' => t('Profile Tools'), '$coverpic' => t('Change cover photo'), '$profpic' => t('Change profile photo'), @@ -732,7 +746,7 @@ class Profiles extends \Zotlabs\Web\Controller { '$cl_prof' => t('Clone this profile'), '$del_prof' => t('Delete this profile'), '$addthing' => t('Add profile things'), - '$personal' => t('Personal'), + '$basic' => t('Basic'), '$location' => t('Location'), '$relation' => t('Relationship'), '$miscellaneous'=> t('Miscellaneous'), @@ -801,6 +815,11 @@ class Profiles extends \Zotlabs\Web\Controller { '$update' => t('Update'), '$delete' => t('Delete'), '$cancel' => t('Cancel'), + + '$show_presence' => $show_presence, + '$suggestme' => $suggestme, + '$profile_in_dir' => $profile_in_dir, + )); $arr = array('profile' => $r[0], 'entry' => $o); diff --git a/Zotlabs/Module/Regate.php b/Zotlabs/Module/Regate.php index 379195461..33bb8d957 100644 --- a/Zotlabs/Module/Regate.php +++ b/Zotlabs/Module/Regate.php @@ -2,6 +2,9 @@ namespace Zotlabs\Module; +use Zotlabs\Lib\Connect; +use Zotlabs\Daemon\Master; + require_once('include/security.php'); /** @@ -184,7 +187,24 @@ class Regate extends \Zotlabs\Web\Controller { $new_channel = auto_channel_create($cra['account']['account_id']); if($new_channel['success']) { + $channel_id = $new_channel['channel']['channel_id']; + + // If we have an inviter, connect. + if ($didx === 'i' && intval($r['reg_byc'])) { + $invite_channel = channelx_by_n($r['reg_byc']); + if ($invite_channel) { + $f = Connect::connect($new_channel['channel'], $invite_channel['xchan_addr']); + if ($f['success']) { + $can_view_stream = intval(get_abconfig($channel_id, $f['abook']['abook_xchan'], 'their_perms', 'view_stream')); + // If we can view their stream, pull in some posts + if ($can_view_stream) { + Master::Summon(['Onepoll', $f['abook']['abook_id']]); + } + } + } + } + change_channel($channel_id); $nextpage = 'profiles/' . $channel_id; $msg_code = 'ZAR1239I'; diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index e95752338..a0da020b7 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -2,6 +2,10 @@ namespace Zotlabs\Module\Settings; +use App; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Access\PermissionRoles; +use Zotlabs\Daemon\Master; use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; @@ -10,602 +14,272 @@ require_once('include/selectors.php'); class Channel { - function post() { - $channel = \App::get_channel(); - check_form_security_token_redirectOnErr('/settings', 'settings'); - call_hooks('settings_post', $_POST); - $set_perms = ''; - - $role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); - $oldrole = get_pconfig(local_channel(),'system','permissions_role'); - - // This mapping can be removed after 3.4 release - if($oldrole === 'social_party') { - $oldrole = 'social_federation'; - } - - if(($role != $oldrole) || ($role === 'custom')) { - - if($role === 'custom') { - $hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0); - $publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); - $def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); - $r = q("update channel set channel_default_group = '%s' where channel_id = %d", - dbesc($def_group), - intval(local_channel()) - ); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - - foreach($global_perms as $k => $v) { - \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,intval($_POST[$k])); - } - $acl = new \Zotlabs\Access\AccessList($channel); - $acl->set_from_array($_POST); - $x = $acl->get(); - - $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', - channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d", - dbesc($x['allow_cid']), - dbesc($x['allow_gid']), - dbesc($x['deny_cid']), - dbesc($x['deny_gid']), - intval(local_channel()) - ); - } - else { - $role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']); - if(! $role_permissions) { - notice('Permissions category could not be found.'); - return; - } - $hide_presence = 1 - (intval($role_permissions['online'])); - if($role_permissions['default_collection']) { - $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - if(! $r) { - require_once('include/group.php'); - group_add(local_channel(), t('Friends')); - group_add_member(local_channel(),t('Friends'),$channel['channel_hash']); - $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - } - if($r) { - q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", - dbesc($r[0]['hash']), - dbesc('<' . $r[0]['hash'] . '>'), - intval(local_channel()) - ); - } - else { - notice( sprintf('Default privacy group \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); - return; - } - } - // no default collection - else { - q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', - channel_deny_cid = '' where channel_id = %d", - intval(local_channel()) - ); - } - - if($role_permissions['perms_connect']) { - $x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']); - foreach($x as $k => $v) { - set_abconfig(local_channel(),$channel['channel_hash'],'my_perms',$k, $v); - if($role_permissions['perms_auto']) { - set_pconfig(local_channel(),'autoperms',$k,$v); - } - else { - del_pconfig(local_channel(),'autoperms',$k); - } - } - } - - if($role_permissions['limits']) { - foreach($role_permissions['limits'] as $k => $v) { - \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,$v); - } - } - if(array_key_exists('directory_publish',$role_permissions)) { - $publish = intval($role_permissions['directory_publish']); - } - } - - set_pconfig(local_channel(),'system','hide_online_status',$hide_presence); - set_pconfig(local_channel(),'system','permissions_role',$role); - } - - $username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : ''); - $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); - $defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : ''); - $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); - $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); - $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); - $evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3); - $photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); - $attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); - - $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); - $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); - $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); - $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); - - $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); - - $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! - $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); - $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); - $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); - $autoperms = ((x($_POST,'autoperms')) ? intval($_POST['autoperms']) : 0); - - $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); - $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); - $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); - $adult = (($_POST['adult'] == 1) ? 1 : 0); - $defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default'); - - $mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : ''); - - $pageflags = $channel['channel_pageflags']; - $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); - if($adult != $existing_adult) + $channel = App::get_channel(); + $role = ((x($_POST, 'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); + $timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); + $defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : ''); + $evdays = ((x($_POST, 'evdays')) ? intval($_POST['evdays']) : 3); + $photo_path = ((x($_POST, 'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); + $attach_path = ((x($_POST, 'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); + $allow_location = (((x($_POST, 'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1 : 0); + $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1 : 0); + $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1 : 0); + $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1 : 0); + $adult = (($_POST['adult'] == 1) ? 1 : 0); + $mailhost = ((array_key_exists('mailhost', $_POST)) ? notags(trim($_POST['mailhost'])) : ''); + $pageflags = $channel['channel_pageflags']; + $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); + $expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0); + + if ($adult != $existing_adult) { $pageflags = ($pageflags ^ PAGE_ADULT); - + } $notify = 0; - - if(x($_POST,'notify1')) + if (x($_POST, 'notify1')) $notify += intval($_POST['notify1']); - if(x($_POST,'notify2')) + if (x($_POST, 'notify2')) $notify += intval($_POST['notify2']); - if(x($_POST,'notify3')) + if (x($_POST, 'notify3')) $notify += intval($_POST['notify3']); - if(x($_POST,'notify4')) + if (x($_POST, 'notify4')) $notify += intval($_POST['notify4']); - if(x($_POST,'notify5')) + if (x($_POST, 'notify5')) $notify += intval($_POST['notify5']); - if(x($_POST,'notify6')) + if (x($_POST, 'notify6')) $notify += intval($_POST['notify6']); - if(x($_POST,'notify7')) + if (x($_POST, 'notify7')) $notify += intval($_POST['notify7']); - if(x($_POST,'notify8')) + if (x($_POST, 'notify8')) $notify += intval($_POST['notify8']); $vnotify = 0; - - if(x($_POST,'vnotify1')) + if (x($_POST, 'vnotify1')) $vnotify += intval($_POST['vnotify1']); - if(x($_POST,'vnotify2')) + if (x($_POST, 'vnotify2')) $vnotify += intval($_POST['vnotify2']); - if(x($_POST,'vnotify3')) + if (x($_POST, 'vnotify3')) $vnotify += intval($_POST['vnotify3']); - if(x($_POST,'vnotify4')) + if (x($_POST, 'vnotify4')) $vnotify += intval($_POST['vnotify4']); - if(x($_POST,'vnotify5')) + if (x($_POST, 'vnotify5')) $vnotify += intval($_POST['vnotify5']); - if(x($_POST,'vnotify6')) + if (x($_POST, 'vnotify6')) $vnotify += intval($_POST['vnotify6']); - if(x($_POST,'vnotify7')) + if (x($_POST, 'vnotify7')) $vnotify += intval($_POST['vnotify7']); - if(x($_POST,'vnotify8')) + if (x($_POST, 'vnotify8')) $vnotify += intval($_POST['vnotify8']); - if(x($_POST,'vnotify9')) + if (x($_POST, 'vnotify9')) $vnotify += intval($_POST['vnotify9']); - if(x($_POST,'vnotify10')) + if (x($_POST, 'vnotify10')) $vnotify += intval($_POST['vnotify10']); - if(x($_POST,'vnotify11') && is_site_admin()) + if (x($_POST, 'vnotify11') && is_site_admin()) $vnotify += intval($_POST['vnotify11']); - if(x($_POST,'vnotify12')) + if (x($_POST, 'vnotify12')) $vnotify += intval($_POST['vnotify12']); - if(x($_POST,'vnotify13')) + if (x($_POST, 'vnotify13')) $vnotify += intval($_POST['vnotify13']); - if(x($_POST,'vnotify14')) + if (x($_POST, 'vnotify14')) $vnotify += intval($_POST['vnotify14']); - if(x($_POST,'vnotify15')) + if (x($_POST, 'vnotify15')) $vnotify += intval($_POST['vnotify15']); - $always_show_in_notices = x($_POST, 'always_show_in_notices') ? 1 : 0; - $update_notices_per_parent = x($_POST, 'update_notices_per_parent') ? 1 : 0; + $always_show_in_notices = ((x($_POST, 'always_show_in_notices')) ? 1 : 0); + $update_notices_per_parent = ((x($_POST, 'update_notices_per_parent')) ? 1 : 0); - $err = ''; + if ($timezone !== $channel['channel_timezone']) { + if (strlen($timezone)) + date_default_timezone_set($timezone); + } - $name_change = false; + if (!$role) { + notice(t('Please select a channel role') . EOL); + return; + } + + if ($role !== get_pconfig(local_channel(), 'system', 'permissions_role')) { + $role_permissions = PermissionRoles::role_perms($_POST['permissions_role']); - if($username != $channel['channel_name']) { - $name_change = true; - require_once('include/channel.php'); - $err = validate_channelname($username); - if($err) { - notice($err); - return; + if (isset($role_permissions['limits'])) { + foreach ($role_permissions['limits'] as $k => $v) { + PermissionLimits::Set(local_channel(), $k, $v); + } } - } - if($timezone != $channel['channel_timezone']) { - if(strlen($timezone)) - date_default_timezone_set($timezone); + set_pconfig(local_channel(), 'system', 'group_actor', 0); + if (isset($role_permissions['channel_type']) && $role_permissions['channel_type'] === 'group') { + set_pconfig(local_channel(), 'system', 'group_actor', 1); + } } - set_pconfig(local_channel(),'system','use_browser_location',$allow_location); - set_pconfig(local_channel(),'system','suggestme', $suggestme); - set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend); - set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup); - set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange); - set_pconfig(local_channel(),'system','blocktags',$blocktags); - set_pconfig(local_channel(),'system','vnotify',$vnotify); - set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices); - set_pconfig(local_channel(),'system','update_notices_per_parent',$update_notices_per_parent); - set_pconfig(local_channel(),'system','evdays',$evdays); - set_pconfig(local_channel(),'system','photo_path',$photo_path); - set_pconfig(local_channel(),'system','attach_path',$attach_path); - set_pconfig(local_channel(),'system','default_permcat',$defpermcat); - set_pconfig(local_channel(),'system','email_notify_host',$mailhost); - set_pconfig(local_channel(),'system','autoperms',$autoperms); - - $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", - dbesc($username), + set_pconfig(local_channel(), 'system', 'permissions_role', $role); + set_pconfig(local_channel(), 'system', 'use_browser_location', $allow_location); + set_pconfig(local_channel(), 'system', 'post_newfriend', $post_newfriend); + set_pconfig(local_channel(), 'system', 'post_joingroup', $post_joingroup); + set_pconfig(local_channel(), 'system', 'post_profilechange', $post_profilechange); + set_pconfig(local_channel(), 'system', 'vnotify', $vnotify); + set_pconfig(local_channel(), 'system', 'always_show_in_notices', $always_show_in_notices); + set_pconfig(local_channel(), 'system', 'update_notices_per_parent', $update_notices_per_parent); + set_pconfig(local_channel(), 'system', 'evdays', $evdays); + set_pconfig(local_channel(), 'system', 'photo_path', $photo_path); + set_pconfig(local_channel(), 'system', 'attach_path', $attach_path); + set_pconfig(local_channel(), 'system', 'email_notify_host', $mailhost); + + $r = q("update channel set channel_pageflags = %d, channel_timezone = '%s', + channel_location = '%s', channel_notifyflags = %d, channel_expire_days = %d + where channel_id = %d", intval($pageflags), dbesc($timezone), dbesc($defloc), intval($notify), - intval($unkmail), - intval($maxreq), intval($expire), intval(local_channel()) ); - if($r) - info( t('Settings updated.') . EOL); - - if(! is_null($publish)) { - $r = q("UPDATE profile SET publish = %d WHERE is_default = 1 AND uid = %d", - intval($publish), - intval(local_channel()) - ); - } - - if($name_change) { - // change name on all associated xchans by matching the url - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'", - dbesc($username), - dbesc(datetime_convert()), - dbesc(z_root() . '/channel/' . $channel['channel_address']) - ); - $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", - dbesc($username), - intval($channel['channel_id']) - ); - } - - \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); + if ($r) + info(t('Settings updated.') . EOL); + Master::Summon(['Directory', local_channel()]); Libsync::build_sync_packet(); - - if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) { + if ($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) { // FIXME - set to un-verified, blocked and redirect to logout // Q: Why? Are we verifying people or email addresses? // A: the policy is to verify email addresses } - goaway(z_root() . '/settings' ); + goaway(z_root() . '/settings'); return; // NOTREACHED } function get() { - require_once('include/acl_selectors.php'); - require_once('include/permissions.php'); - - - $yes_no = array(t('No'),t('Yes')); - - - $p = q("SELECT * FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1", - intval(local_channel()) - ); - if(count($p)) - $profile = $p[0]; - - load_pconfig(local_channel(),'expire'); - - $channel = \App::get_channel(); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - - $permiss = array(); - - $perm_opts = array( - array( t('Nobody except yourself'), 0), - array( t('Only those you specifically allow'), PERMS_SPECIFIC), - array( t('Approved connections'), PERMS_CONTACTS), - array( t('Any connections'), PERMS_PENDING), - array( t('Anybody on this website'), PERMS_SITE), - array( t('Anybody in this network'), PERMS_NETWORK), - array( t('Anybody authenticated'), PERMS_AUTHED), - array( t('Anybody on the internet'), PERMS_PUBLIC) - ); - - $limits = \Zotlabs\Access\PermissionLimits::Get(local_channel()); - $anon_comments = get_config('system','anonymous_comments',true); - - foreach($global_perms as $k => $perm) { - $options = array(); - $can_be_public = ((strstr($k,'view') || ($k === 'post_comments' && $anon_comments)) ? true : false); - foreach($perm_opts as $opt) { - if($opt[1] == PERMS_PUBLIC && (! $can_be_public)) - continue; - $options[$opt[1]] = $opt[0]; - } - $permiss[] = array($k,$perm,$limits[$k],'',$options); - } - - // logger('permiss: ' . print_r($permiss,true)); - - $username = $channel['channel_name']; - $nickname = $channel['channel_address']; - $timezone = $channel['channel_timezone']; - $notify = $channel['channel_notifyflags']; - $defloc = $channel['channel_location']; - - $maxreq = $channel['channel_max_friend_req']; - $expire = $channel['channel_expire_days']; - $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); - $sys_expire = get_config('system','default_expire_days'); - -// $unkmail = \App::$user['unkmail']; -// $cntunkmail = \App::$user['cntunkmail']; - - $hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status')); - - - $expire_items = get_pconfig(local_channel(), 'expire','items'); - $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 - - $expire_notes = get_pconfig(local_channel(), 'expire','notes'); - $expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1 - - $expire_starred = get_pconfig(local_channel(), 'expire','starred'); - $expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1 - - $expire_photos = get_pconfig(local_channel(), 'expire','photos'); - $expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0 - - $expire_network_only = get_pconfig(local_channel(), 'expire','network_only'); - $expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0 - - - $suggestme = get_pconfig(local_channel(), 'system','suggestme'); - $suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0 - - $post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend'); - $post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0 - - $post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup'); - $post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0 - - $post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange'); - $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 - - $blocktags = get_pconfig(local_channel(),'system','blocktags'); - $blocktags = (($blocktags===false) ? '0' : $blocktags); - - $timezone = date_default_timezone_get(); - - $opt_tpl = get_markup_template("field_checkbox.tpl"); - if(get_config('system','publish_all')) { - $profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />'; - } - else { - $profile_in_dir = replace_macros($opt_tpl,array( - '$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no), - )); - } - - $suggestme = replace_macros($opt_tpl,array( - '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), - - )); - - $subdir = ((strlen(\App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); - - $webbie = $nickname . '@' . \App::get_hostname(); - $intl_nickname = unpunify($nickname) . '@' . unpunify(\App::get_hostname()); - - - $tpl_addr = get_markup_template("settings_nick_set.tpl"); - - $prof_addr = replace_macros($tpl_addr,array( - '$desc' => t('Your channel address is'), + load_pconfig(local_channel()); + + $channel = App::get_channel(); + $nickname = $channel['channel_address']; + $timezone = $channel['channel_timezone']; + $notify = $channel['channel_notifyflags']; + $defloc = $channel['channel_location']; + $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); + $post_newfriend = get_pconfig(local_channel(), 'system', 'post_newfriend'); + $post_newfriend = (($post_newfriend === false) ? '0' : $post_newfriend); // default if not set: 0 + $post_joingroup = get_pconfig(local_channel(), 'system', 'post_joingroup'); + $post_joingroup = (($post_joingroup === false) ? '0' : $post_joingroup); // default if not set: 0 + $post_profilechange = get_pconfig(local_channel(), 'system', 'post_profilechange'); + $post_profilechange = (($post_profilechange === false) ? '0' : $post_profilechange); // default if not set: 0 + $subdir = ((strlen(App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); + $webbie = $nickname . '@' . App::get_hostname(); + $intl_nickname = unpunify($nickname) . '@' . unpunify(App::get_hostname()); + $disable_discover_tab = intval(get_config('system', 'disable_discover_tab', 1)) == 1; + $site_firehose = intval(get_config('system', 'site_firehose', 0)) == 1; + + $expire = $channel['channel_expire_days']; + $sys_expire = get_config('system', 'default_expire_days'); + + $tpl_addr = get_markup_template("settings_nick_set.tpl"); + $prof_addr = replace_macros($tpl_addr, [ + '$desc' => t('Your channel address is'), '$nickname' => (($intl_nickname === $webbie) ? $webbie : $intl_nickname . ' (' . $webbie . ')'), - '$subdir' => $subdir, - '$davdesc' => t('Your files/photos are accessible via WebDAV at'), - '$davpath' => z_root() . '/dav/' . $nickname, - '$basepath' => \App::get_hostname() - )); - - - - $pcat = new \Zotlabs\Lib\Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if($pcatlist) { - foreach($pcatlist as $pc) { - $permcats[$pc['name']] = $pc['localname']; - } - } - - $default_permcat = get_pconfig(local_channel(),'system','default_permcat','default'); - - - $stpl = get_markup_template('settings.tpl'); - - $acl = new \Zotlabs\Access\AccessList($channel); - $perm_defaults = $acl->get(); - - require_once('include/group.php'); - $group_select = mini_group_select(local_channel(),$channel['channel_default_group']); - - $evdays = get_pconfig(local_channel(),'system','evdays'); - if(! $evdays) + '$subdir' => $subdir, + '$davdesc' => t('Your files/photos are accessible via WebDAV at'), + '$davpath' => z_root() . '/dav/' . $nickname, + '$basepath' => App::get_hostname() + ]); + + $evdays = get_pconfig(local_channel(), 'system', 'evdays'); + if (!$evdays) $evdays = 3; - $permissions_role = get_pconfig(local_channel(),'system','permissions_role'); - if(! $permissions_role) - $permissions_role = 'custom'; - // compatibility mapping - can be removed after 3.4 release - if($permissions_role === 'social_party') - $permissions_role = 'social_federation'; + $always_show_in_notices = get_pconfig(local_channel(), 'system', 'always_show_in_notices'); + $update_notices_per_parent = get_pconfig(local_channel(), 'system', 'update_notices_per_parent', 1); - if(in_array($permissions_role,['forum','repository'])) - $autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [ - '$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]); - else - $autoperms = '<input type="hidden" name="autoperms" value="' . intval(get_pconfig(local_channel(),'system','autoperms')) . '" />'; + $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); + if ($vnotify === false) + $vnotify = (-1); - $permissions_set = (($permissions_role != 'custom') ? true : false); + $perm_roles = PermissionRoles::channel_roles(); + $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role'); - $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + if (!in_array($permissions_role, ['public', 'personal', 'group', 'custom'])) { + notice(t('Please select a channel role') . EOL); + array_unshift($perm_roles , ''); + } - $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); - $update_notices_per_parent = get_pconfig(local_channel(), 'system', 'update_notices_per_parent', 1); - $vnotify = get_pconfig(local_channel(),'system','vnotify'); + $plugin = ['basic' => '', 'notify' => '']; + call_hooks('channel_settings', $plugin); - if($vnotify === false) - $vnotify = (-1); + $yes_no = [t('No'), t('Yes')]; - $plugin = [ 'basic' => '', 'security' => '', 'notify' => '' ]; - call_hooks('channel_settings',$plugin); - - $disable_discover_tab = intval(get_config('system','disable_discover_tab',1)) == 1; - $site_firehose = intval(get_config('system','site_firehose',0)) == 1; - - - $o .= replace_macros($stpl,array( - '$ptitle' => t('Channel Settings'), - - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$uid' => local_channel(), - '$form_security_token' => get_form_security_token("settings"), - '$nickname_block' => $prof_addr, - '$h_basic' => t('Basic Settings'), - '$username' => array('username', t('Full Name:'), $username,''), - '$email' => array('email', t('Email Address:'), $email, ''), - '$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()), - '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), - '$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no), - - '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no), - - '$h_prv' => t('Security and Privacy Settings'), - '$permissions_set' => $permissions_set, - '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), - - '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), - - '$lbl_pmacro' => t('Simple Privacy Settings:'), - '$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'), - '$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'), - '$pmacro1' => t('Private - <em>default private, never open or public</em>'), - '$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'), - '$permiss_arr' => $permiss, - '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), - - '$lbl_p2macro' => t('Channel Permission Limits'), - - '$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), - '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), - '$permissions' => t('Default Privacy Group'), - '$permdesc' => t("\x28click to open/close\x29"), - '$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), - - '$allow_cid' => acl2json($perm_defaults['allow_cid']), - '$allow_gid' => acl2json($perm_defaults['allow_gid']), - '$deny_cid' => acl2json($perm_defaults['deny_cid']), - '$deny_gid' => acl2json($perm_defaults['deny_gid']), - '$suggestme' => $suggestme, - '$group_select' => $group_select, - '$role' => array('permissions_role' , t('Channel role and privacy'), $permissions_role, '', $perm_roles), - '$defpermcat' => [ 'defpermcat', t('Default permissions category'), $default_permcat, '', $permcats ], - '$permcat_enable' => Apps::system_app_installed(local_channel(), 'Permission Categories'), - '$profile_in_dir' => $profile_in_dir, - '$hide_friends' => $hide_friends, - '$hide_wall' => $hide_wall, - '$unkmail' => $unkmail, - '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), - - '$autoperms' => $autoperms, - '$h_not' => t('Notification Settings'), - '$activity_options' => t('By default post a status message when:'), - '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), - '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), - '$post_profilechange' => array('post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, '', $yes_no), - '$lbl_not' => t('Send a notification email when:'), - '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), - '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no), - '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), - '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), - '$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), - '$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no), - '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), - '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no), - - '$notify9' => array('notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no), - - - '$lbl_vnot' => t('Show visual notifications including:'), - - '$vnotify1' => array('vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), - '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), - '$vnotify3' => array('vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), - '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), - '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), - '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), - '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), - '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), - '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), - '$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no), - '$vnotify11' => ((is_site_admin()) ? array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no) : array()), - '$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no), - '$vnotify13' => ((($disable_discover_tab && !$site_firehose) || !Apps::system_app_installed(local_channel(), 'Public Stream')) ? array() : array('vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no)), - '$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no), - '$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no), - '$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ], - '$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), - '$update_notices_per_parent' => array('update_notices_per_parent', t('Mark all notices of the thread read if a notice is clicked'), $update_notices_per_parent, 1, t('If no, only the clicked notice will be marked read'), $yes_no), - '$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'), + $stpl = get_markup_template('settings.tpl'); + $o = replace_macros($stpl, [ + '$ptitle' => t('Channel Settings'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$uid' => local_channel(), + '$form_security_token' => get_form_security_token("settings"), + '$role' => ['permissions_role', t('Channel role'), $permissions_role, '', $perm_roles], + '$nickname_block' => $prof_addr, + '$h_basic' => t('Basic Settings'), + '$timezone' => ['timezone_select', t('Channel timezone:'), $timezone, '', get_timezones()], + '$defloc' => ['defloc', t('Default post location:'), $defloc, t('Geographical location to display on your posts')], + '$allowloc' => ['allow_location', t('Use browser location'), ((get_pconfig(local_channel(), 'system', 'use_browser_location')) ? 1 : ''), '', $yes_no], + '$adult' => ['adult', t('Adult content'), $adult_flag, t('This channel frequently or regularly publishes adult content'), $yes_no], + '$maxreq' => ['maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']), t('May reduce spam activity')], + '$h_not' => t('Notification Settings'), + '$activity_options' => t('By default post a status message when:'), + '$post_newfriend' => ['post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no], + '$post_joingroup' => ['post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no], + '$post_profilechange' => ['post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, '', $yes_no], + '$lbl_not' => t('Send a notification email when:'), + '$notify1' => ['notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no], + '$notify2' => ['notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no], + '$notify3' => ['notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no], + '$notify4' => ['notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no], + '$notify5' => ['notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no], + '$notify6' => ['notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no], + '$notify7' => ['notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no], + '$notify8' => ['notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no], + '$notify9' => ['notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no], + '$lbl_vnot' => t('Show visual notifications including:'), + '$vnotify1' => ['vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no], + '$vnotify2' => ['vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no], + '$vnotify3' => ['vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no], + '$vnotify4' => ['vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no], + '$vnotify5' => ['vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no], + '$vnotify6' => ['vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no], + '$vnotify7' => ['vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no], + '$vnotify8' => ['vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no], + '$vnotify9' => ['vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no], + '$vnotify10' => ['vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no], + '$vnotify11' => ((is_site_admin()) ? ['vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no] : []), + '$vnotify12' => ['vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no], + '$vnotify13' => ((($disable_discover_tab && !$site_firehose) || !Apps::system_app_installed(local_channel(), 'Public Stream')) ? [] : ['vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no]), + '$vnotify14' => ['vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no], + '$vnotify15' => ['vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no], + '$mailhost' => ['mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(), 'system', 'email_notify_host', App::get_hostname()), sprintf(t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'), App::get_hostname())], + '$always_show_in_notices' => ['always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no], + '$update_notices_per_parent' => ['update_notices_per_parent', t('Mark all notices of the thread read if a notice is clicked'), $update_notices_per_parent, 1, t('If no, only the clicked notice will be marked read'), $yes_no], + '$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'), '$desktop_notifications_request' => t('Grant permission'), - '$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')), - '$basic_addon' => $plugin['basic'], - '$sec_addon' => $plugin['security'], - '$notify_addon' => $plugin['notify'], - - '$h_advn' => t('Advanced Account/Page Type Settings'), - '$h_descadvn' => t('Change the behaviour of this account for special situations'), - '$pagetype' => $pagetype, - '$lbl_misc' => t('Miscellaneous Settings'), - '$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')), - '$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')), - '$removeme' => t('Remove Channel'), - '$removechannel' => t('Remove this channel.'), - )); - - call_hooks('settings_form',$o); - - //$o .= '</form>' . "\r\n"; + '$evdays' => ['evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')], + '$basic_addon' => $plugin['basic'], + '$notify_addon' => $plugin['notify'], + '$photo_path' => ['photo_path', t('Default photo upload folder'), get_pconfig(local_channel(), 'system', 'photo_path'), t('%Y - current year, %m - current month')], + '$attach_path' => ['attach_path', t('Default file upload folder'), get_pconfig(local_channel(), 'system', 'attach_path'), t('%Y - current year, %m - current month')], + '$removeme' => t('Remove Channel'), + '$removechannel' => t('Remove this channel.'), + '$expire' => ['expire', t('Expire other channel content after this many days'), $expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf(t('This website expires after %d days.'), intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')], + ]); + + call_hooks('settings_form', $o); return $o; } diff --git a/Zotlabs/Module/Settings/Privacy.php b/Zotlabs/Module/Settings/Privacy.php new file mode 100644 index 000000000..fbda78a6f --- /dev/null +++ b/Zotlabs/Module/Settings/Privacy.php @@ -0,0 +1,127 @@ +<?php + +namespace Zotlabs\Module\Settings; + +use App; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Access\Permissions; +use Zotlabs\Daemon\Master; +use Zotlabs\Lib\Group; +use Zotlabs\Lib\Libsync; + +class Privacy { + + function post() { + + check_form_security_token_redirectOnErr('/settings/privacy', 'settings'); + call_hooks('settings_post', $_POST); + + $index_opt_out = (((x($_POST, 'index_opt_out')) && (intval($_POST['index_opt_out']) == 1)) ? 1 : 0); + set_pconfig(local_channel(), 'system', 'index_opt_out', $index_opt_out); + + $autoperms = (((x($_POST, 'autoperms')) && (intval($_POST['autoperms']) == 1)) ? 1 : 0); + set_pconfig(local_channel(), 'system', 'autoperms', $autoperms); + + $role = get_pconfig(local_channel(), 'system', 'permissions_role'); + if ($role === 'custom') { + + $global_perms = Permissions::Perms(); + + foreach ($global_perms as $k => $v) { + PermissionLimits::Set(local_channel(), $k, intval($_POST[$k])); + } + + $group_actor = (((x($_POST, 'group_actor')) && (intval($_POST['group_actor']) == 1)) ? 1 : 0); + set_pconfig(local_channel(), 'system', 'group_actor', $group_actor); + + } + + info(t('Privacy settings updated.') . EOL); + Master::Summon(['Directory', local_channel()]); + Libsync::build_sync_packet(); + + goaway(z_root() . '/settings/privacy'); + return; // NOTREACHED + } + + function get() { + + load_pconfig(local_channel()); + + $channel = App::get_channel(); + $global_perms = Permissions::Perms(); + $permiss = []; + + $perm_opts = [ + [t('Only me'), 0], + [t('Only those you specifically allow'), PERMS_SPECIFIC], + [t('Approved connections'), PERMS_CONTACTS], + [t('Any connections'), PERMS_PENDING], + [t('Anybody on this website'), PERMS_SITE], + [t('Anybody in this network'), PERMS_NETWORK], + [t('Anybody authenticated'), PERMS_AUTHED], + [t('Anybody on the internet'), PERMS_PUBLIC] + ]; + + $help = [ + 'view_stream', + 'view_wiki', + 'view_pages', + 'view_storage' + ]; + + $help_txt = t('Advise: set to "Anybody on the internet" and use privacy groups to restrict access'); + $limits = PermissionLimits::Get(local_channel()); + $anon_comments = get_config('system', 'anonymous_comments', true); + + foreach ($global_perms as $k => $perm) { + $options = []; + $can_be_public = (strstr($k, 'view') || ($k === 'post_comments' && $anon_comments)); + + foreach ($perm_opts as $opt) { + if ($opt[1] == PERMS_PUBLIC && (!$can_be_public)) + continue; + + $options[$opt[1]] = $opt[0]; + } + + $permiss[] = [ + $k, + $perm, + $limits[$k], + ((in_array($k, $help)) ? $help_txt : ''), + $options + ]; + } + + //logger('permiss: ' . print_r($permiss,true)); + + $autoperms = get_pconfig(local_channel(), 'system', 'autoperms'); + $index_opt_out = get_pconfig(local_channel(), 'system', 'index_opt_out'); + $group_actor = get_pconfig(local_channel(), 'system', 'group_actor'); + + $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role', 'custom'); + $permission_limits = ($permissions_role === 'custom'); + + $stpl = get_markup_template('settings_privacy.tpl'); + + $o = replace_macros($stpl, [ + '$ptitle' => t('Privacy Settings'), + '$submit' => t('Submit'), + '$form_security_token' => get_form_security_token("settings"), + '$permission_limits' => $permission_limits, + '$permiss_arr' => $permiss, + '$permission_limits_label' => t('Advanced configuration'), + '$permission_limits_warning' => [ + t('Proceed with caution'), + t('Changing advanced configuration settings can impact your, and your contacts channels functionality and security.'), + t('Accept the risk and continue') + ], + '$autoperms' => ['autoperms', t('Automatically approve new contacts'), $autoperms, '', [t('No'), t('Yes')]], + '$index_opt_out' => ['index_opt_out', t('Opt-out of search engine indexing'), $index_opt_out, '', [t('No'), t('Yes')]], + '$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]], + ]); + + return $o; + } +} diff --git a/Zotlabs/Module/Settings/Profiles.php b/Zotlabs/Module/Settings/Profiles.php index 67b03e04f..a1a1b8d96 100644 --- a/Zotlabs/Module/Settings/Profiles.php +++ b/Zotlabs/Module/Settings/Profiles.php @@ -13,14 +13,14 @@ class Profiles { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); $profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : ''); set_pconfig(local_channel(),'system','profile_assign',$profile_assign); - + Libsync::build_sync_packet(); if($_POST['rpath']) @@ -38,7 +38,7 @@ class Profiles { $extra_settings_html = ''; if(feature_enabled(local_channel(),'multi_profiles')) - $extra_settings_html = contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign','')); + $extra_settings_html = contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign',''), t('Default profile for new contacts')); $tpl = get_markup_template("settings_module.tpl"); @@ -51,7 +51,7 @@ class Profiles { '$extra_settings_html' => $extra_settings_html, '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php index eaaeae7b7..3a13b0a6f 100644 --- a/Zotlabs/Module/Sse_bs.php +++ b/Zotlabs/Module/Sse_bs.php @@ -124,7 +124,7 @@ class Sse_bs extends Controller { $str = ''; foreach($arr as $a) { - $mids[] = '\'' . dbesc(@base64url_decode(substr($a,4))) . '\''; + $mids[] = '\'' . dbesc(unpack_link_id($a)) . '\''; } $str = implode(',', $mids); diff --git a/Zotlabs/Module/Tokens.php b/Zotlabs/Module/Tokens.php index 31b219019..9de54f568 100644 --- a/Zotlabs/Module/Tokens.php +++ b/Zotlabs/Module/Tokens.php @@ -5,6 +5,11 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Apps; +use Zotlabs\Lib\AccessList; +use Zotlabs\Lib\Permcat; +use Zotlabs\Lib\Libsync; + +require_once('include/security.php'); class Tokens extends Controller { @@ -13,15 +18,65 @@ class Tokens extends Controller { if(! local_channel()) return; - if(! Apps::system_app_installed(local_channel(), 'Guest Access')) - return; - $channel = App::get_channel(); + if(! Apps::system_app_installed($channel['channel_id'], 'Guest Access')) + return; + check_form_security_token_redirectOnErr('tokens', 'tokens'); + + if(isset($_POST['delete'])) { + $r = q("select * from atoken where atoken_id = %d and atoken_uid = %d", + intval($_POST['atoken_id']), + intval(local_channel()) + ); + + if (!$r) { + return; + } + + $atoken = $r[0]; + $atoken_xchan = substr($channel['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid']; + + $atoken['deleted'] = true; + + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", + intval($channel['channel_id']), + dbesc($atoken_xchan) + ); + + if (!$r) { + return; + } + + $clone = $r[0]; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + $clone['deleted'] = true; + + $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } + + atoken_delete($atoken['atoken_id']); + Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => [ $atoken ] ], true); + + return; + } + $token_errs = 0; if(array_key_exists('token',$_POST)) { $atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0); + + if (! $atoken_id) { + $atoken_guid = new_uuid(); + } + $name = trim(escape_tags($_POST['name'])); $token = trim($_POST['token']); if((! $name) || (! $token)) @@ -30,10 +85,10 @@ class Tokens extends Controller { $expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']); else $expires = NULL_DATE; - $max_atokens = service_class_fetch(local_channel(),'access_tokens'); + $max_atokens = service_class_fetch($channel['channel_id'],'access_tokens'); if($max_atokens) { $r = q("select count(atoken_id) as total where atoken_uid = %d", - intval(local_channel()) + intval($channel['channel_id']) ); if($r && intval($r[0]['total']) >= $max_tokens) { notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL); @@ -45,6 +100,17 @@ class Tokens extends Controller { notice( t('Name and Password are required.') . EOL); return; } + + $old_atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", + intval($channel['channel_id']), + dbesc($name) + ); + + if ($old_atok) { + $old_atok = $old_atok[0]; + $old_xchan = atoken_xchan($old_atok); + } + if($atoken_id) { $r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s' where atoken_id = %d and atoken_uid = %d", @@ -56,8 +122,9 @@ class Tokens extends Controller { ); } else { - $r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) - values ( %d, %d, '%s', '%s', '%s' ) ", + $r = q("insert into atoken (atoken_guid, atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) + values ('%s', %d, %d, '%s', '%s', '%s' ) ", + dbesc($atoken_guid), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc($name), @@ -66,21 +133,84 @@ class Tokens extends Controller { ); } - $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name; + $atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", + intval($channel['channel_id']), + dbesc($name) + ); - $all_perms = \Zotlabs\Access\Permissions::Perms(); + if ($atok) { + $xchan = atoken_xchan($atok[0]); + atoken_create_xchan($xchan); + $atoken_xchan = $xchan['xchan_hash']; + if ($old_atok && $old_xchan) { + $r = q("update xchan set xchan_name = '%s' where xchan_hash = '%s'", + dbesc($xchan['xchan_name']), + dbesc($old_xchan['xchan_hash']) + ); + } + } - if($all_perms) { - foreach($all_perms as $perm => $desc) { - if(array_key_exists('perms_' . $perm, $_POST)) { - set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm])); - } - else { - set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0); + + if (! $atoken_id) { + + // If this is a new token, create a new abook record + + $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness',80); + $profile_assign = get_pconfig($channel['channel_id'], 'system', 'profile_assign', ''); + + $r = abook_store_lowlevel( + [ + 'abook_account' => $channel['channel_account_id'], + 'abook_channel' => $channel['channel_id'], + 'abook_closeness' => intval($closeness), + 'abook_xchan' => $atoken_xchan, + 'abook_profile' => $profile_assign, + 'abook_feed' => 0, + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_instance' => z_root(), + ] + ); + + if (! $r) { + logger('abook creation failed'); + } + + /** If there is a default group for this channel, add this connection to it */ + if ($channel['channel_default_group']) { + $g = AccessList::by_hash($channel['channel_id'], $channel['channel_default_group']); + if ($g) { + AccessList::member_add($channel['channel_id'], '', $atoken_xchan,$g['id']); } } } + $role = ((array_key_exists('permcat', $_POST)) ? escape_tags($_POST['permcat']) : ''); + \Zotlabs\Lib\Permcat::assign($channel, $role, [$atoken_xchan]); + + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", + intval($channel['chnnel_id']), + dbesc($atoken_xchan) + ); + + if (! $r) { + return; + } + + $clone = $r[0]; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } + + Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => $atok ], true); info( t('Token saved.') . EOL); return; @@ -99,10 +229,13 @@ class Tokens extends Controller { return Apps::app_render($papp, 'module'); } + nav_set_selected('Guest Access'); + $channel = App::get_channel(); $atoken = null; $atoken_xchan = ''; + $atoken_abook = []; if(argc() > 1) { $id = argv(1); @@ -114,76 +247,52 @@ class Tokens extends Controller { if($atoken) { $atoken = $atoken[0]; - $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name']; - } + $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_guid']; + + $atoken_abook = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", + intval(local_channel()), + dbesc($atoken_xchan) + ); - if($atoken && argc() > 2 && argv(2) === 'drop') { - atoken_delete($id); - $atoken = null; - $atoken_xchan = ''; + $atoken_abook = $atoken_abook[0]; } } - $t = q("select * from atoken where atoken_uid = %d", - intval(local_channel()) - ); - $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); - $desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - $their_perms = []; - - $existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : ''),false); + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $default_role = get_pconfig(local_channel(), 'system', 'default_permcat'); + $current_permcat = (($atoken_abook) ? $atoken_abook['abook_role'] : $default_role); - if($atoken_xchan) { - $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", - intval(local_channel()), - dbesc($atoken_xchan) - ); - if($theirs) { - foreach($theirs as $t) { - $their_perms[$t['k']] = $t['v']; - } - } + $roles_dict = []; + foreach ($pcatlist as $role) { + $roles_dict[$role['name']] = $role['localname']; } - foreach($global_perms as $k => $v) { - $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); -//fixme - - $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k); - if($existing[$k]) - $thisperm = "1"; - - $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + if (!$current_permcat) { + notice(t('Please select a role for this guest!') . EOL); + $permcats[] = ''; } - + if ($pcatlist) { + foreach ($pcatlist as $pc) { + $permcats[$pc['name']] = $pc['localname']; + } + } $tpl = get_markup_template("tokens.tpl"); $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("tokens"), - '$title' => t('Guest Access Tokens'), - '$desc' => $desc, - '$desc2' => $desc2, - '$tokens' => $t, + '$form_security_token' => get_form_security_token('tokens'), + '$permcat' => ['permcat', t('Select a role for this guest'), $current_permcat, '', $permcats], + '$title' => t('Guest Access'), + '$desc' => $desc, '$atoken' => $atoken, - '$url1' => z_root() . '/channel/' . $channel['channel_address'], - '$url2' => z_root() . '/photos/' . $channel['channel_address'], '$name' => array('name', t('Login Name') . ' <span class="required">*</span>', (($atoken) ? $atoken['atoken_name'] : ''),''), - '$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''), + '$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : new_token()), ''), '$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''), - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$inherited' => t('inherited'), - '$notself' => 1, - '$self' => 0, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), - '$submit' => t('Submit') + '$submit' => t('Submit'), + '$delete' => t('Delete') )); return $o; } diff --git a/Zotlabs/Module/Uexport.php b/Zotlabs/Module/Uexport.php index d73bc40d4..870c42802 100644 --- a/Zotlabs/Module/Uexport.php +++ b/Zotlabs/Module/Uexport.php @@ -2,24 +2,27 @@ namespace Zotlabs\Module; use App; +use ZipArchive; use Zotlabs\Lib\Apps; use Zotlabs\Web\Controller; class Uexport extends Controller { function init() { - if(! local_channel()) - killme(); + if(! local_channel()) { + return; + } - if(! Apps::system_app_installed(local_channel(), 'Channel Export')) + if(! Apps::system_app_installed(local_channel(), 'Channel Export')) { return; + } if(argc() > 1) { - $sections = (($_REQUEST['sections']) ? explode(',',$_REQUEST['sections']) : ''); $zap_compat = (($_REQUEST['zap_compat']) ? intval($_REQUEST['zap_compat']) : false); - $channel = App::get_channel(); + $year = null; + $month = null; if(argc() > 1 && intval(argv(1)) > 1900) { $year = intval(argv(1)); @@ -29,25 +32,110 @@ class Uexport extends Controller { $month = intval(argv(2)); } - header('content-type: application/json'); - header('content-disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . (($_REQUEST['sections']) ? '-' . $_REQUEST['sections'] : '') . '.json"' ); + $sections = []; + $section = ''; + if(argc() > 1 && ctype_lower(argv(1))) { + $section = argv(1); + } - if($year) { - echo json_encode(identity_export_year(local_channel(),$year,$month, $zap_compat)); - killme(); + switch ($section) { + case 'channel': + $sections = get_default_export_sections(); + break; + case 'chatrooms': + $sections = ['chatrooms']; + break; + case 'events': + $sections = ['events']; + break; + case 'webpages': + $sections = ['webpages']; + break; + case 'wikis': + $sections = ['wikis']; + break; + case 'custom': + default: + $custom_sections = ['channel', 'connections', 'config', 'apps', 'chatrooms', 'events', 'webpages', 'wikis']; + $raw_sections = (($_REQUEST['sections']) ? explode(',', $_REQUEST['sections']) : ''); + if ($raw_sections) { + foreach ($raw_sections as $raw_section) { + if(in_array($raw_section, $custom_sections)) { + $sections[] = $raw_section; + } + } + } } - if(argc() > 1 && argv(1) === 'basic') { - echo json_encode(identity_basic_export(local_channel(),$sections, $zap_compat)); + if ($sections) { + + $export = json_encode(identity_basic_export(local_channel(), $sections, $zap_compat)); + + header('Content-Type: application/json'); + header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . '-' . implode('-', $sections) . '.json"'); + header('Content-Length: ' . strlen($export)); + + echo $export; + killme(); } + elseif ($year && !$month) { + $zip_dir = 'store/[data]/' . $channel['channel_address'] . '/tmp'; + if (!is_dir($zip_dir)) + mkdir($zip_dir, STORAGE_DEFAULT_PERMISSIONS, true); + + $zip_file = $channel['channel_address'] . '-' . $year . '.zip'; + $zip_path = $zip_dir . '/' . $zip_file; + $zip_content_available = false; + $zip = new ZipArchive(); + + if ($zip->open($zip_path, ZipArchive::CREATE) === true) { + $month = 1; + while ($month <= 12) { + $name = $channel['channel_address'] . '-' . $year . '-' . $month . '.json'; + $content = conv_item_export_year(local_channel(), $year, $month, $zap_compat); + if(isset($content['item'])) { + $zip_content_available = true; + $zip->addFromString($name, json_encode($content)); + } + $month++; + } + $zip->setCompressionName($zip_path, ZipArchive::CM_STORE); + $zip->close(); + } + if (!$zip_content_available) { + unlink($zip_path); + notice(t('No content available for year') . ' ' . $year . EOL); + goaway('/uexport'); + } + + header('Content-Type: application/zip'); + header('Content-Disposition: attachment; filename="' . $zip_file . '"'); + header('Content-Length: ' . filesize($zip_path)); + + $istream = fopen($zip_path, 'rb'); + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + + unlink($zip_path); + killme(); + } + elseif ($year && $month) { + $export = json_encode(conv_item_export_year(local_channel(), $year, $month, $zap_compat)); + + header('Content-Type: application/json'); + header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . '-' . $year . '-' . $month . '.json"'); + header('Content-Length: ' . strlen($export)); - // Warning: this option may consume a lot of memory + echo $export; - if(argc() > 1 && argv(1) === 'complete') { - $sections = get_default_export_sections(); - $sections[] = 'items'; - echo json_encode(identity_basic_export(local_channel(),$sections, $zap_compat)); + killme(); + } + else { killme(); } } @@ -55,6 +143,10 @@ class Uexport extends Controller { function get() { + if(! local_channel()) { + return; + } + if(! Apps::system_app_installed(local_channel(), 'Channel Export')) { //Do not display any associated widgets at this point App::$pdl = ''; @@ -62,27 +154,47 @@ class Uexport extends Controller { return Apps::app_render($papp, 'module'); } - $y = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); + $account = App::get_account(); + $year_start = datetime_convert('UTC', date_default_timezone_get(), $account['account_created'], 'Y'); + $year_end = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y'); + $years = []; + + while ($year_start <= $year_end) { + $years[] = $year_start; + $year_start++; + } + + $item_import_url = '/import_items'; + $channel_import_url = '/import'; - $yearurl = z_root() . '/uexport/' . $y; - $janurl = z_root() . '/uexport/' . $y . '/1'; - $impurl = '/import_items'; $o = replace_macros(get_markup_template('uexport.tpl'), array( '$title' => t('Export Channel'), - '$basictitle' => t('Export Channel'), - '$basic' => t('Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content.'), - '$fulltitle' => t('Export Content'), - '$full' => t('Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'), - '$by_year' => t('Export your posts from a given year.'), + '$channel_title' => t('Export channel'), + '$channel_info' => t('This will export your identity and social graph into a file which can be used to import your channel to a new hub.'), - '$extra' => t('You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range.'), - '$extra2' => sprintf( t('To select all posts for a given year, such as this year, visit <a href="%1$s">%2$s</a>'),$yearurl,$yearurl), - '$extra3' => sprintf( t('To select all posts for a given month, such as January of this year, visit <a href="%1$s">%2$s</a>'),$janurl,$janurl), - '$extra4' => sprintf( t('These content files may be imported or restored by visiting <a href="%1$s">%2$s</a> on any site containing your channel. For best results please import or restore these in date order (oldest first).'),$impurl,$impurl) + '$years' => $years, + '$content_title' => t('Export content'), + '$content_info' => t('This will export your posts, direct messages, articles and cards per month stored into a zip file per year. Months with no posts will be dismissed.'), + '$wikis_title' => t('Export wikis'), + '$wikis_info' => t('This will export your wikis and wiki pages.'), + + '$webpages_title' => t('Export webpages'), + '$webpages_info' => t('This will export your webpages and menus.'), + + '$events_title' => t('Export channel calendar'), + '$events_info' => t('This will export your channel calendar events and associated items. CalDAV calendars are not included.'), + + '$chatrooms_title' => t('Export chatrooms'), + '$chatrooms_info' => t('This will export your chatrooms. Chat history is dismissed.'), + + '$items_extra_info' => sprintf( t('This export can be imported or restored by visiting <a href="%1$s">%2$s</a> on any site containing your channel.'), $item_import_url, $item_import_url), )); - return $o; + return $o; } + + + } diff --git a/Zotlabs/Module/Viewconnections.php b/Zotlabs/Module/Viewconnections.php index a0c293ddf..d54f61c36 100644 --- a/Zotlabs/Module/Viewconnections.php +++ b/Zotlabs/Module/Viewconnections.php @@ -6,7 +6,7 @@ require_once('include/selectors.php'); class Viewconnections extends \Zotlabs\Web\Controller { function init() { - + if(observer_prohibited()) { return; } @@ -16,58 +16,58 @@ class Viewconnections extends \Zotlabs\Web\Controller { } } - + function get() { - + if(observer_prohibited()) { notice( t('Public access denied.') . EOL); return; } - + if(((! count(\App::$profile)) || (\App::$profile['hide_friends']))) { notice( t('Permission denied.') . EOL); return; - } - + } + if(! perm_is_allowed(\App::$profile['uid'], get_observer_hash(),'view_contacts')) { notice( t('Permission denied.') . EOL); return; - } - + } + if(! $_REQUEST['aj']) $_SESSION['return_url'] = \App::$query_string; - - + + $is_owner = ((local_channel() && local_channel() == \App::$profile['uid']) ? true : false); - - $abook_flags = " and abook_pending = 0 and abook_self = 0 "; + + $abook_flags = " and abook_pending = 0 and abook_self = 0 and abook_blocked = 0 and abook_ignored = 0 "; $sql_extra = ''; - + if(! $is_owner) { $abook_flags .= " and abook_hidden = 0 "; $sql_extra = " and xchan_hidden = 0 "; } - + $r = q("SELECT count(*) as total FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ", intval(\App::$profile['uid']) ); if($r) { \App::set_pager_total($r[0]['total']); } - + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra order by xchan_name LIMIT %d OFFSET %d ", intval(\App::$profile['uid']), intval(\App::$pager['itemspage']), intval(\App::$pager['start']) ); - + if((! $r) && (! $_REQUEST['aj'])) { info( t('No connections.') . EOL ); return $o; } - + $contacts = array(); - + foreach($r as $rr) { $oneway = false; @@ -103,7 +103,7 @@ class Viewconnections extends \Zotlabs\Web\Controller { 'id' => $rr['abook_id'], 'archived' => (intval($rr['abook_archived']) ? true : false), 'img_hover' => sprintf( t('Visit %s\'s profile [%s]'), $rr['xchan_name'], $rr['xchan_url']), - 'thumb' => $rr['xchan_photo_m'], + 'thumb' => $rr['xchan_photo_m'], 'name' => substr($rr['xchan_name'],0,20), 'username' => $rr['xchan_addr'], 'link' => $url, @@ -137,11 +137,11 @@ class Viewconnections extends \Zotlabs\Web\Controller { // '$paginate' => paginate($a), )); } - + if(! $contacts) $o .= '<div id="content-complete"></div>'; - + return $o; } - + } diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index d67a6f176..4f909d33d 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -24,7 +24,7 @@ class Vote extends Controller { $fetch = null; $id = argv(1); $response = $_REQUEST['answer']; - + if ($id) { $fetch = q("select * from item where id = %d limit 1", intval($id) @@ -42,7 +42,7 @@ class Vote extends Controller { } $valid = false; - + if ($obj['oneOf']) { foreach($obj['oneOf'] as $selection) { // logger('selection: ' . $selection); @@ -80,7 +80,6 @@ class Vote extends Controller { $item = []; - $item['aid'] = $channel['channel_account_id']; $item['uid'] = $channel['channel_id']; $item['item_origin'] = 1; @@ -95,11 +94,8 @@ class Vote extends Controller { $item['owner_xchan'] = $fetch[0]['author_xchan']; $item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>'; $item['item_private'] = 1; - - $item['obj_type'] = 'Note'; $item['author'] = channelx_by_n($channel['channel_id']); - $item['obj'] = Activity::encode_item($item); // now reset the placeholders @@ -108,17 +104,15 @@ class Vote extends Controller { $item['obj_type'] = 'Answer'; unset($item['author']); - $x = item_store($item); - retain_item($fetch[0]['id']); if($x['success']) { $itemid = $x['item_id']; Master::Summon( [ 'Notifier', 'like', $itemid ] ); } - + $r = q("select * from item where id = %d", intval($itemid) ); @@ -128,6 +122,7 @@ class Vote extends Controller { Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]); } } + $ret['success'] = true; $ret['message'] = t('Response submitted. Updates may not appear instantly.'); json_return_and_die($ret); diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index a06119506..3d0c07492 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -500,7 +500,7 @@ class Wiki extends Controller { $r = NativeWiki::create_wiki($owner, $observer_hash, $wiki, $acl); if($r['success']) { NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']); - $homePage = NativeWikiPage::create_page($owner['channel_id'],$observer_hash,'Home', $r['item']['resource_id'], $wiki['mimeType']); + $homePage = NativeWikiPage::create_page($owner, $observer_hash, 'Home', $r['item']['resource_id'], $wiki['mimeType']); if(! $homePage['success']) { notice( t('Wiki created, but error creating Home page.')); goaway(z_root() . '/wiki/' . $nick . '/' . NativeWiki::name_encode($wiki['urlName'])); @@ -606,7 +606,7 @@ class Wiki extends Controller { json_return_and_die(array('message' => 'Error creating page. Invalid name (' . print_r($_POST,true) . ').', 'success' => false)); } - $page = NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype); + $page = NativeWikiPage::create_page($owner, $observer_hash, $name, $resource_id, $mimetype); if($page['item_id']) { $commit = NativeWikiPage::commit([ |