From 2968bf8241d2969c4d51f1651fc3f8c7688b2fca Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 15 Dec 2021 12:17:19 +0000 Subject: merge branch perms_ng into dev --- Zotlabs/Access/PermissionLimits.php | 2 +- Zotlabs/Access/PermissionRoles.php | 79 ++- Zotlabs/Access/Permissions.php | 37 +- Zotlabs/Daemon/Notifier.php | 12 + Zotlabs/Lib/AccessList.php | 239 +++++---- Zotlabs/Lib/Activity.php | 30 +- Zotlabs/Lib/Connect.php | 5 +- Zotlabs/Lib/Enotify.php | 2 +- Zotlabs/Lib/Group.php | 405 --------------- Zotlabs/Lib/Libzot.php | 43 +- Zotlabs/Lib/Permcat.php | 130 ++++- Zotlabs/Lib/ThreadItem.php | 31 +- Zotlabs/Module/Acl.php | 8 +- Zotlabs/Module/Admin/Site.php | 4 +- Zotlabs/Module/Apschema.php | 5 +- Zotlabs/Module/Channel.php | 4 + Zotlabs/Module/Connections.php | 126 +++-- Zotlabs/Module/Connedit.php | 798 +++++++++++------------------ Zotlabs/Module/Contactedit.php | 668 ++++++++++++++++++++++++ Zotlabs/Module/Contactgroup.php | 26 +- Zotlabs/Module/Defperms.php | 21 +- Zotlabs/Module/Follow.php | 4 +- Zotlabs/Module/Group.php | 67 ++- Zotlabs/Module/Item.php | 36 +- Zotlabs/Module/Network.php | 7 +- Zotlabs/Module/New_channel.php | 4 +- Zotlabs/Module/Permcats.php | 148 ++++-- Zotlabs/Module/Profiles.php | 71 ++- Zotlabs/Module/Regate.php | 2 +- Zotlabs/Module/Settings/Channel.php | 714 +++++++------------------- Zotlabs/Module/Settings/Privacy.php | 127 +++++ Zotlabs/Module/Uexport.php | 4 + Zotlabs/Update/_1249.php | 31 ++ Zotlabs/Widget/Collections.php | 6 +- Zotlabs/Widget/Messages.php | 2 +- Zotlabs/Widget/Permcats.php | 79 +++ Zotlabs/Widget/Profile.php | 10 +- Zotlabs/Widget/Settings_menu.php | 5 + app/group.apd | 4 +- boot.php | 8 +- include/attach.php | 6 +- include/channel.php | 49 +- include/connections.php | 3 +- include/conversation.php | 28 +- include/group.php | 2 +- include/items.php | 202 ++++++-- include/nav.php | 6 +- include/permissions.php | 40 +- include/selectors.php | 14 +- include/text.php | 64 ++- tests/unit/Access/PermissionLimitsTest.php | 7 +- tests/unit/Access/PermissionRolesTest.php | 26 +- tests/unit/Access/PermissionsTest.php | 14 +- view/css/mod_connections.css | 18 +- view/css/widgets.css | 5 +- view/js/main.js | 15 +- view/js/mod_connections.js | 2 +- view/pdl/mod_chat.pdl | 2 +- view/pdl/mod_connections.pdl | 3 - view/pdl/mod_connedit.pdl | 2 - view/pdl/mod_import_items.pdl | 3 + view/pdl/mod_permcats.pdl | 7 + view/pdl/mod_profperm.pdl | 2 +- view/pdl/mod_viewconnections.pdl | 2 +- view/theme/redbasic/css/style.css | 19 +- view/theme/redbasic/schema/Focus-Boxy.css | 22 +- view/tpl/abook_edit.tpl | 164 +++--- view/tpl/admin_site.tpl | 2 +- view/tpl/connection_template.tpl | 21 +- view/tpl/connections.tpl | 24 +- view/tpl/connstatus.tpl | 2 +- view/tpl/contact_edit.tpl | 133 +++++ view/tpl/contact_edit_header.tpl | 9 + view/tpl/contact_edit_modal.tpl | 152 ++++++ view/tpl/contact_edit_tools.tpl | 14 + view/tpl/conv_frame.tpl | 1 + view/tpl/conv_item.tpl | 4 +- view/tpl/conv_list.tpl | 2 +- view/tpl/conversation.tpl | 6 +- view/tpl/field_acheckbox.tpl | 41 +- view/tpl/field_checkbox.tpl | 2 +- view/tpl/group_edit.tpl | 2 + view/tpl/group_selection.tpl | 12 +- view/tpl/group_side.tpl | 4 +- view/tpl/micropro_card.tpl | 2 +- view/tpl/new_channel.tpl | 12 +- view/tpl/notes.tpl | 2 +- view/tpl/permcats.tpl | 68 +-- view/tpl/privacy_groups.tpl | 2 + view/tpl/profile_edit.tpl | 12 +- view/tpl/profile_vcard.tpl | 16 +- view/tpl/search_item.tpl | 2 +- view/tpl/settings.tpl | 63 +-- view/tpl/settings_privacy.tpl | 56 ++ 94 files changed, 3138 insertions(+), 2259 deletions(-) delete mode 100644 Zotlabs/Lib/Group.php create mode 100644 Zotlabs/Module/Contactedit.php create mode 100644 Zotlabs/Module/Settings/Privacy.php create mode 100644 Zotlabs/Update/_1249.php create mode 100644 Zotlabs/Widget/Permcats.php create mode 100644 view/pdl/mod_import_items.pdl create mode 100644 view/pdl/mod_permcats.pdl create mode 100644 view/tpl/contact_edit.tpl create mode 100644 view/tpl/contact_edit_header.tpl create mode 100644 view/tpl/contact_edit_modal.tpl create mode 100644 view/tpl/contact_edit_tools.tpl create mode 100644 view/tpl/settings_privacy.tpl diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php index fb5fe6133..7a574ba6a 100644 --- a/Zotlabs/Access/PermissionLimits.php +++ b/Zotlabs/Access/PermissionLimits.php @@ -89,4 +89,4 @@ class PermissionLimits { return false; } -} \ No newline at end of file +} diff --git a/Zotlabs/Access/PermissionRoles.php b/Zotlabs/Access/PermissionRoles.php index 998b6d8d2..2078b52a8 100644 --- a/Zotlabs/Access/PermissionRoles.php +++ b/Zotlabs/Access/PermissionRoles.php @@ -17,7 +17,7 @@ class PermissionRoles { * @return number */ static public function version() { - return 2; + return 3; } static function role_perms($role) { @@ -27,6 +27,54 @@ class PermissionRoles { $ret['role'] = $role; switch($role) { + + case 'public': + $ret['default_collection'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki', + 'send_stream', 'post_comments', 'post_mail', 'post_wall', 'chat', 'post_like', 'republish' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['limits']['post_comments'] = PERMS_AUTHED; + $ret['limits']['post_mail'] = PERMS_AUTHED; + $ret['limits']['post_like'] = PERMS_AUTHED; + $ret['limits']['chat'] = PERMS_AUTHED; + break; + + // Hubzilla default role + case 'personal': + $ret['default_collection'] = true; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki', + 'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['limits']['view_contacts'] = PERMS_SPECIFIC; + break; + + case 'group': + $ret['default_collection'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', + 'view_pages', 'view_wiki', 'post_wall', 'post_comments', + 'post_mail', 'post_like', 'chat' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['channel_type'] = 'group'; + break; + + // Provide some defaults for the custom role so that we do not start + // with no permissions at all if we create a new channel with this role + case 'custom': + $ret['default_collection'] = true; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki', + 'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + break; + +/* case 'social': $ret['perms_auto'] = false; $ret['default_collection'] = false; @@ -193,13 +241,14 @@ class PermissionRoles { $ret['channel_type'] = 'group'; break; +*/ - case 'custom': default: break; } $x = get_config('system','role_perms'); + // let system settings over-ride any or all if($x && is_array($x) && array_key_exists($role,$x)) $ret = array_merge($ret,$x[$role]); @@ -284,6 +333,7 @@ class PermissionRoles { */ static public function roles() { $roles = [ + t('Social Networking') => [ 'social_federation' => t('Social - Federation'), 'social' => t('Social - Mostly Public'), @@ -317,4 +367,29 @@ class PermissionRoles { return $roles; } + /** + * @brief Array with translated role names and grouping. + * + * Return an associative array with role names that can be used + * to create select groups like in \e field_select_grouped.tpl. + * + * @return array + */ + static public function channel_roles() { + $channel_roles = [ + //'public' => [t('Public'), t('A very permissive role suited for participation in the fediverse')], + //'personal' => [t('Personal'), t('The $Projectname default role suited for a personal channel')], + //'forum' => [t('Community forum'), t('This role configures your channel to act as an community forum')], + //'custom' => [t('Custom'), t('This role comes with the presets of the personal role but allows you to configure it to your needs')] + 'public' => t('Public'), + 'personal' => t('Personal'), + 'group' => t('Community forum'), + 'custom' => t('Custom') + ]; + + call_hooks('list_channel_roles', $channel_roles); + + return $channel_roles; + } + } diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index 45dd30d69..09f4c9678 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -41,7 +41,7 @@ class Permissions { * @return number */ static public function version() { - return 2; + return 3; } /** @@ -67,9 +67,9 @@ class Permissions { 'post_comments' => t('Can comment on or like my posts'), 'post_mail' => t('Can send me direct messages'), 'post_like' => t('Can like/dislike profiles and profile things'), - 'tag_deliver' => t('Can forward direct messages to all my channel connections (forum)'), 'chat' => t('Can chat with me'), - 'republish' => t('Can source my public posts in derived channels'), + 'republish' => t('Can source/mirror my public posts in derived channels'), + //'tag_deliver' => t('Can forward to my contacts via direct messages (forum)'), 'delegate' => t('Can administer my channel') ]; @@ -217,25 +217,23 @@ class Permissions { $my_perms = []; $permcat = null; - $automatic = 0; + $automatic = get_pconfig($channel_id, 'system', 'autoperms'); // If a default permcat exists, use that - $pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default'); - if (!in_array($pc, ['', 'default'])) { - $pcp = new Zlib\Permcat($channel_id); - $permcat = $pcp->fetch($pc); - if ($permcat && $permcat['perms']) { - foreach ($permcat['perms'] as $p) { - $my_perms[$p['name']] = $p['value']; - } + $pc = get_pconfig($channel_id, 'system', 'default_permcat', 'default'); + $pcp = new Zlib\Permcat($channel_id); + $permcat = $pcp->fetch($pc); + if ($permcat && $permcat['perms']) { + foreach ($permcat['perms'] as $p) { + $my_perms[$p['name']] = $p['value']; } } // look up the permission role to see if it specified auto-connect // and if there was no permcat or a default permcat, set the perms // from the role - +/* $role = get_pconfig($channel_id, 'system', 'permissions_role'); if ($role) { $xx = PermissionRoles::role_perms($role); @@ -247,11 +245,12 @@ class Permissions { $my_perms = Permissions::FilledPerms($default_perms); } } +*/ // If we reached this point without having any permission information, // it is likely a custom permissions role. First see if there are any // automatic permissions. - +/* if (!$my_perms) { $m = Permissions::FilledAutoperms($channel_id); if ($m) { @@ -259,11 +258,12 @@ class Permissions { $my_perms = $m; } } - +*/ // If we reached this point with no permissions, the channel is using // custom perms but they are not automatic. They will be stored in abconfig with // the channel's channel_hash (the 'self' connection). +/* if (!$my_perms) { $r = q("select channel_hash from channel where channel_id = %d", intval($channel_id) @@ -280,10 +280,10 @@ class Permissions { } } } - - return (['perms' => $my_perms, 'automatic' => $automatic]); +*/ + return (['perms' => $my_perms, 'automatic' => $automatic, 'role' => $pc]); } - +/* static public function serialise($p) { $n = []; if ($p) { @@ -295,4 +295,5 @@ class Permissions { } return implode(',', $n); } +*/ } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 4ca109495..23bddae8f 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -630,6 +630,18 @@ class Notifier { // default: zot protocol + // Prevent zot6 delivery of group comment boosts, which are not required for conversational platforms. + // ActivityPub conversational platforms may wish to filter these if they don't want or require them. + // We will assume here that if $target_item exists and has a verb that it is an actual item structure + // so we won't need to check the existence of the other item fields prior to evaluation. + + // This shouldn't produce false positives on comment boosts that were generated on other platforms + // because we won't be delivering them. + + if (isset($target_item) && isset($target_item['verb']) && $target_item['verb'] === 'Announce' && $target_item['author_xchan'] === $target_item['owner_xchan'] && ! intval($target_item['item_thread_top'])) { + continue; + } + $hash = new_uuid(); $env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : ''); diff --git a/Zotlabs/Lib/AccessList.php b/Zotlabs/Lib/AccessList.php index 3c008f8c7..51c100afb 100644 --- a/Zotlabs/Lib/AccessList.php +++ b/Zotlabs/Lib/AccessList.php @@ -1,38 +1,37 @@ -may apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL); + notice(t('A deleted list with this name was revived. Existing item permissions may apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL); } - return true; + $hash = self::by_id($uid, $r); + return $hash; } $hash = new_uuid(); - $r = q("INSERT INTO pgrp ( hash, uid, visible, gname ) + $r = q("INSERT INTO pgrp ( hash, uid, visible, gname ) VALUES( '%s', %d, %d, '%s' ) ", dbesc($hash), intval($uid), @@ -42,12 +41,12 @@ class AccessList { $ret = $r; } - Libsync::build_sync_packet($uid,null,true); - return $ret; - } + Libsync::build_sync_packet($uid, null, true); + return (($ret) ? $hash : $ret); + } - static function remove($uid,$name) { + static function remove($uid, $name) { $ret = false; if ($uid && $name) { $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", @@ -55,36 +54,36 @@ class AccessList { dbesc($name) ); if ($r) { - $group_id = $r[0]['id']; + $group_id = $r[0]['id']; $group_hash = $r[0]['hash']; } else { return false; } - + // remove group from default posting lists $r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1", - intval($uid) + intval($uid) ); if ($r) { $user_info = array_shift($r); - $change = false; + $change = false; if ($user_info['channel_default_group'] == $group_hash) { $user_info['channel_default_group'] = ''; - $change = true; + $change = true; } if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) { $user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']); - $change = true; + $change = true; } if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) { $user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']); - $change = true; + $change = true; } if ($change) { - q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s' + q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s' WHERE channel_id = %d", intval($user_info['channel_default_group']), dbesc($user_info['channel_allow_gid']), @@ -110,16 +109,16 @@ class AccessList { } - Libsync::build_sync_packet($uid,null,true); + Libsync::build_sync_packet($uid, null, true); return $ret; } // returns the integer id of an access group owned by $uid and named $name // or false. - - static function byname($uid,$name) { - if (! ($uid && $name)) { + + static function by_name($uid, $name) { + if (!($uid && $name)) { return false; } $r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", @@ -132,11 +131,11 @@ class AccessList { return false; } - static function by_id($uid,$id) { - if (! ($uid && $id)) { + static function by_id($uid, $id) { + if (!($uid && $id)) { return false; } - + $r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0", intval($uid), intval($id) @@ -147,10 +146,8 @@ class AccessList { return false; } - - - static function rec_byhash($uid,$hash) { - if (! ( $uid && $hash)) { + static function by_hash($uid, $hash) { + if (!($uid && $hash)) { return false; } $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1", @@ -163,46 +160,43 @@ class AccessList { return false; } + static function member_remove($uid, $name, $member) { + $gid = self::by_name($uid, $name); - static function member_remove($uid,$name,$member) { - $gid = self::byname($uid,$name); - if (! $gid) { - return false; - } - if (! ($uid && $gid && $member)) { + if (!($uid && $gid && $member)) { return false; } + $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", intval($uid), intval($gid), dbesc($member) ); - Libsync::build_sync_packet($uid,null,true); + Libsync::build_sync_packet($uid, null, true); return $r; } - - static function member_add($uid,$name,$member,$gid = 0) { - if (! $gid) { - $gid = self::byname($uid,$name); + static function member_add($uid, $name, $member, $gid = 0) { + if (!$gid) { + $gid = self::by_name($uid, $name); } - if (! ($gid && $uid && $member)) { + if (!($gid && $uid && $member)) { return false; } - $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", + $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", intval($uid), intval($gid), dbesc($member) ); if ($r) { - return true; // You might question this, but - // we indicate success because the group member was in fact created - // -- It was just created at another time + return true; // You might question this, but + // we indicate success because the group member was in fact created + // -- It was just created at another time } - else { + else { $r = q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", intval($uid), @@ -210,15 +204,14 @@ class AccessList { dbesc($member) ); } - Libsync::build_sync_packet($uid,null,true); + Libsync::build_sync_packet($uid, null, true); return $r; } - static function members($uid, $gid) { $ret = []; if (intval($gid)) { - $r = q("SELECT * FROM pgrp_member + $r = q("SELECT * FROM pgrp_member LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ", intval($gid), @@ -232,7 +225,7 @@ class AccessList { return $ret; } - static function members_xchan($uid,$gid) { + static function members_xchan($uid, $gid) { $ret = []; if (intval($gid)) { $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d", @@ -248,99 +241,123 @@ class AccessList { return $ret; } - static function members_profile_xchan($uid,$gid) { + static function profile_members_xchan($uid,$gid) { $ret = []; - if (intval($gid)) { + + if(intval($gid)) { $r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d", intval($gid), intval($uid) ); - if ($r) { - foreach($r as $rv) { - $ret[] = $rv['xchan']; + if($r) { + foreach($r as $rr) { + $ret[] = $rr['xchan']; } } } return $ret; } + static function select($uid, $options) { + $selected = $options['selected'] ?? ''; + $form_id = $options['form_id'] ?? 'accesslist_select'; + $label = $options['label'] ?? t('Select a privacy group'); + $before = $options['before'] ?? []; + $after = $options['after'] ?? []; - - static function select($uid,$group = '') { - $grps = []; + $o = ''; + + $grps[] = [ + 'name' => '', + 'id' => '0', + 'selected' => false + ]; + + if ($before) { + $grps[] = $before; + } $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval($uid) ); - $grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ]; - if ($r) { - foreach ($r as $rr) { - $grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ]; + + if($r) { + foreach($r as $rr) { + $grps[] = [ + 'name' => $rr['gname'], + 'id' => $rr['hash'], + 'selected' => ($selected == $rr['hash']) + ]; } + } + if ($after) { + $grps[] = $after; } - - return replace_macros(get_markup_template('group_selection.tpl'), [ - '$label' => t('Add new connections to this access list'), - '$groups' => $grps - ]); - } + logger('select: ' . print_r($grps,true), LOGGER_DATA); - static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) { + $o = replace_macros(get_markup_template('group_selection.tpl'), array( + '$label' => $label, + '$form_id' => $form_id, + '$groups' => $grps + )); + + return $o; + } - $o = ''; + + static function widget($every = "connections", $each = "lists", $edit = false, $group_id = 0, $cid = '', $mode = 1) { $groups = []; - $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval($_SESSION['uid']) ); $member_of = []; if ($cid) { - $member_of = self::containing(local_channel(),$cid); - } + $member_of = self::containing(local_channel(), $cid); + } if ($r) { foreach ($r as $rr) { $selected = (($group_id == $rr['id']) ? ' group-selected' : ''); - + if ($edit) { - $groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ]; - } + $groupedit = ['href' => "lists/" . $rr['id'], 'title' => t('edit')]; + } else { $groupedit = null; } - + $groups[] = [ - 'id' => $rr['id'], - 'enc_cid' => base64url_encode($cid), - 'cid' => $cid, - 'text' => $rr['gname'], - 'selected' => $selected, - 'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''), - 'edit' => $groupedit, - 'ismember' => in_array($rr['id'],$member_of), + 'id' => $rr['id'], + 'enc_cid' => base64url_encode($cid), + 'cid' => $cid, + 'text' => $rr['gname'], + 'selected' => $selected, + 'href' => (($mode == 0) ? $each . '?f=&gid=' . $rr['id'] : $each . "/" . $rr['id']) . ((x($_GET, 'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET, 'order')) ? '&order=' . $_GET['order'] : ''), + 'edit' => $groupedit, + 'ismember' => in_array($rr['id'], $member_of), ]; } } - + return replace_macros(get_markup_template('group_side.tpl'), [ - '$title' => t('Lists'), - '$edittext' => t('Edit list'), - '$createtext' => t('Create new list'), - '$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''), - '$groups' => $groups, - '$add' => t('add'), + '$title' => t('Lists'), + '$edittext' => t('Edit list'), + '$createtext' => t('Create new list'), + '$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''), + '$groups' => $groups, + '$add' => t('add'), ]); } - static function expand($g) { - if (! (is_array($g) && count($g))) { + if (!(is_array($g) && count($g))) { return []; } @@ -350,8 +367,8 @@ class AccessList { // private profile linked virtual groups foreach ($g as $gv) { - if (substr($gv,0,3) === 'vp.') { - $profile_hash = substr($gv,3); + if (substr($gv, 0, 3) === 'vp.') { + $profile_hash = substr($gv, 3); if ($profile_hash) { $r = q("select abook_xchan from abook where abook_profile = '%s'", dbesc($profile_hash) @@ -366,10 +383,10 @@ class AccessList { else { $x[] = $gv; } - } + } if ($x) { - stringify_array_elms($x,true); + stringify_array_elms($x, true); $groups = implode(',', $x); if ($groups) { $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))"); @@ -383,9 +400,8 @@ class AccessList { return $ret; } - static function member_of($c) { - $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id + $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ", dbesc($c) ); @@ -393,7 +409,7 @@ class AccessList { return $r; } - static function containing($uid,$c) { + static function containing($uid, $c) { $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ", intval($uid), @@ -405,7 +421,8 @@ class AccessList { foreach ($r as $rv) $ret[] = $rv['gid']; } - + return $ret; } -} \ No newline at end of file + +} diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 664886fc2..8e5a4e1a6 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -886,10 +886,6 @@ class Activity { else return []; - if (strpos($i['body'], '[/share]') !== false) { - $i['obj'] = null; - } - if ($i['obj']) { if (!is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'], true); @@ -899,8 +895,10 @@ class Activity { } $obj = self::encode_object($i['obj']); - if ($obj) + + if ($obj) { $ret['object'] = $obj; + } else return []; } @@ -1042,7 +1040,7 @@ class Activity { $tmp = expand_acl($i['allow_cid']); $list = stringify_array($tmp, true); if ($list) { - $details = q("select hubloc_id_url from hubloc where hubloc_hash in (" . $list . ") and hubloc_id_url != ''"); + $details = q("select hubloc_id_url from hubloc where hubloc_hash in (" . $list . ") and hubloc_id_url != '' and hubloc_deleted = 0"); if ($details) { foreach ($details as $d) { $ret[] = $d['hubloc_id_url']; @@ -1089,10 +1087,11 @@ class Activity { $ret['type'] = 'Person'; if ($c) { - $role = get_pconfig($c['channel_id'], 'system', 'permissions_role'); - if (strpos($role, 'forum') !== false) { + if (get_pconfig($c['channel_id'], 'system', 'group_actor')) { $ret['type'] = 'Group'; } + + $ret['manuallyApprovesFollowers'] = ((get_pconfig($c['channel_id'], 'system', 'autoperms')) ? false : true); } if ($c) { @@ -1554,9 +1553,9 @@ class Activity { /* If there is a default group for this channel and permissions are automatic, add this member to it */ if ($channel['channel_default_group'] && $automatic) { - $g = Group::rec_byhash($channel['channel_id'], $channel['channel_default_group']); + $g = AccessList::by_hash($channel['channel_id'], $channel['channel_default_group']); if ($g) - Group::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']); + AccessList::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']); } @@ -2692,6 +2691,17 @@ class Activity { // set the owner to the owner of the parent $item['owner_xchan'] = $p[0]['owner_xchan']; + // quietly reject group comment boosts by group owner + // (usually only sent via ActivityPub so groups will work on microblog platforms) + // This catches those activities if they slipped in via a conversation fetch + + if ($p[0]['parent_mid'] !== $item['parent_mid']) { + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $item['owner_xchan']) { + logger('group boost activity by group owner rejected'); + return; + } + } + // check permissions against the author, not the sender $allowed = perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'post_comments'); if ((!$allowed)/* && $permit_mentions*/) { diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php index 38fe69995..0b9ff7089 100644 --- a/Zotlabs/Lib/Connect.php +++ b/Zotlabs/Lib/Connect.php @@ -261,7 +261,8 @@ class Connect { 'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0), 'abook_created' => datetime_convert(), 'abook_updated' => datetime_convert(), - 'abook_instance' => (($singleton) ? z_root() : '') + 'abook_instance' => (($singleton) ? z_root() : ''), + 'abook_role' => get_pconfig($uid, 'system', 'default_permcat', 'default') ] ); } @@ -300,7 +301,7 @@ class Connect { /** If there is a default group for this channel, add this connection to it */ if ($default_group) { - $g = AccessList::rec_byhash($uid,$default_group); + $g = AccessList::by_hash($uid,$default_group); if ($g) { AccessList::member_add($uid,'',$xchan_hash,$g['id']); } diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index fdc7d4567..2e483cb92 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -902,7 +902,7 @@ class Enotify { static public function format_intros($rr) { return [ - 'notify_link' => z_root() . '/connections/ifpending', + 'notify_link' => z_root() . '/connections#' . $rr['abook_id'], 'name' => $rr['xchan_name'], 'addr' => $rr['xchan_addr'], 'url' => $rr['xchan_url'], diff --git a/Zotlabs/Lib/Group.php b/Zotlabs/Lib/Group.php deleted file mode 100644 index a4ff4fced..000000000 --- a/Zotlabs/Lib/Group.php +++ /dev/null @@ -1,405 +0,0 @@ -may apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL); - } - return true; - } - - do { - $dups = false; - $hash = random_string(32) . str_replace(['<','>'],['.','.'], $name); - - $r = q("SELECT id FROM pgrp WHERE hash = '%s' LIMIT 1", dbesc($hash)); - if($r) - $dups = true; - } while($dups == true); - - - $r = q("INSERT INTO pgrp ( hash, uid, visible, gname ) - VALUES( '%s', %d, %d, '%s' ) ", - dbesc($hash), - intval($uid), - intval($public), - dbesc($name) - ); - $ret = $r; - } - - Libsync::build_sync_packet($uid,null,true); - return $ret; - } - - - static function remove($uid,$name) { - $ret = false; - if(x($uid) && x($name)) { - $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", - intval($uid), - dbesc($name) - ); - if($r) { - $group_id = $r[0]['id']; - $group_hash = $r[0]['hash']; - } - - if(! $group_id) - return false; - - // remove group from default posting lists - $r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1", - intval($uid) - ); - if($r) { - $user_info = $r[0]; - $change = false; - - if($user_info['channel_default_group'] == $group_hash) { - $user_info['channel_default_group'] = ''; - $change = true; - } - if(strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) { - $user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']); - $change = true; - } - if(strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) { - $user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']); - $change = true; - } - - if($change) { - q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s' - WHERE channel_id = %d", - intval($user_info['channel_default_group']), - dbesc($user_info['channel_allow_gid']), - dbesc($user_info['channel_deny_gid']), - intval($uid) - ); - } - } - - // remove all members - $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ", - intval($uid), - intval($group_id) - ); - - // remove group - $r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'", - intval($uid), - dbesc($name) - ); - - $ret = $r; - - } - - Libsync::build_sync_packet($uid,null,true); - - return $ret; - } - - - static function byname($uid,$name) { - if((! $uid) || (! strlen($name))) - return false; - $r = q("SELECT * FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", - intval($uid), - dbesc($name) - ); - if($r) - return $r[0]['id']; - return false; - } - - - static function rec_byhash($uid,$hash) { - if((! $uid) || (! strlen($hash))) - return false; - $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1", - intval($uid), - dbesc($hash) - ); - if($r) - return $r[0]; - return false; - } - - - static function member_remove($uid,$name,$member) { - $gid = self::byname($uid,$name); - if(! $gid) - return false; - if(! ( $uid && $gid && $member)) - return false; - $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", - intval($uid), - intval($gid), - dbesc($member) - ); - - Libsync::build_sync_packet($uid,null,true); - - return $r; - } - - - static function member_add($uid,$name,$member,$gid = 0) { - if(! $gid) - $gid = self::byname($uid,$name); - if((! $gid) || (! $uid) || (! $member)) - return false; - - $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", - intval($uid), - intval($gid), - dbesc($member) - ); - if($r) - return true; // You might question this, but - // we indicate success because the group member was in fact created - // -- It was just created at another time - if(! $r) - $r = q("INSERT INTO pgrp_member (uid, gid, xchan) - VALUES( %d, %d, '%s' ) ", - intval($uid), - intval($gid), - dbesc($member) - ); - - Libsync::build_sync_packet($uid,null,true); - - return $r; - } - - - static function members($gid) { - $ret = array(); - if(intval($gid)) { - $r = q("SELECT * FROM pgrp_member - LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan - WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ", - intval($gid), - intval(local_channel()), - intval(local_channel()) - ); - if($r) - $ret = $r; - } - return $ret; - } - - static function members_xchan($gid) { - $ret = []; - if(intval($gid)) { - $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d", - intval($gid), - intval(local_channel()) - ); - if($r) { - foreach($r as $rr) { - $ret[] = $rr['xchan']; - } - } - } - return $ret; - } - - static function members_profile_xchan($uid,$gid) { - $ret = []; - - if(intval($gid)) { - $r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d", - intval($gid), - intval($uid) - ); - if($r) { - foreach($r as $rr) { - $ret[] = $rr['xchan']; - } - } - } - return $ret; - } - - - - - static function select($uid,$group = '') { - - $grps = []; - $o = ''; - - $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval($uid) - ); - $grps[] = array('name' => '', 'hash' => '0', 'selected' => ''); - if($r) { - foreach($r as $rr) { - $grps[] = array('name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '')); - } - - } - logger('select: ' . print_r($grps,true), LOGGER_DATA); - - $o = replace_macros(get_markup_template('group_selection.tpl'), array( - '$label' => t('Add new connections to this privacy group'), - '$groups' => $grps - )); - return $o; - } - - - - - static function widget($every="connections",$each="group",$edit = false, $group_id = 0, $cid = '',$mode = 1) { - - $o = ''; - - if(! (local_channel() && feature_enabled(local_channel(),'groups'))) { - return ''; - } - - $groups = array(); - - $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval($_SESSION['uid']) - ); - $member_of = array(); - if($cid) { - $member_of = self::containing(local_channel(),$cid); - } - - if($r) { - foreach($r as $rr) { - $selected = (($group_id == $rr['id']) ? ' group-selected' : ''); - - if ($edit) { - $groupedit = [ 'href' => "group/".$rr['id'], 'title' => t('edit') ]; - } - else { - $groupedit = null; - } - - $groups[] = [ - 'id' => $rr['id'], - 'enc_cid' => base64url_encode($cid), - 'cid' => $cid, - 'text' => $rr['gname'], - 'selected' => $selected, - 'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''), - 'edit' => $groupedit, - 'ismember' => in_array($rr['id'],$member_of), - ]; - } - } - - - $tpl = get_markup_template("group_side.tpl"); - $o = replace_macros($tpl, array( - '$title' => t('Privacy Groups'), - '$edittext' => t('Edit group'), - '$createtext' => t('Add privacy group'), - '$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''), - '$groups' => $groups, - '$add' => t('add'), - )); - - - return $o; - } - - - static function expand($g) { - if(! (is_array($g) && count($g))) - return array(); - - $ret = []; - $x = []; - - // private profile linked virtual groups - - foreach($g as $gv) { - if(substr($gv,0,3) === 'vp.') { - $profile_hash = substr($gv,3); - if($profile_hash) { - $r = q("select abook_xchan from abook where abook_profile = '%s'", - dbesc($profile_hash) - ); - if($r) { - foreach($r as $rv) { - $ret[] = $rv['abook_xchan']; - } - } - } - } - else { - $x[] = $gv; - } - } - - if($x) { - stringify_array_elms($x,true); - $groups = implode(',', $x); - if($groups) { - $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))"); - if($r) { - foreach($r as $rr) { - $ret[] = $rr['xchan']; - } - } - } - } - return $ret; - } - - - static function member_of($c) { - $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ", - dbesc($c) - ); - - return $r; - - } - - static function containing($uid,$c) { - - $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ", - intval($uid), - dbesc($c) - ); - - $ret = array(); - if($r) { - foreach($r as $rr) - $ret[] = $rr['gid']; - } - - return $ret; - } -} \ No newline at end of file diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 31b8f04de..e2cbc66e6 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -386,9 +386,10 @@ class Libzot { else { $p = Permissions::connect_perms($channel['channel_id']); - $my_perms = $p['perms']; + $my_perms = $p['perms']; $automatic = $p['automatic']; + $role = (($automatic) ? $p['role'] : ''); // new connection @@ -410,7 +411,8 @@ class Libzot { 'abook_created' => datetime_convert(), 'abook_updated' => datetime_convert(), 'abook_dob' => $next_birthday, - 'abook_pending' => intval(($automatic) ? 0 : 1) + 'abook_pending' => intval(($automatic) ? 0 : 1), + 'abook_role' => $role ] ); @@ -435,7 +437,7 @@ class Libzot { 'type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] + 'link' => z_root() . '/connections#' . $new_connection[0]['abook_id'] ] ); @@ -453,10 +455,10 @@ class Libzot { $default_group = $channel['channel_default_group']; if ($default_group) { - $g = Group::rec_byhash($channel['channel_id'], $default_group); + $g = AccessList::by_hash($channel['channel_id'], $default_group); if ($g) { - Group::member_add($channel['channel_id'], '', $x['hash'], $g['id']); + AccessList::member_add($channel['channel_id'], '', $x['hash'], $g['id']); } } } @@ -1143,6 +1145,7 @@ class Libzot { if ($env['encoding'] === 'activitystreams') { $AS = new ActivityStreams($data); + if (!$AS->is_valid()) { logger('Activity rejected: ' . print_r($data, true)); return; @@ -1158,8 +1161,6 @@ class Libzot { } - - $deliveries = null; if (array_key_exists('recipients', $env) && count($env['recipients'])) { @@ -1592,6 +1593,7 @@ class Libzot { if ((!$tag_delivery) && (!$local_public)) { $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); + if ((!$allowed) && $perm === 'post_comments') { $parent = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['parent_mid']), @@ -2785,28 +2787,6 @@ class Libzot { if ($deleted || $censored || $sys_channel) $searchable = false; - $public_forum = false; - - $role = get_pconfig($e['channel_id'], 'system', 'permissions_role'); - if ($role === 'forum' || $role === 'repository') { - $public_forum = true; - } - else { - // check if it has characteristics of a public forum based on custom permissions. - $m = Permissions::FilledAutoperms($e['channel_id']); - if ($m) { - foreach ($m as $k => $v) { - if ($k == 'tag_deliver' && intval($v) == 1) - $ch++; - if ($k == 'send_stream' && intval($v) == 0) - $ch++; - } - if ($ch == 2) - $public_forum = true; - } - } - - // This is for birthdays and keywords, but must check access permissions $p = q("select * from profile where uid = %d and is_default = 1", intval($e['channel_id']) @@ -2875,6 +2855,7 @@ class Libzot { ]; $ret['channel_role'] = get_pconfig($e['channel_id'], 'system', 'permissions_role', 'custom'); + $ret['channel_type'] = ((get_pconfig($e['channel_id'], 'system', 'group_actor')) ? 'group' : 'normal'); $hookinfo = [ 'channel_id' => $id, @@ -2890,8 +2871,10 @@ class Libzot { $ret['protocols'] = $hookinfo['protocols']; $ret['searchable'] = $searchable; $ret['adult_content'] = $adult_channel; - $ret['public_forum'] = $public_forum; + // now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group" + // and has nothing to do with accessibility. + $ret['public_forum'] = get_pconfig($e['channel_id'], 'system', 'group_actor'); $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_comments')); $ret['mail'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_mail')); diff --git a/Zotlabs/Lib/Permcat.php b/Zotlabs/Lib/Permcat.php index ca4aed9ed..bda35a9cb 100644 --- a/Zotlabs/Lib/Permcat.php +++ b/Zotlabs/Lib/Permcat.php @@ -4,6 +4,8 @@ namespace Zotlabs\Lib; use Zotlabs\Access\PermissionRoles; use Zotlabs\Access\Permissions; +use Zotlabs\Lib\Libsync; +use Zotlabs\Daemon\Master; /** * @brief Permission Categories. Permission rules for various classes of connections. @@ -79,8 +81,9 @@ class Permcat { $this->permcats[] = [ 'name' => 'default', - 'localname' => t('default','permcat'), + 'localname' => t('Default','permcat'), 'perms' => Permissions::Operms($perms), + 'raw_perms' => $perms, 'system' => 1 ]; @@ -92,6 +95,7 @@ class Permcat { 'name' => $p[$x][0], 'localname' => $p[$x][1], 'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])), + 'raw_perms' => Permissions::FilledPerms($p[$x][2]), 'system' => intval($p[$x][3]) ]; } @@ -128,27 +132,24 @@ class Permcat { } public function load_permcats($uid) { - +/* $permcats = [ - [ 'follower', t('follower','permcat'), - [ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki', - 'post_like' ], 1 + [ 'contributor', t('Contributor','permcat'), + [ 'view_stream','view_profile','view_contacts','view_storage','view_pages', + 'write_storage','post_wall','write_pages','write_wiki','post_comments', 'post_mail', 'post_like', + 'chat' ], 1 ], - [ 'contributor', t('contributor','permcat'), + [ 'muted', t('Muted','permcat'), [ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki', - 'post_wall','post_comments','write_wiki','post_like','tag_deliver','chat' ], 1 + 'post_comments','write_wiki','post_like' ], 1 ], - [ 'publisher', t('publisher','permcat'), - [ 'view_stream','view_profile','view_contacts','view_storage','view_pages', - 'write_storage','post_wall','write_pages','write_wiki','post_comments','post_like','tag_deliver', - 'chat', 'republish' ], 1 - ] ]; - +*/ if($uid) { $x = q("select * from pconfig where uid = %d and cat = 'permcat'", intval($uid) ); + if($x) { foreach($x as $xv) { $value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']); @@ -183,4 +184,105 @@ class Permcat { PConfig::Delete($channel_id, 'permcat', $name); } -} \ No newline at end of file + /** + * @brief assign a contact role to contacts + * + * @param int $channel_id + * @param string $role the name of the role + * @param array $contacts an array of contact hashes + */ + public static function assign($channel, $role, $contacts) { + + if(!isset($channel['channel_id'])) { + return; + } + + if(!is_array($contacts) || empty($contacts)) { + return; + } + + if(!$role) { + // lookup the default + $role = get_pconfig($channel_id, 'system', 'default_permcat', 'default'); + } + + + // Doublecheck that we do not assign a role to ourself. + // It does not make a difference but could be confusing. + if (in_array($channel['channel_hash'], $contacts)) { + $contacts = array_diff($contacts, [$channel['channel_hash']]); + } + + $all_perms = Permissions::Perms(); + $permcats = new Permcat($channel['channel_id']); + $role_perms = $permcats->fetch($role); + + if (isset($role_perms['error'])) { + return false; + } + + $perms = $role_perms['raw_perms']; + + $values_sql = ''; + stringify_array_elms($contacts, true); + + if ($all_perms && $perms) { + + foreach ($contacts as $contact) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists($perm, $perms)) { + $values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', " . intval($perms[$perm]) . "),"; + } + else { + $values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', 0), "; + } + } + } + } + + $values_sql = rtrim($values_sql, ','); + + dbq("DELETE FROM abconfig WHERE chan = " . intval($channel['channel_id']) . " AND cat = 'my_perms' AND xchan IN (" . protect_sprintf(implode(',', $contacts)) . ")"); + + dbq("INSERT INTO abconfig ( chan, xchan, cat, k, v ) VALUES $values_sql"); + + q("UPDATE abook SET abook_role = '%s' + WHERE abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook_channel = %d", + dbesc($role), + intval($channel['channel_id']) + ); + + $r = q("SELECT abook.*, xchan.* FROM abook LEFT JOIN xchan ON abook.abook_xchan = xchan.xchan_hash WHERE abook.abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook.abook_channel = %d AND abook_self = 0", + intval($channel['channel_id']) + ); + + foreach ($r as $rr) { + + if (intval($rr['abook_self'])) { + continue; + } + + Master::Summon([ + 'Notifier', + 'permission_update', + $rr['abook_id'] + ]); + + $clone = $rr; + + 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]]); + + } + + return true; + } + +} diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index cd54fea17..e7cb2d5de 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -3,6 +3,7 @@ namespace Zotlabs\Lib; use Zotlabs\Lib\Apps; +use Zotlabs\Access\AccessList; require_once('include/text.php'); @@ -58,6 +59,9 @@ class ThreadItem { $child = new ThreadItem($item); $this->add_child($child); } + + // performance: we have already added the children + unset($this->data['children']); } // allow a site to configure the order and content of the reaction emoji list @@ -98,11 +102,20 @@ class ThreadItem { $conv = $this->get_conversation(); $observer = $conv->get_observer(); - $lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) - || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) - ? t('Private Message') + $acl = new AccessList(false); + $acl->set($item); + + $lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private())) + ? t('Restricted message') : false); - $locktype = $item['item_private']; + + // 1 = restricted message, 2 = direct message + $locktype = intval($item['item_private']); + // 0 = limited based on public policy + if ($item['uid'] == local_channel() && intval($item['item_private']) && !$acl->is_private() && strlen($item['public_policy'])) { + $lock = t('Public Policy'); + $locktype = 0; + } $shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false); @@ -110,6 +123,16 @@ class ThreadItem { if($item['author']['xchan_network'] === 'rss') $shareable = true; + // @fixme + // Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group. + // Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions. + // The original poll author may not accept responses from strangers. Forking the poll will receive responses from the sharer's + // followers, but there's no elegant way to merge these two sets of results together. For now, we'll disable sharing polls. + + if ($item['obj_type'] === 'Question') { + $shareable = false; + } + $privacy_warning = false; if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) { $recips = get_iconfig($item['parent'], 'activitypub', 'recips'); 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/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 4ebd2ee29..aebc70c15 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -95,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..b77e5d06d 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,14 +322,14 @@ 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'], @@ -349,13 +357,21 @@ 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']] ); } } } - - + + $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 +387,29 @@ class Connections extends \Zotlabs\Web\Controller { } else { $o .= ""; - $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'), '$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 .= '
'; - + 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 @@ = 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 .= "\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 = ''; $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 .= '
' . 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'), '', '',$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 privacy settings, which have higher priority than individual settings. You can not change those settings here.'), - '$permnote_self' => t('Some permissions may be inherited from your channel\'s privacy settings, 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 privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$permnote_self' => t('Some permissions may be inherited from your channel\'s privacy settings, 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 @@ += 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 = ''; + $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 .= '
' . t('Location independence is not supported by their network.'); + } + + $header_card = '  ' . $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 @@ 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..4c6b0c838 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; } @@ -127,7 +140,7 @@ class Group extends Controller { foreach($groups as $group) { $entries[$i]['name'] = $group['gname']; $entries[$i]['id'] = $group['id']; - $entries[$i]['count'] = count(group_get_members($group['id'])); + $entries[$i]['count'] = count(AccessList::members(local_channel(), $group['id'])); $i++; } @@ -135,6 +148,10 @@ class Group extends Controller { 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'), @@ -143,16 +160,19 @@ class Group extends Controller { // 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'), + '$is_default_acl' => $is_default_acl, + '$is_default_group' => $is_default_group, // groups list '$title' => t('Privacy Groups'), '$name_label' => t('Name'), '$count_label' => t('Members'), '$entries' => $entries + ]); return $o; @@ -174,7 +194,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 +235,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 +247,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,7 +272,7 @@ 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'), '$form_security_token_drop' => get_form_security_token("group_drop"), @@ -280,7 +300,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 +322,15 @@ class Group extends Controller { $context['$desc'] = t('Click a channel to toggle membership'); $context['$pgrp_extras'] = $pgrp_extras; + $channel = App::get_channel(); + +//hz_syslog(print_r($group,true)); +//hz_syslog(print_r($channel,true)); + + $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/Item.php b/Zotlabs/Module/Item.php index 9b76c7569..66629fa2b 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -416,6 +416,7 @@ class Item extends Controller { $expires = NULL_DATE; + $comments_closed = NULL_DATE; $route = ''; $parent_item = null; @@ -692,6 +693,7 @@ class Item extends Controller { $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']; @@ -794,13 +796,7 @@ 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 = (($channel_type === 'group') ? true : false); + $is_group = get_pconfig($profile_uid, 'system', 'group_actor'); if (($is_group) && ($walltowall) && (!$walltowall_comment)) { $groupww = true; @@ -994,8 +990,9 @@ class Item extends Controller { $notify_type = (($parent) ? 'comment-new' : 'wall-new'); + $uuid = (($message_id) ? $message_id : item_message_id()); + if (!$mid) { - $uuid = (($message_id) ? $message_id : item_message_id()); $mid = z_root() . '/item/' . $uuid; } @@ -1015,10 +1012,22 @@ class Item extends Controller { } if ($obj) { - $obj['url'] = $mid; - $obj['attributedTo'] = channel_url($channel); - $datarray['obj'] = $obj; - $obj_type = 'Question'; + $obj['url'] = $mid; + $obj['id'] = $mid; + $obj['diaspora:guid'] = $uuid; + $obj['attributedTo'] = channel_url($channel); + $obj['published'] = $created; + + $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) { @@ -1082,6 +1091,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); @@ -1594,6 +1604,8 @@ 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); } 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 @@ %') . "' ) 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 3b0b35258..5989e3da6 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -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.') . '
' . '' . t('Read more about channel permission roles') . '',$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..a46253ec2 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,59 @@ 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'); - $all_perms = \Zotlabs\Access\Permissions::Perms(); - $name = escape_tags(trim($_POST['name'])); - if(! $name) { + $is_system_role = isset($_POST['is_system_role']); + $return_path = z_root() . '/permcats/' . $_POST['return_path']; + $group_hash = ((isset($_POST['group_select'])) ? $_POST['group_select'] : ''); + $contacts = []; + + 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($_POST['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 +77,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,13 +97,6 @@ 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'); - } - $channel = App::get_channel(); if(argc() > 1) @@ -70,24 +104,49 @@ class Permcats extends Controller { if(argc() > 2 && argv(2) === 'drop') { \Zotlabs\Lib\Permcat::delete(local_channel(),$name); + + // TODO: assign all members of the deleted role to the default role + 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(); + +/* not yet ready + $test = $pcatlist[4]['perms']; + $role_sql = ''; + + foreach ($test as $t) + $role_sql .= "( k = '" . dbesc($t['name']) . "' AND v = '" . intval($t['value']) . "' ) OR "; + + $role_sql = rtrim($role_sql, ' OR '); + + // get all xchans belonging to a permission role + $q = q("SELECT xchan FROM abconfig WHERE chan = %d AND cat = 'my_perms' AND ( $role_sql ) GROUP BY xchan HAVING count(xchan) = %d", + intval(local_channel()), + intval(count($test)) + ); +*/ + + $is_system_role = false; $permcats = []; 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']; + } + + $permcats[bin2hex($pc['name'])] = $pc['localname']; + + if($pc['name'] == $name) + $localname = $pc['localname']; } } @@ -98,33 +157,56 @@ 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 + ]; } + $is_default_role = (get_pconfig(local_channel(),'system','default_permcat','default') == $name); + + $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, + '$default_role' => array('default_role', t('Use this role as default for new contacts'), intval($is_default_role), '', [t('No'), t('Yes')]), + + '$title' => t('Contact Roles'), '$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') . ' *', (($name) ? $name : ''), ''), - '$me' => t('My Settings'), + '$name' => ['name', t('Role name') . ' *', (($localname) ? $localname : ''), (($is_system_role) ? t('System role - not editable') : '') , '', (($is_system_role) ? 'disabled' : '')], '$perms' => $perms, '$inherited' => t('inherited'), - '$notself' => 0, - '$self' => 1, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not 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 channel role, which have higher priority than contact role settings.'), + '$submit' => t('Submit'), + '$return_path' => argv(1), + '$group_select' => $group_select, + )); return $o; } diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 1512148b1..ca0ca4f1a 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -316,8 +316,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); @@ -513,6 +511,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); } @@ -551,7 +559,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), @@ -587,6 +596,7 @@ class Profiles extends \Zotlabs\Web\Controller { dbesc($education), intval($hide_friends), dbesc($profile_vcard), + intval($publish), intval(argv(1)), intval(local_channel()) ); @@ -675,13 +685,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 = ''; + } + 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 +750,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 +764,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 +772,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 +841,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 462c997ff..33bb8d957 100644 --- a/Zotlabs/Module/Regate.php +++ b/Zotlabs/Module/Regate.php @@ -196,7 +196,7 @@ class Regate extends \Zotlabs\Web\Controller { if ($invite_channel) { $f = Connect::connect($new_channel['channel'], $invite_channel['xchan_addr']); if ($f['success']) { - $can_view_stream = their_perms_contains($channel_id, $f['abook']['abook_xchan'], 'view_stream'); + $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']]); diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index e95752338..914523960 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,266 @@ 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 !== 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 = ''; - } - 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())) ? '
' . 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())) ? '
' . 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 = ''; + $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); + if ($vnotify === false) + $vnotify = (-1); - $permissions_set = (($permissions_role != 'custom') ? true : false); + $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role'); + if (!$permissions_role) { + $permissions_role = 'custom'; + } - $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + $perm_roles = PermissionRoles::channel_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 - extremely permissive (should be used with caution)'), - '$pmacro2' => t('Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)'), - '$pmacro1' => t('Private - default private, never open or public'), - '$pmacro0' => t('Blocked - default blocked to/from everybody'), - '$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 interesting 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')], + '$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 interesting 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 .= '' . "\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 @@ + $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/Uexport.php b/Zotlabs/Module/Uexport.php index 8116f616b..870c42802 100644 --- a/Zotlabs/Module/Uexport.php +++ b/Zotlabs/Module/Uexport.php @@ -143,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 = ''; diff --git a/Zotlabs/Update/_1249.php b/Zotlabs/Update/_1249.php new file mode 100644 index 000000000..6d72c4de4 --- /dev/null +++ b/Zotlabs/Update/_1249.php @@ -0,0 +1,31 @@ +' : ''); diff --git a/Zotlabs/Widget/Permcats.php b/Zotlabs/Widget/Permcats.php new file mode 100644 index 000000000..72c80ca0c --- /dev/null +++ b/Zotlabs/Widget/Permcats.php @@ -0,0 +1,79 @@ +listing(); + + $list = 'Roles:
'; + $active = ''; + $active_role = ''; + + if($pcatlist) { + $i = 0; + foreach($pcatlist as $pc) { + if(argc() > 1) { + if($pc['name'] == hex2bin(argv(1))) { + $active = $i; + $active_role = $pc['name']; + } + } + + $list .= '' . $pc['localname'] . '
'; + $i++; + } + } + + if(argc() > 1) { + +/* get role members based on permissions + $test = $pcatlist[$active]['perms']; + + $role_sql = ''; + $count = 0; + foreach ($test as $t) { + $checkinherited = PermissionLimits::Get(local_channel(),$t['name']); + + if($checkinherited & PERMS_SPECIFIC) { + $role_sql .= "( abconfig.k = '" . dbesc($t['name']) . "' AND abconfig.v = '" . intval($t['value']) . "' ) OR "; + $count++; + } + } + + $role_sql = rtrim($role_sql, ' OR '); + + $r = q("SELECT abconfig.xchan, xchan.xchan_name, abook.abook_id FROM abconfig LEFT JOIN xchan on abconfig.xchan = xchan.xchan_hash LEFT JOIN abook ON abconfig.xchan = abook.abook_xchan WHERE xchan.xchan_deleted = 0 and abconfig.chan = %d AND abconfig.cat = 'my_perms' AND ( $role_sql ) GROUP BY abconfig.xchan HAVING count(abconfig.xchan) = %d ORDER BY xchan.xchan_name", + intval(local_channel()), + intval($count) + ); +*/ + + // get role members based on abook_role + + $r = q("SELECT abook.abook_id, abook.abook_role, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM abook + LEFT JOIN xchan on abook.abook_xchan = xchan.xchan_hash + WHERE abook.abook_channel = %d AND abook.abook_role = '%s' AND abook_self = 0 AND xchan_deleted = 0 + ORDER BY xchan.xchan_name", + intval(local_channel()), + dbesc($active_role) + ); + + $members = 'Role members:
'; + $members .= '
'; + + foreach ($r as $rr) { + $addr = (($rr['xchan_addr']) ? $rr['xchan_addr'] : $rr['xchan_url']); + $members .= '' . $rr['xchan_name'] . '
' . $addr . '
'; + } + $members .= '
'; + } + return $list . '
' . $members. '
' . $others; + + } +} diff --git a/Zotlabs/Widget/Profile.php b/Zotlabs/Widget/Profile.php index 8bd624c0f..0e5444a56 100644 --- a/Zotlabs/Widget/Profile.php +++ b/Zotlabs/Widget/Profile.php @@ -2,12 +2,16 @@ namespace Zotlabs\Widget; +use App; class Profile { - function widget($args) { + if(!App::$profile['profile_uid']) { + return; + } + $block = observer_prohibited(); - return profile_sidebar(\App::$profile, $block, true, false); - } + return profile_sidebar(App::$profile, $block, true, false); + } } diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php index 25b80a4b4..4d0f1d2dd 100644 --- a/Zotlabs/Widget/Settings_menu.php +++ b/Zotlabs/Widget/Settings_menu.php @@ -40,6 +40,11 @@ class Settings_menu { 'selected' => ((argv(1) === 'channel') ? 'active' : ''), ), + array( + 'label' => t('Privacy settings'), + 'url' => z_root().'/settings/privacy', + 'selected' => ((argv(1) === 'privacy') ? 'active' : '') + ) ); $tabs[] = array( diff --git a/app/group.apd b/app/group.apd index d026ed23d..bf3ddf4a1 100644 --- a/app/group.apd +++ b/app/group.apd @@ -1,7 +1,7 @@ -version: 3 +version: 4 url: $baseurl/group requires: local_channel name: Privacy Groups -photo: icon:users +photo: icon:lock categories: Networking desc: A tool to create and manage privacy groups. diff --git a/boot.php b/boot.php index 607d64e60..120383d7c 100644 --- a/boot.php +++ b/boot.php @@ -55,10 +55,10 @@ require_once('include/bbcode.php'); require_once('include/items.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '6.5.1' ); +define ( 'STD_VERSION', '6.5.9' ); define ( 'ZOT_REVISION', '6.0' ); -define ( 'DB_UPDATE_VERSION', 1248 ); +define ( 'DB_UPDATE_VERSION', 1249 ); define ( 'PROJECT_BASE', __DIR__ ); @@ -484,7 +484,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' ); define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' ); -define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.9' ); +define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.10' ); /** * activity stream defines */ @@ -860,7 +860,7 @@ class App { private static $baseurl; - private static $meta; + public static $meta; /** * App constructor. diff --git a/include/attach.php b/include/attach.php index 067da21ae..2109b84f1 100644 --- a/include/attach.php +++ b/include/attach.php @@ -15,10 +15,10 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Activity; use Zotlabs\Access\PermissionLimits; use Zotlabs\Daemon\Master; +use Zotlabs\Lib\AccessList; require_once('include/permissions.php'); require_once('include/security.php'); -require_once('include/group.php'); /** * @brief Guess the mimetype from file ending. @@ -2208,7 +2208,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $ //lookup all channels in sharee group and add them to sharee $arr_allow_cid if($arr_allow_gid) { - $in_group = expand_groups($arr_allow_gid); + $in_group = AccessList::expand($arr_allow_gid); $arr_allow_cid = array_unique(array_merge($arr_allow_cid, $in_group)); } @@ -2280,7 +2280,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $ //check sharee arr_allow_cid against members of allow_gid of all parent folders foreach($parent_arr['allow_gid'] as $folder_arr_allow_gid) { //get the group members - $folder_arr_allow_cid = expand_groups($folder_arr_allow_gid); + $folder_arr_allow_cid = AccessList::expand($folder_arr_allow_gid); foreach($folder_arr_allow_cid as $ac_hash) { $count_values[$ac_hash]++; } diff --git a/include/channel.php b/include/channel.php index 102a03489..00d973738 100644 --- a/include/channel.php +++ b/include/channel.php @@ -15,6 +15,7 @@ use Zotlabs\Render\Comanche; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Connect; use Zotlabs\Lib\Libsync; +use Zotlabs\Lib\AccessList; require_once('include/crypto.php'); require_once('include/menu.php'); @@ -240,7 +241,7 @@ function create_identity($arr) { // Force a few things on the short term until we can provide a theme or app with choice - $publish = 1; + $publish = 0; if(array_key_exists('publish', $arr)) $publish = intval($arr['publish']); @@ -325,6 +326,12 @@ function create_identity($arr) { if($role_permissions && array_key_exists('perms_auto',$role_permissions)) set_pconfig($r[0]['channel_id'],'system','autoperms',intval($role_permissions['perms_auto'])); + $group_actor = false; + if($role_permissions && array_key_exists('channel_type', $role_permissions) && $role_permissions['channel_type'] === 'group') { + set_pconfig($r[0]['channel_id'], 'system', 'group_actor', 1); + $group_actor = true; + } + $ret['channel'] = $r[0]; if(intval($arr['account_id'])) @@ -374,7 +381,8 @@ function create_identity($arr) { 'xchan_network' => 'zot6', 'xchan_photo_date' => datetime_convert(), 'xchan_name_date' => datetime_convert(), - 'xchan_system' => $system + 'xchan_system' => $system, + 'xchan_pubforum' => $group_actor ] ); if(! $r) @@ -399,14 +407,6 @@ function create_identity($arr) { ] ); - if($role_permissions) { - $myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : array()); - } - else { - $x = PermissionRoles::role_perms('social'); - $myperms = $x['perms_connect']; - } - $r = abook_store_lowlevel( [ 'abook_account' => intval($ret['channel']['channel_account_id']), @@ -419,19 +419,18 @@ function create_identity($arr) { ] ); - $x = Permissions::FilledPerms($myperms); - foreach($x as $k => $v) { - set_abconfig($newuid,$hash,'my_perms',$k,$v); - } - if(intval($ret['channel']['channel_account_id'])) { - // Save our permissions role so we can perhaps call it up and modify it later. + + // Set the default permcat + set_pconfig($newuid,'system','default_permcat','default'); if($role_permissions) { + // Save our permissions role so we can perhaps call it up and modify it later. set_pconfig($newuid,'system','permissions_role',$arr['permissions_role']); + if(array_key_exists('online',$role_permissions)) - set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online'])); + set_pconfig($newuid,'system','show_online_status', intval($role_permissions['online'])); if(array_key_exists('perms_auto',$role_permissions)) { $autoperms = intval($role_permissions['perms_auto']); set_pconfig($newuid,'system','autoperms',$autoperms); @@ -453,11 +452,10 @@ function create_identity($arr) { // Create a group with yourself as a member. This allows somebody to use it // right away as a default group for new contacts. - require_once('include/group.php'); - $group_hash = group_add($newuid, t('Friends')); + $group_hash = AccessList::add($newuid, t('Friends')); if($group_hash) { - group_add_member($newuid,t('Friends'),$ret['channel']['channel_hash']); + AccessList::member_add($newuid,t('Friends'),$ret['channel']['channel_hash']); $default_collection_str = ''; // if our role_permissions indicate that we're using a default collection ACL, add it. @@ -496,8 +494,7 @@ function create_identity($arr) { if($acct) { $f = connect_and_sync($ret['channel'], $acct); if($f['success']) { - $can_view_stream = their_perms_contains($ret['channel']['channel_id'],$f['abook']['abook_xchan'],'view_stream'); - + $can_view_stream = intval(get_abconfig($ret['channel']['channel_id'], $f['abook']['abook_xchan'], 'their_perms', 'view_stream')); // If we can view their stream, pull in some posts if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) { Master::Summon([ 'Onepoll',$f['abook']['abook_id'] ]); @@ -1488,6 +1485,7 @@ function profile_load($nickname, $profile = '') { if($can_view_profile) { $online = get_online_status($nickname); + App::$profile['online_status'] = $online['result']; } @@ -2060,11 +2058,12 @@ function get_online_status($nick) { return $ret; $r = q("select channel_id, channel_hash from channel where channel_address = '%s' limit 1", - dbesc(argv(1)) + dbesc($nick) ); + if($r) { - $hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status'); - if($hide) + $show = get_pconfig($r[0]['channel_id'],'system','show_online_status'); + if(!$show) return $ret; $x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1", diff --git a/include/connections.php b/include/connections.php index 0611377ab..11264e6d8 100644 --- a/include/connections.php +++ b/include/connections.php @@ -27,7 +27,8 @@ function abook_store_lowlevel($arr) { 'abook_profile' => ((array_key_exists('abook_profile',$arr)) ? $arr['abook_profile'] : ''), 'abook_incl' => ((array_key_exists('abook_incl',$arr)) ? $arr['abook_incl'] : ''), 'abook_excl' => ((array_key_exists('abook_excl',$arr)) ? $arr['abook_excl'] : ''), - 'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : '') + 'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : ''), + 'abook_role' => ((array_key_exists('abook_role',$arr)) ? $arr['abook_role'] : '') ]; return create_table_from_array('abook',$store); diff --git a/include/conversation.php b/include/conversation.php index a7dfa6b73..d12151fcc 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1070,7 +1070,7 @@ function thread_author_menu($item, $mode = '') { if($contact) { $poke_link = ((Apps::system_app_installed($local_channel, 'Poke')) ? z_root() . '/poke/?f=&c=' . $contact['abook_id'] : ''); if (! intval($contact['abook_self'])) - $contact_url = z_root() . '/connedit/' . $contact['abook_id']; + $contact_url = z_root() . '/connections#' . $contact['abook_id']; $posts_link = z_root() . '/network/?cid=' . $contact['abook_id']; $clean_url = normalise_link($item['author-link']); @@ -1086,7 +1086,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('View Profile'), 'icon' => 'fw', 'action' => '', - 'href' => $profile_link + 'href' => $profile_link, + 'data' => '', + 'class' => '' ]; } @@ -1096,7 +1098,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('Recent Activity'), 'icon' => 'fw', 'action' => '', - 'href' => $posts_link + 'href' => $posts_link, + 'data' => '', + 'class' => '' ]; } @@ -1107,6 +1111,8 @@ function thread_author_menu($item, $mode = '') { 'icon' => 'fw', 'action' => 'doFollowAuthor(\'' . $follow_url . '\'); return false;', 'href' => '#', + 'data' => '', + 'class' => '' ]; } @@ -1116,7 +1122,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('Edit Connection'), 'icon' => 'fw', 'action' => '', - 'href' => $contact_url + 'href' => $contact_url, + 'data' => 'data-id="' . $contact['abook_id'] . '"', + 'class' => 'contact-edit' ]; } @@ -1126,7 +1134,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('Message'), 'icon' => 'fw', 'action' => '', - 'href' => $pm_url + 'href' => $pm_url, + 'data' => '', + 'class' => '' ]; } @@ -1136,7 +1146,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('Ratings'), 'icon' => 'fw', 'action' => '', - 'href' => $ratings_url + 'href' => $ratings_url, + 'data' => '', + 'class' => '' ]; } @@ -1146,7 +1158,9 @@ function thread_author_menu($item, $mode = '') { 'title' => t('Poke'), 'icon' => 'fw', 'action' => '', - 'href' => $poke_link + 'href' => $poke_link, + 'data' => '', + 'class' => '' ]; } diff --git a/include/group.php b/include/group.php index bb1ed5ed8..4e1472900 100644 --- a/include/group.php +++ b/include/group.php @@ -326,7 +326,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id $o = replace_macros($tpl, array( '$title' => t('Privacy Groups'), '$edittext' => t('Edit group'), - '$createtext' => t('Add privacy group'), + '$createtext' => ((argv(1) == 'new' ) ? '' : t('Manage privacy groups')), '$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''), '$groups' => $groups, '$add' => t('add'), diff --git a/include/items.php b/include/items.php index 2ee870c2f..a66703e6e 100644 --- a/include/items.php +++ b/include/items.php @@ -13,9 +13,10 @@ use Zotlabs\Lib\IConfig; use Zotlabs\Lib\Activity; use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\ActivityStreams; use Zotlabs\Access\PermissionLimits; use Zotlabs\Access\PermissionRoles; -use Zotlabs\Access\AccessList; +use Zotlabs\Lib\AccessList; use Zotlabs\Daemon\Master; require_once('include/bbcode.php'); @@ -35,8 +36,6 @@ require_once('include/permissions.php'); */ function collect_recipients($item, &$private_envelope,$include_groups = true) { - require_once('include/group.php'); - $private_envelope = ((intval($item['item_private'])) ? true : false); $recipients = array(); @@ -47,7 +46,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { $allow_people = expand_acl($item['allow_cid']); if($include_groups) { - $allow_groups = expand_groups(expand_acl($item['allow_gid'])); + $allow_groups = AccessList::expand(expand_acl($item['allow_gid'])); } else { $allow_groups = []; @@ -72,7 +71,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { } $deny_people = expand_acl($item['deny_cid']); - $deny_groups = expand_groups(expand_acl($item['deny_gid'])); + $deny_groups = AccessList::expand(expand_acl($item['deny_gid'])); $deny = array_unique(array_merge($deny_people,$deny_groups)); @@ -344,6 +343,7 @@ function can_comment_on_post($observer_xchan, $item) { return true; break; case 'any connections': + case 'specific': case 'contacts': case '': if(local_channel() && get_abconfig(local_channel(),$item['owner_xchan'],'their_perms','post_comments')) { @@ -1226,6 +1226,9 @@ function map_scope($scope, $strip = false) { return 'site: ' . App::get_hostname(); case PERMS_PENDING: return 'any connections'; +// uncomment after Hubzilla version 7.0 is running on the majority of active hubs +// case PERMS_SPECIFIC: +// return 'specific'; case PERMS_CONTACTS: default: return 'contacts'; @@ -2537,12 +2540,7 @@ function get_item_contact($item,$contacts) { */ function tag_deliver($uid, $item_id) { - $role = get_pconfig($uid,'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - - $is_group = (($channel_type === 'group') ? true : false); - + $is_group = get_pconfig($uid, 'system', 'group_actor'); $mention = false; /* @@ -2579,15 +2577,18 @@ function tag_deliver($uid, $item_id) { } if ($is_group && intval($item['item_private']) === 2 && intval($item['item_thread_top'])) { - // do not turn the groups own direkt messages into group items if($item['item_wall'] && $item['author_xchan'] === $u[0]['channel_hash']) return; // group delivery via DM - if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall') || perm_is_allowed($uid,$item['owner_xchan'],'tag_deliver')) { + if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall')) { logger('group DM delivery for ' . $u[0]['channel_address']); start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted'])); + q("update item set item_blocked = %d where id = %d", + intval(ITEM_HIDDEN), + intval($item_id) + ); } return; } @@ -2600,13 +2601,6 @@ function tag_deliver($uid, $item_id) { return; } - /* this should not be required anymore due to the check above - if (strpos($item['body'],'[/share]')) { - logger('W2W post already shared'); - return; - } - */ - // group delivery via W2W logger('rewriting W2W post for ' . $u[0]['channel_address']); start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted'])); @@ -2677,9 +2671,37 @@ function tag_deliver($uid, $item_id) { intval($uid) ); - if(($x) && intval($x[0]['item_uplink'])) { - start_delivery_chain($u[0],$item,$item_id,$x[0]); + if ($x) { + + // group comments don't normally require a second delivery chain + // but we create a linked Announce so they will show up in the home timeline + // on microblog platforms and this creates a second delivery chain + + if ($is_group && intval($x[0]['item_wall'])) { + // don't let the forked delivery chain recurse + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $u['channel_hash']) { + return; + } + // don't announce moderated content until it has been approved + if (intval($item['item_blocked']) === ITEM_MODERATED) { + return; + } + + // don't boost likes and other response activities as it is likely that + // few platforms will handle this in an elegant way + + if (ActivityStreams::is_response_activity($item['verb'])) { + return; + } + logger('group_comment'); + start_delivery_chain($u[0], $item, $item_id, $x[0], true, (($item['edited'] != $item['created']) || $item['item_deleted'])); + + } + elseif (intval($x[0]['item_uplink'])) { + start_delivery_chain($u,$item,$item_id,$x[0]); + } } + } @@ -2920,13 +2942,7 @@ function item_community_tag($channel,$item) { */ function tgroup_check($uid, $item) { - - $role = get_pconfig($uid,'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - - $is_group = (($channel_type === 'group') ? true : false); - + $is_group = get_pconfig($uid, 'system', 'group_actor'); $mention = false; // check that the message originated elsewhere and is a top-level post @@ -3125,6 +3141,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $arr = []; + q("update item set item_hidden = 1 where id = %d", + intval($item_id) + ); + if ($edit) { // process edit or delete action @@ -3155,7 +3175,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false } else { $arr['uuid'] = item_message_id(); - $arr['mid'] = z_root() . '/activity/' . $arr['uuid']; + $arr['mid'] = z_root() . '/item/' . $arr['uuid']; $arr['parent_mid'] = $arr['mid']; } @@ -3173,6 +3193,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); + if ($channel['channel_allow_cid'] && empty($channel['channel_allow_gid'])) { + $arr['item_private'] = 2; + } + $arr['item_origin'] = 1; $arr['item_wall'] = 1; $arr['item_thread_top'] = 1; @@ -3192,6 +3216,29 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $bb .= "[/share]"; $arr['body'] = $bb; + // Conversational objects shouldn't be copied, but other objects should. + if (in_array($item['obj_type'], [ 'Image', 'Event', 'Question' ])) { + $arr['obj'] = $item['obj']; + $t = json_decode($arr['obj'],true); + + if ($t !== NULL) { + $arr['obj'] = $t; + } + $arr['obj']['content'] = bbcode($bb); + $arr['obj']['source']['content'] = $bb; + $arr['obj']['id'] = $arr['mid']; + + if (! array_path_exists('obj/source/mediaType',$arr)) { + $arr['obj']['source']['mediaType'] = 'text/bbcode'; + } + + $arr['obj']['directMessage'] = (intval($arr['item_private']) === 2); + + } + + $arr['tgt_type'] = $item['tgt_type']; + $arr['target'] = $item['target']; + $arr['term'] = $item['term']; $arr['author_xchan'] = $channel['channel_hash']; @@ -3222,6 +3269,92 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false } + if ($group && $parent) { + logger('comment arrived in group', LOGGER_DEBUG); + $arr = []; + + // don't let this recurse. We checked for this before calling, but this ensures + // it doesn't sneak through another way because recursion is nasty. + + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $channel['channel_hash']) { + return; + } + + // Don't send Announce activities for poll responses. + + if ($item['obj_type'] === 'Answer') { + return; + } + + if ($edit) { + if (intval($item['item_deleted'])) { + drop_item($item['id'],false,DROPITEM_PHASE1); + Master::Summon([ 'Notifier','drop',$item['id'] ]); + return; + } + return; + } + else { + $arr['uuid'] = item_message_id(); + $arr['mid'] = z_root() . '/activity/' . $arr['uuid']; + $arr['parent_mid'] = $item['parent_mid']; + //IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid'])); + } + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + + $arr['verb'] = 'Announce'; + + if (is_array($item['obj'])) { + $arr['obj'] = $item['obj']; + } + elseif (is_string($item['obj']) && strlen($item['obj'])) { + $arr['obj'] = json_decode($item['obj'],true); + } + + if (! $arr['obj']) { + $arr['obj'] = $item['mid']; + } + + if (is_array($arr['obj'])) { + $obj_actor = ((isset($arr['obj']['actor'])) ? ((is_array($arr['obj']['actor'])) ? $arr['obj']['actor']['id'] : $arr['obj']['actor']) : $arr['obj']['attributedTo']); + $mention = Activity::get_actor_bbmention($obj_actor); + $arr['body'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $arr['obj']['type']); + } + + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_wall'] = 1; + + $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); + + $arr['item_origin'] = 1; + $arr['item_notshown'] = 1; + + $arr['item_thread_top'] = 0; + + $arr['allow_cid'] = $channel['channel_allow_cid']; + $arr['allow_gid'] = $channel['channel_allow_gid']; + $arr['deny_cid'] = $channel['channel_deny_cid']; + $arr['deny_gid'] = $channel['channel_deny_gid']; + $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments')); + + $post = item_store($arr); + $post_id = $post['item_id']; + + if ($post_id) { + Master::Summon([ 'Notifier','tgroup',$post_id ]); + } + + q("update channel set channel_lastpost = '%s' where channel_id = %d", + dbesc(datetime_convert()), + intval($channel['channel_id']) + ); + + return; + } + + // Change this copy of the post to a forum head message and deliver to all the tgroup members // also reset all the privacy bits to the forum default permissions @@ -3510,12 +3643,11 @@ function compare_permissions($obj1,$obj2) { * @return array */ function enumerate_permissions($obj) { - require_once('include/group.php'); $allow_people = expand_acl($obj['allow_cid']); - $allow_groups = expand_groups(expand_acl($obj['allow_gid'])); + $allow_groups = AccessList::expand(expand_acl($obj['allow_gid'])); $deny_people = expand_acl($obj['deny_cid']); - $deny_groups = expand_groups(expand_acl($obj['deny_gid'])); + $deny_groups = AccessList::expand(expand_acl($obj['deny_gid'])); $recipients = array_unique(array_merge($allow_people,$allow_groups)); $deny = array_unique(array_merge($deny_people,$deny_groups)); $recipients = array_diff($recipients,$deny); @@ -4252,7 +4384,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $contact_str = ''; - $contacts = group_get_members($r[0]['id']); + $contacts = AccessList::members($uid, $r[0]['id']); if ($contacts) { foreach($contacts as $c) { if($contact_str) @@ -4268,7 +4400,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $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($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) "; - $x = group_rec_byhash($uid,$r[0]['hash']); + $x = AccessList::by_hash($uid, $r[0]['hash']); $result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']); } elseif($arr['cid'] && $uid) { diff --git a/include/nav.php b/include/nav.php index 7cc64ab1b..9278c1587 100644 --- a/include/nav.php +++ b/include/nav.php @@ -26,7 +26,7 @@ function nav($template = 'default') { intval($channel['channel_id']) ); - if (empty($_SESSION['delegate'])) { + if (empty($_SESSION['delegate']) && feature_enabled(local_channel(), 'nav_channel_select')) { $chans = q("select channel_name, channel_id from channel where channel_account_id = %d and channel_removed = 0 order by channel_name ", intval(get_account_id()) ); @@ -97,13 +97,11 @@ function nav($template = 'default') { if (empty($_SESSION['delegate'])) { $nav['manage'] = ['manage', t('Channels'), "", t('Manage your channels'), 'manage_nav_btn']; } - if (Apps::system_app_installed(local_channel(), 'Privacy Groups')) - $nav['group'] = ['group', t('Privacy Groups'), "", t('Manage your privacy groups'), 'group_nav_btn']; $nav['settings'] = ['settings', t('Settings'), "", t('Account/Channel Settings'), 'settings_nav_btn']; - if ($chans && count($chans) > 1 && feature_enabled(local_channel(), 'nav_channel_select')) + if ($chans && count($chans) > 1) $nav['channels'] = $chans; $nav['logout'] = ['logout', t('Logout'), "", t('End this session'), 'logout_nav_btn']; diff --git a/include/permissions.php b/include/permissions.php index d94b70da6..bbd13ed58 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -21,7 +21,7 @@ require_once('include/security.php'); * @param bool $default_ignored (default true) * if false, lie and pretend the ignored person has permissions you are ignoring (used in channel discovery) * - * @returns array of all permissions, key is permission name, value is true or false + * @returns array of all permissions, key is permission name, value is 1 or 0 */ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ignored = true) { @@ -61,7 +61,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // The uid provided doesn't exist. This would be a big fail. if(! $r) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -70,7 +70,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if($observer_xchan) { if($channel_perm & PERMS_AUTHED) { - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } @@ -104,7 +104,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // If they're blocked - they can't read or write if(($x) && intval($x[0]['abook_blocked'])) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -115,7 +115,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if(($x) && ($default_ignored) && in_array($perm_name,$blocked_anon_perms) && intval($x[0]['abook_ignored'])) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } } @@ -123,7 +123,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // system is blocked to anybody who is not authenticated if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -133,16 +133,16 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if(($observer_xchan) && ($r[0]['channel_hash'] === $observer_xchan)) { if($r[0]['channel_moved'] && (in_array($perm_name,$blocked_anon_perms))) - $ret[$perm_name] = false; + $ret[$perm_name] = 0; else - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } // Anybody at all (that wasn't blocked or ignored). They have permission. if($channel_perm & PERMS_PUBLIC) { - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } @@ -150,7 +150,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // out, permission is denied. if(! $observer_xchan) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -158,7 +158,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if($channel_perm & PERMS_NETWORK) { if($x && $x[0]['xchan_network'] === 'zot6') { - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } } @@ -175,9 +175,9 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ } if($c) - $ret[$perm_name] = true; + $ret[$perm_name] = 1; else - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -186,19 +186,19 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // handle whether we're allowing any, approved or specific ones if(! $x) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } // They are in your address book, but haven't been approved if($channel_perm & PERMS_PENDING && (! intval($x[0]['abook_pseudo']))) { - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } if(intval($x[0]['abook_pending'])) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } @@ -207,11 +207,11 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if($channel_perm & PERMS_CONTACTS) { // it was a fake abook entry, not really a connection if(array_key_exists('abook_pseudo',$x[0]) && intval($x[0]['abook_pseudo'])) { - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } - $ret[$perm_name] = true; + $ret[$perm_name] = 1; continue; } @@ -221,7 +221,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ if($abperms) { foreach($abperms as $ab) { if(($ab['cat'] == 'my_perms') && ($ab['k'] == $perm_name)) { - $ret[$perm_name] = (intval($ab['v']) ? true : false); + $ret[$perm_name] = (intval($ab['v']) ? 1 : 0); break; } } @@ -231,7 +231,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ // No permissions allowed. - $ret[$perm_name] = false; + $ret[$perm_name] = 0; continue; } diff --git a/include/selectors.php b/include/selectors.php index 71e2a387d..d58ef1085 100644 --- a/include/selectors.php +++ b/include/selectors.php @@ -15,7 +15,7 @@ function contact_profile_assign($current) { $select = [ 'profile_assign', - t('Profile to assign new connections'), + t('Select a profile to assign to this contact'), $current, '', $options @@ -70,7 +70,7 @@ function gender_selector($current="",$suffix="") { } $o .= ''; return $o; -} +} function gender_selector_min($current="",$suffix="") { $o = ''; @@ -87,7 +87,7 @@ function gender_selector_min($current="",$suffix="") { } $o .= ''; return $o; -} +} @@ -107,7 +107,7 @@ function sexpref_selector($current="",$suffix="") { } $o .= ''; return $o; -} +} function sexpref_selector_min($current="",$suffix="") { @@ -125,7 +125,7 @@ function sexpref_selector_min($current="",$suffix="") { } $o .= ''; return $o; -} +} @@ -144,7 +144,7 @@ function marital_selector($current="",$suffix="") { } $o .= ''; return $o; -} +} function marital_selector_min($current="",$suffix="") { $o = ''; @@ -161,5 +161,5 @@ function marital_selector_min($current="",$suffix="") { } $o .= ''; return $o; -} +} diff --git a/include/text.php b/include/text.php index d46c089b5..b2b3fce6e 100644 --- a/include/text.php +++ b/include/text.php @@ -12,6 +12,7 @@ use Ramsey\Uuid\Exception\UnableToBuildUuidException; use Zotlabs\Lib\Crypto; use Zotlabs\Lib\SvgSanitizer; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\AccessList; require_once("include/bbcode.php"); @@ -1753,6 +1754,7 @@ function prepare_body(&$item,$attach = false,$opts = false) { } } + $poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],[ ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE ])) ? format_poll($item, $s, $opts) : false); if ($poll) { $s = $poll; @@ -1854,11 +1856,16 @@ function format_poll($item,$s,$opts) { return EMPTY_STR; } - $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR),$item); + $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR), $item); + + $activated = ((local_channel() && local_channel() == $item['uid'] && get_observer_hash() !== $item['owner_xchan']) ? true : false); + $output = $s; + + if (strpos($item['body'], '[/share]') !== false) { + $output = substr($output, 0, -12); + } - //logger('format_poll: ' . print_r($item,true)); - $activated = ((local_channel() && local_channel() == $item['uid']) ? true : false); - $output = $s . EOL. EOL; + $output .= EOL . EOL; if ($act['type'] === 'Question') { if ($activated and $commentable) { @@ -1884,6 +1891,12 @@ function format_poll($item,$s,$opts) { } } if (array_key_exists('oneOf',$act) && is_array($act['oneOf'])) { + $totalResponses = 0; + foreach ($act['oneOf'] as $poll) { + if (array_path_exists('replies/totalItems',$poll)) { + $totalResponses += intval($poll['replies']['totalItems']); + } + } foreach ($act['oneOf'] as $poll) { if (array_key_exists('name',$poll) && $poll['name']) { $text = html2plain(purify_html($poll['name']),256); @@ -1894,29 +1907,48 @@ function format_poll($item,$s,$opts) { $total = 0; } if ($activated && $commentable) { - $output .= ' ' . $text . '' . ' (' . $total . ')' . EOL; + $output .= '  ' . $text . '' . EOL; + $output .= '
'; + $output .= '
'; + $output .= '
'; + $output .= '
' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . ' | ' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '
'; + $output .= EOL; } + else { - $output .= '( ) ' . $text . ' (' . $total . ')' . EOL; + $output .= '  ' . $text . '' . EOL; + $output .= '
'; + $output .= '
'; + $output .= '
'; + $output .= '
' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . ' | ' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '
'; + $output .= EOL; } } } } + + $message = (($totalResponses) ? sprintf(tt('%d Vote in total', '%d Votes in total', $totalResponses, 'noun'), $totalResponses) . EOL : ''); + if ($item['comments_closed'] > NULL_DATE) { $t = datetime_convert('UTC',date_default_timezone_get(), $item['comments_closed'], 'Y-m-d H:i'); $closed = ((datetime_convert() > $item['comments_closed']) ? true : false); if ($closed) { - $message = t('Poll has ended.'); + $message .= t('Poll has ended'); } else { - $message = sprintf(t('Poll ends: %s'),$t); + $message .= sprintf(t('Poll ends in %s'), ''); } - $output .= EOL . '
' . $message . '
'; } - if ($activated and $commentable) { - $output .= EOL . ''. ''; + + $output .= '
' . $message . '
'; + + if ($activated && $commentable && !$closed) { + $output .= ''. ''; } + if (strpos($item['body'], '[/share]') !== false) { + $output .= ''; + } } return $output; } @@ -2989,7 +3021,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) // weird - as all the other tags are linked to something. if(local_channel() && local_channel() == $profile_uid) { - $grp = group_byname($profile_uid,$name); + $grp = AccessList::byname($profile_uid,$name); if($grp) { $g = q("select hash from pgrp where id = %d and visible = 1 limit 1", @@ -3692,6 +3724,13 @@ function get_forum_channels($uid) { if(! $uid) return; + $r = q("select abook_id, xchan_pubforum, xchan_hash, xchan_network, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 and abook_self = 0 and xchan_pubforum = 1 order by xchan_name", + intval($uid) + ); + + +/* + if(isset(App::$data['forum_channels'])) return App::$data['forum_channels']; @@ -3763,6 +3802,7 @@ function get_forum_channels($uid) { } App::$data['forum_channels'] = $r; +*/ return $r; diff --git a/tests/unit/Access/PermissionLimitsTest.php b/tests/unit/Access/PermissionLimitsTest.php index 57ad42a19..0a90d11df 100644 --- a/tests/unit/Access/PermissionLimitsTest.php +++ b/tests/unit/Access/PermissionLimitsTest.php @@ -45,8 +45,8 @@ class PermissionLimitsTest extends UnitTestCase { * @uses ::call_hooks */ public function testStd_Limits() { - // There are 18 default perms - $permsCount = 18; + // There are 17 default perms + $permsCount = 17; // Create a stub for global function t() with expectation $t = $this->getFunctionMock('Zotlabs\Access', 't'); @@ -69,10 +69,9 @@ class PermissionLimitsTest extends UnitTestCase { $this->assertEquals(PERMS_SPECIFIC, $stdlimits['post_comments']); $this->assertEquals(PERMS_SPECIFIC, $stdlimits['post_mail']); $this->assertEquals(PERMS_SPECIFIC, $stdlimits['post_like']); - $this->assertEquals(PERMS_SPECIFIC, $stdlimits['tag_deliver']); $this->assertEquals(PERMS_SPECIFIC, $stdlimits['chat']); $this->assertEquals(PERMS_SPECIFIC, $stdlimits['republish']); $this->assertEquals(PERMS_SPECIFIC, $stdlimits['delegate']); } -} \ No newline at end of file +} diff --git a/tests/unit/Access/PermissionRolesTest.php b/tests/unit/Access/PermissionRolesTest.php index dd55eb6e2..3d3cbbae5 100644 --- a/tests/unit/Access/PermissionRolesTest.php +++ b/tests/unit/Access/PermissionRolesTest.php @@ -40,7 +40,7 @@ class PermissionRolesTest extends UnitTestCase { use PHPMock; public function testVersion() { - $expectedVersion = 2; + $expectedVersion = 3; $this->assertEquals($expectedVersion, PermissionRoles::version()); @@ -58,23 +58,12 @@ class PermissionRolesTest extends UnitTestCase { } ); - $roles = PermissionRoles::roles(); + $roles = PermissionRoles::channel_roles(); $r = new PermissionRoles(); - $this->assertEquals($roles, $r->roles()); + $this->assertEquals($roles, $r->channel_roles()); - $socialNetworking = [ - 'social_federation' => 'Social - Federation', - 'social' => 'Social - Mostly Public', - 'social_restricted' => 'Social - Restricted', - 'social_private' => 'Social - Private' - ]; + $this->assertCount(4, $roles, 'There should be 4 channel roles.'); - Assert::assertArraySubset(['Social Networking' => $socialNetworking], $roles); - $this->assertEquals($socialNetworking, $roles['Social Networking']); - - $this->assertCount(5, $roles, 'There should be 5 permission groups.'); - - $this->assertCount(1, $roles['Other'], "In the 'Other' group should be just one permission role"); } @@ -88,12 +77,9 @@ class PermissionRolesTest extends UnitTestCase { $t = $this->getFunctionMock('Zotlabs\Access', 't'); $t = $this->getFunctionMock('Zotlabs\Access', 'get_config'); - $rp_social = PermissionRoles::role_perms('social'); - $this->assertEquals('social', $rp_social['role']); - + $rp_social = PermissionRoles::role_perms('personal'); + $this->assertEquals('personal', $rp_social['role']); - $rp_custom = PermissionRoles::role_perms('custom'); - $this->assertEquals(['role' => 'custom'], $rp_custom); $rp_nonexistent = PermissionRoles::role_perms('nonexistent'); $this->assertEquals(['role' => 'nonexistent'], $rp_nonexistent); diff --git a/tests/unit/Access/PermissionsTest.php b/tests/unit/Access/PermissionsTest.php index 40724fff8..3ab567ad0 100644 --- a/tests/unit/Access/PermissionsTest.php +++ b/tests/unit/Access/PermissionsTest.php @@ -37,7 +37,7 @@ class PermissionsTest extends UnitTestCase { use PHPMock; public function testVersion() { - $expectedVersion = 2; + $expectedVersion = 3; // static call $this->assertEquals($expectedVersion, Permissions::version()); @@ -60,8 +60,8 @@ class PermissionsTest extends UnitTestCase { * @uses ::call_hooks */ public function testPerms() { - // There are 18 default perms - $permsCount = 18; + // There are 17 default perms + $permsCount = 17; // Create a stub for global function t() with expectation $t = $this->getFunctionMock('Zotlabs\Access', 't'); @@ -94,8 +94,8 @@ class PermissionsTest extends UnitTestCase { * @uses ::call_hooks */ public function testPermsFilter() { - // There are 18 default perms - $permsCount = 18; + // There are 17 default perms + $permsCount = 17; // Create a stub for global function t() with expectation $t = $this->getFunctionMock('Zotlabs\Access', 't'); @@ -154,7 +154,6 @@ class PermissionsTest extends UnitTestCase { 'post_comments' => 0, 'post_mail' => 0, 'post_like' => 0, - 'tag_deliver' => 0, 'chat' => 0, 'republish' => 0, 'delegate' => 0 @@ -177,7 +176,6 @@ class PermissionsTest extends UnitTestCase { 'post_comments' => 0, 'post_mail' => 0, 'post_like' => 0, - 'tag_deliver' => 0, 'chat' => 0, 'republish' => 0, 'delegate' => 0 @@ -200,7 +198,6 @@ class PermissionsTest extends UnitTestCase { 'post_comments' => 0, 'post_mail' => 0, 'post_like' => 0, - 'tag_deliver' => 0, 'chat' => 0, 'republish' => 0, 'delegate' => 0 @@ -234,7 +231,6 @@ class PermissionsTest extends UnitTestCase { 'post_comments' => 0, 'post_mail' => 0, 'post_like' => 0, - 'tag_deliver' => 0, 'chat' => 0, 'republish' => 0, 'delegate' => 0 diff --git a/view/css/mod_connections.css b/view/css/mod_connections.css index 4c26193b4..6a83367b8 100644 --- a/view/css/mod_connections.css +++ b/view/css/mod_connections.css @@ -1,17 +1,8 @@ +#contacts-follow-form, #contacts-search-form { display: none; } -.section-subtitle-wrapper .btn-xs { - margin-top: -2px; -} - -.contact-search { - height: 22px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; -} - .directory-photo-img.archived { opacity: 0.3; filter:alpha(opacity=30); @@ -39,7 +30,8 @@ } .contact-photo-wrapper .oneway-overlay { - margin-top: -25px; - margin-left: 53px; - font-size: 20px; + margin-top: -18px; + margin-left: 62px; + font-size: 1.2rem; + display: inherit; /* this is required for chromium */ } diff --git a/view/css/widgets.css b/view/css/widgets.css index df77940dd..0a091272c 100644 --- a/view/css/widgets.css +++ b/view/css/widgets.css @@ -244,9 +244,8 @@ a.wikilist { /* contact block */ .contact-block-div .oneway-overlay { font-size: .9rem; - margin-left: -1.2rem; - margin-top: 2rem; - opacity: 0.8; + margin-left: -1rem; + margin-top: 1.9rem; } #cid-filter-wrapper { diff --git a/view/js/main.js b/view/js/main.js index 0e16809e4..f4f641e33 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -525,11 +525,14 @@ function showHideComments(id) { } } -function openClose(theID) { - if(document.getElementById(theID).style.display == "block") { +function openClose(theID, display) { + if (typeof display == typeof undefined) + display = 'block'; + + if(document.getElementById(theID).style.display == display) { document.getElementById(theID).style.display = "none"; } else { - document.getElementById(theID).style.display = "block"; + document.getElementById(theID).style.display = display; } } @@ -541,9 +544,11 @@ function openCloseTR(theID) { } } -function closeOpen(theID) { +function closeOpen(theID, display) { + if (typeof display == typeof undefined) + display = 'block'; if(document.getElementById(theID).style.display == "none") { - document.getElementById(theID).style.display = "block"; + document.getElementById(theID).style.display = display; } else { document.getElementById(theID).style.display = "none"; } diff --git a/view/js/mod_connections.js b/view/js/mod_connections.js index db18e078d..848e9ed9f 100644 --- a/view/js/mod_connections.js +++ b/view/js/mod_connections.js @@ -1,5 +1,5 @@ $(document).ready(function() { $("#contacts-search").contact_autocomplete(baseurl + '/acl', 'a', true); $(".autotime").timeago(); -}); +}); diff --git a/view/pdl/mod_chat.pdl b/view/pdl/mod_chat.pdl index 808ba3d5a..8a79b4b12 100644 --- a/view/pdl/mod_chat.pdl +++ b/view/pdl/mod_chat.pdl @@ -1,5 +1,5 @@ [region=aside] -[widget=vcard][/widget] +[widget=profile][/widget] [widget=chatroom_list][/widget] [widget=bookmarkedchats][/widget] [widget=suggestedchats][/widget] diff --git a/view/pdl/mod_connections.pdl b/view/pdl/mod_connections.pdl index b777cada5..3c3dfd313 100644 --- a/view/pdl/mod_connections.pdl +++ b/view/pdl/mod_connections.pdl @@ -1,7 +1,4 @@ [region=aside] -[widget=follow][/widget] -[widget=collections][var=mode][connections[/arg][/widget] -[widget=suggestions][/widget] [widget=findpeople][/widget] [/region] [region=right_aside] diff --git a/view/pdl/mod_connedit.pdl b/view/pdl/mod_connedit.pdl index 4bdadb5e8..fa2f2969b 100644 --- a/view/pdl/mod_connedit.pdl +++ b/view/pdl/mod_connedit.pdl @@ -1,8 +1,6 @@ [region=aside] [widget=vcard][/widget] [widget=collections][var=mode]abook[/var][/widget] -[widget=suggestions][/widget] -[widget=findpeople][/widget] [/region] [region=right_aside] [widget=notifications][/widget] diff --git a/view/pdl/mod_import_items.pdl b/view/pdl/mod_import_items.pdl new file mode 100644 index 000000000..e657fa88b --- /dev/null +++ b/view/pdl/mod_import_items.pdl @@ -0,0 +1,3 @@ +[region=right_aside] +[widget=notifications][/widget] +[/region] diff --git a/view/pdl/mod_permcats.pdl b/view/pdl/mod_permcats.pdl new file mode 100644 index 000000000..bc6c89920 --- /dev/null +++ b/view/pdl/mod_permcats.pdl @@ -0,0 +1,7 @@ +[region=aside] +[widget=permcats][/widget] +[/region] +[region=right_aside] +[widget=notifications][/widget] +[widget=newmember][/widget] +[/region] diff --git a/view/pdl/mod_profperm.pdl b/view/pdl/mod_profperm.pdl index 7e15fc869..d7e5d29f3 100644 --- a/view/pdl/mod_profperm.pdl +++ b/view/pdl/mod_profperm.pdl @@ -1,5 +1,5 @@ [region=aside] -[widget=fullprofile][/widget] +[widget=profile][/widget] [/region] [region=right_aside] [widget=notifications][/widget] diff --git a/view/pdl/mod_viewconnections.pdl b/view/pdl/mod_viewconnections.pdl index 7e15fc869..d7e5d29f3 100644 --- a/view/pdl/mod_viewconnections.pdl +++ b/view/pdl/mod_viewconnections.pdl @@ -1,5 +1,5 @@ [region=aside] -[widget=fullprofile][/widget] +[widget=profile][/widget] [/region] [region=right_aside] [widget=notifications][/widget] diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index ac5b6a80a..542940404 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -418,11 +418,6 @@ footer { filter:alpha(opacity=100); } -#profile-photo-wrapper img { - width: 100%; - height: 100%; -} - #hide-friends-yes-label, #hide-friends-no-label { margin-left: 125px; @@ -1223,24 +1218,24 @@ img.mail-conv-sender-photo { } .menu-img-3 { - width: 3.3em; - height: 3.3em; + width: 2.7rem; + height: 2.7rem; margin-right: 5px; border-radius: $radius; float: left; } .menu-img-2 { - height: 2.2em; - width: 2.2em; + height: 1.8rem; + width: 1.8rem; margin-right: 5px; border-radius: $radius; float: left; } .menu-img-1 { - height: 1.28571429em; - width: 1.28571429em; + height: 1.1rem; + width: 1.1rem; border-radius: $radius; } @@ -1784,7 +1779,7 @@ dl.bb-dl > dd > li { .oneway-overlay { position: absolute; - text-shadow: -2px 0 1px #fff, 0 2px 1px#fff, 2px 0 1px #fff, 0 -2px 1px #fff; + text-shadow: -1px 0 1px #fff, 0 1px 1px#fff, 1px 0 1px #fff, 0 -1px 1px #fff; } .cover-photo-review { diff --git a/view/theme/redbasic/schema/Focus-Boxy.css b/view/theme/redbasic/schema/Focus-Boxy.css index b9b259796..90fd51b02 100644 --- a/view/theme/redbasic/schema/Focus-Boxy.css +++ b/view/theme/redbasic/schema/Focus-Boxy.css @@ -3,13 +3,31 @@ } .wall-item-content-wrapper.comment { - border-bottom: 1px solid #dee2e6; + border-bottom: 1px solid rgba(0,0,0,.125); } .widget { - border: 1px solid #dee2e6; + border: 1px solid rgba(0,0,0,.125); } #note-text { border: 1px solid transparent; } + +.vcard-card { + border: 1px solid rgba(0,0,0,.125); + border-bottom: 0; +} + +.vcard-card .card { + border-top: 0; + border-right: 0; + border-left: 0; +} + +.vcard-card .vcard { + border: 1px solid rgba(0,0,0,.125); + border-top: 0; + border-right: 0; + border-left: 0; +} diff --git a/view/tpl/abook_edit.tpl b/view/tpl/abook_edit.tpl index 686b40a54..28631ed68 100644 --- a/view/tpl/abook_edit.tpl +++ b/view/tpl/abook_edit.tpl @@ -24,6 +24,7 @@ {{if $abook_prev || $abook_next}}
+ {{if $sections}}
+ {{/if}}
{{/if}} @@ -40,6 +42,65 @@

{{$header}}

+
+ + + + +
+  {{$permcat_new}} + {{include file="field_select.tpl" field=$permcat}} + + + +
+ {{if $notself}} {{foreach $tools as $tool}} {{if $tool.info}} @@ -73,33 +134,9 @@
{{/if}} - - - - -
{{if $notself}} - {{if $is_pending}} -
- -
-
- {{include file="field_checkbox.tpl" field=$unapproved}} -
- -
-
-
-
- {{/if}} {{if ! $is_pending}}
@@ -438,85 +475,6 @@ {{/if}} - {{if $rating}} -
- -
-
-
- {{$rating_info}} -
-
{{$lbl_rating_label}}
- {{$rating}} - {{include file="field_textarea.tpl" field=$rating_text}} - -
- -
-
-
-
- {{/if}} - - {{/if}} - - {{if ! $is_pending}} -
- {{if $notself}} - - {{/if}} -
-
-
- {{if $notself}}{{$permnote}}{{/if}} - {{if $self}}{{$permnote_self}}{{/if}} -
- - {{if $permcat_enable}} -  {{$permcat_new}} - {{include file="field_select.tpl" field=$permcat}} - {{/if}} - - - - - {{if $notself}} - - {{/if}} - - - {{foreach $perms as $prm}} - {{include file="field_acheckbox.tpl" field=$prm}} - {{/foreach}} -
{{$them}}{{$me}}
- - {{if $self}} -
- - {{include file="field_checkbox.tpl" field=$autoperms}} -
- {{/if}} - -
- -
-
-
-
{{/if}}
diff --git a/view/tpl/admin_site.tpl b/view/tpl/admin_site.tpl index 6882c3b8a..fa942baff 100644 --- a/view/tpl/admin_site.tpl +++ b/view/tpl/admin_site.tpl @@ -31,7 +31,7 @@

{{$registration}}

{{include file="field_input.tpl" field=$register_text}} - {{include file="field_select_grouped.tpl" field=$role}} + {{include file="field_select.tpl" field=$role}} {{include file="field_select.tpl" field=$register_policy}} {{** include file="field_checkbox.tpl" field=$register_wo_email **}} {{include file="register_duty.tpl" field=$register_duty}} diff --git a/view/tpl/connection_template.tpl b/view/tpl/connection_template.tpl index e7ab559cb..5c1542111 100644 --- a/view/tpl/connection_template.tpl +++ b/view/tpl/connection_template.tpl @@ -1,23 +1,12 @@
- {{if $contact.approve && $contact.ignore}} -
- - - {{$contact.ignore}} - - {{/if}} - {{if $contact.connect}} - {{$contact.connect}} - {{/if}} - {{$contact.delete}} - {{$contact.edit}} - {{if $contact.approve}} -
- {{/if}} + {{$contact.role}} +
-

{{if $contact.public_forum}} {{/if}}{{$contact.name}}{{if $contact.phone}} {{/if}}

+

{{if $contact.public_forum}} {{/if}}{{$contact.name}}{{if $contact.phone}} {{/if}}

diff --git a/view/tpl/connections.tpl b/view/tpl/connections.tpl index 1719a6522..5fec38a84 100644 --- a/view/tpl/connections.tpl +++ b/view/tpl/connections.tpl @@ -1,7 +1,10 @@
-
+
- + +
+
+
+
+ {{if $abook_usage_message}} +
+ {{$abook_usage_message}} +
+ {{/if}} +
+
+ +
@@ -34,3 +50,5 @@
+{{include file="contact_edit_modal.tpl"}} + diff --git a/view/tpl/connstatus.tpl b/view/tpl/connstatus.tpl index 869345682..30f450820 100644 --- a/view/tpl/connstatus.tpl +++ b/view/tpl/connstatus.tpl @@ -1 +1 @@ - + diff --git a/view/tpl/contact_edit.tpl b/view/tpl/contact_edit.tpl new file mode 100644 index 000000000..3c4ed2ffe --- /dev/null +++ b/view/tpl/contact_edit.tpl @@ -0,0 +1,133 @@ +
+
+
+ +
+
+ {{include file="field_select.tpl" field=$permcat}} + + +  {{$permcat_new}} + + + + + + + + + + + {{foreach $perms as $perm}} + + + + + + {{/foreach}} + + +
Permission{{$them}}{{$me}}
{{$perm.1}} + {{if $perm.2}} + + {{else}} + + {{/if}} + + {{if $perm.3}} + + {{else}} + + {{/if}} +
+
+
+
+ {{if $groups}} +
+ +
+
+ {{foreach $groups as $group}} + {{include file="field_checkbox.tpl" field=$group}} + {{/foreach}} + +  Privacy groups + +
+
+
+ {{/if}} + {{if $multiprofs}} +
+ +
+
+ {{$profile_select}} + +  Profiles + +
+
+
+ {{/if}} + {{if $slide}} +
+ +
+
+
+ {{$slide}} + +
+
+
+ {{/if}} + {{if $connfilter}} +
+ +
+
+ {{include file="field_textarea.tpl" field=$incl}} + {{include file="field_textarea.tpl" field=$excl}} +
+
+
+ {{else}} + + + {{/if}} +
+
diff --git a/view/tpl/contact_edit_header.tpl b/view/tpl/contact_edit_header.tpl new file mode 100644 index 000000000..997d294bd --- /dev/null +++ b/view/tpl/contact_edit_header.tpl @@ -0,0 +1,9 @@ + +
+
{{if $is_group}} {{/if}}{{$name}}
+
{{$addr}}
+
diff --git a/view/tpl/contact_edit_modal.tpl b/view/tpl/contact_edit_modal.tpl new file mode 100644 index 000000000..be290c403 --- /dev/null +++ b/view/tpl/contact_edit_modal.tpl @@ -0,0 +1,152 @@ + + diff --git a/view/tpl/contact_edit_tools.tpl b/view/tpl/contact_edit_tools.tpl new file mode 100644 index 000000000..565b9df86 --- /dev/null +++ b/view/tpl/contact_edit_tools.tpl @@ -0,0 +1,14 @@ + + diff --git a/view/tpl/conv_frame.tpl b/view/tpl/conv_frame.tpl index c28bb732a..4237c671b 100644 --- a/view/tpl/conv_frame.tpl +++ b/view/tpl/conv_frame.tpl @@ -18,3 +18,4 @@
+{{include file="contact_edit_modal.tpl"}} diff --git a/view/tpl/conv_item.tpl b/view/tpl/conv_item.tpl index 7c3505410..0a07319c8 100644 --- a/view/tpl/conv_item.tpl +++ b/view/tpl/conv_item.tpl @@ -40,7 +40,7 @@ {{/if}} @@ -48,7 +48,7 @@
{{if $item.lock}} {{/if}} diff --git a/view/tpl/conv_list.tpl b/view/tpl/conv_list.tpl index a20a6de8d..b4071ba16 100644 --- a/view/tpl/conv_list.tpl +++ b/view/tpl/conv_list.tpl @@ -43,7 +43,7 @@
{{if $item.lock}} {{/if}} diff --git a/view/tpl/conversation.tpl b/view/tpl/conversation.tpl index 82c7be922..6729cf55c 100644 --- a/view/tpl/conversation.tpl +++ b/view/tpl/conversation.tpl @@ -9,10 +9,10 @@ {{/if}} - + {{include file="{{$item.template}}"}} - - + + {{/foreach}}
{{/foreach}} diff --git a/view/tpl/field_acheckbox.tpl b/view/tpl/field_acheckbox.tpl index 4c8b62f36..44f65fefd 100644 --- a/view/tpl/field_acheckbox.tpl +++ b/view/tpl/field_acheckbox.tpl @@ -1,24 +1,31 @@ - + -
- {{$field.6}} + + {{$field.6}} - {{if $notself}} - - {{if $field.2 == 1}}{{/if}} - {{if $field.2 == 0}}{{/if}} - - {{/if}} - - {{if $self || !$field.5 }} - - {{/if}} - {{if $notself && $field.5}} - - {{if $field.3}}{{else}}{{/if}} + + {{if $field.5}} + + {{$inherited}} + {{if $field.7}} + + {{else}} + + {{/if}} + {{/if}} - {{if $field.5}}{{$inherited}}{{if $self}}{{if $field.7}} {{else}} {{/if}}{{/if}}{{/if}} + {{if $is_system_role}} + {{if $field.3}} + + {{else}} + + {{/if}} + {{else}} + + {{/if}} + + diff --git a/view/tpl/field_checkbox.tpl b/view/tpl/field_checkbox.tpl index a1ab42d5e..670bb7e29 100644 --- a/view/tpl/field_checkbox.tpl +++ b/view/tpl/field_checkbox.tpl @@ -1,6 +1,6 @@
-
+
{{$field.3}}
{{* diff --git a/view/tpl/group_edit.tpl b/view/tpl/group_edit.tpl index 5568179af..61203ab10 100644 --- a/view/tpl/group_edit.tpl +++ b/view/tpl/group_edit.tpl @@ -13,6 +13,8 @@ {{include file="field_input.tpl" field=$gname}} {{include file="field_checkbox.tpl" field=$public}} + {{include file="field_checkbox.tpl" field=$is_default_acl}} + {{include file="field_checkbox.tpl" field=$is_default_group}} {{$pgrp_extras}} {{$delete}} diff --git a/view/tpl/group_selection.tpl b/view/tpl/group_selection.tpl index a91658464..7db80e06f 100644 --- a/view/tpl/group_selection.tpl +++ b/view/tpl/group_selection.tpl @@ -1,8 +1,8 @@
- - + +
diff --git a/view/tpl/group_side.tpl b/view/tpl/group_side.tpl index 14f714ae9..979d20aa5 100644 --- a/view/tpl/group_side.tpl +++ b/view/tpl/group_side.tpl @@ -13,9 +13,11 @@
{{$group.text}} {{/foreach}} + {{if $createtext}} + {{/if}}
diff --git a/view/tpl/micropro_card.tpl b/view/tpl/micropro_card.tpl index 058bfc14c..40a7967c5 100644 --- a/view/tpl/micropro_card.tpl +++ b/view/tpl/micropro_card.tpl @@ -1,5 +1,5 @@ - {{if $perminfo}}{{include "connstatus.tpl"}}{{/if}} + {{if $perminfo}}{{include "connstatus.tpl"}}{{/if}} {{$name}} {{$addr}}
{{$network}}
diff --git a/view/tpl/new_channel.tpl b/view/tpl/new_channel.tpl index 8d72df55b..f11a4291f 100644 --- a/view/tpl/new_channel.tpl +++ b/view/tpl/new_channel.tpl @@ -18,17 +18,17 @@ {{if $default_role}} {{else}} - {{include file="field_select_grouped.tpl" field=$role}} + {{include file="field_select.tpl" field=$role}} {{/if}} - + {{include file="field_input.tpl" field=$name}} - + {{include file="field_input.tpl" field=$nickname}} - - + +
- +
diff --git a/view/tpl/notes.tpl b/view/tpl/notes.tpl index 902691fae..24c3ec53c 100644 --- a/view/tpl/notes.tpl +++ b/view/tpl/notes.tpl @@ -8,7 +8,7 @@ {{else}}
{{$strings.read}}
-

{{$banner}}

+

{{$strings.title}}

{{/if}}
{{$html}}
diff --git a/view/tpl/permcats.tpl b/view/tpl/permcats.tpl index 5b2d811d7..279903048 100644 --- a/view/tpl/permcats.tpl +++ b/view/tpl/permcats.tpl @@ -4,49 +4,37 @@
- -
- - {{include file="field_input.tpl" field=$name}} + + -
- -
-
+ {{if $is_system_role}} + + + {{/if}} -
- -
-
-
- {{$permnote}} -
+ {{include file="field_input.tpl" field=$name}} + {{include file="field_checkbox.tpl" field=$default_role}} - - - - - {{foreach $perms as $prm}} - {{include file="field_acheckbox.tpl" field=$prm}} - {{/foreach}} -
{{$me}}
+ {{$group_select}} -
- -
+
+

+ {{$permlbl}} +

-
- {{if $permcats}} -
+
+ {{$permnote}} +
+ + {{foreach $perms as $prm}} + {{include file="field_acheckbox.tpl" field=$prm}} + {{/foreach}} +
+
+ +
+ {{**if $permcats}} {{foreach $permcats as $k => $v}} @@ -55,10 +43,8 @@ {{/foreach}}
-
- {{/if}} + {{/if**}} +
- -
diff --git a/view/tpl/privacy_groups.tpl b/view/tpl/privacy_groups.tpl index c06f5b0ca..0bbc998a1 100644 --- a/view/tpl/privacy_groups.tpl +++ b/view/tpl/privacy_groups.tpl @@ -8,6 +8,8 @@ {{include file="field_input.tpl" field=$gname}} {{include file="field_checkbox.tpl" field=$public}} + {{include file="field_checkbox.tpl" field=$is_default_acl}} + {{include file="field_checkbox.tpl" field=$is_default_group}} {{$pgrp_extras}} diff --git a/view/tpl/profile_edit.tpl b/view/tpl/profile_edit.tpl index 95346b3a8..3f5814c4a 100644 --- a/view/tpl/profile_edit.tpl +++ b/view/tpl/profile_edit.tpl @@ -50,7 +50,7 @@ @@ -84,7 +84,17 @@ {{$dob}} {{/if}} + {{$profile_in_dir}} + + {{$suggestme}} + + {{if $show_presence}} + {{include file="field_checkbox.tpl" field=$show_presence}} + {{/if}} + + {{if $hide_friends}} {{include file="field_checkbox.tpl" field=$hide_friends}} + {{/if}}
diff --git a/view/tpl/profile_vcard.tpl b/view/tpl/profile_vcard.tpl index 8ebc9a311..9002d3742 100644 --- a/view/tpl/profile_vcard.tpl +++ b/view/tpl/profile_vcard.tpl @@ -1,5 +1,5 @@ -
-
+
+
{{if $editmenu}} @@ -49,10 +49,10 @@ {{if $details}}
{{if $profile.pdesc}} -
{{$profile.pdesc}}
+
{{$profile.pdesc}}
{{/if}} {{if $location}} -
+
{{$location}}
{{if $profile.address}} @@ -72,25 +72,25 @@
{{/if}} {{if $hometown}} -
+
{{$hometown}}
{{$profile.hometown}}
{{/if}} {{if $gender}} -
+
{{$gender}}
{{if $profile.gender_icon}} {{/if}}{{$profile.gender}}
{{/if}} {{if $marital}} -
+
 {{$marital}}
{{$profile.marital}}
{{/if}} {{if $homepage}} -
+
{{$homepage}}
{{$profile.homepage}}
diff --git a/view/tpl/search_item.tpl b/view/tpl/search_item.tpl index ee89973a8..f3d0a8d03 100644 --- a/view/tpl/search_item.tpl +++ b/view/tpl/search_item.tpl @@ -36,7 +36,7 @@
{{if $item.lock}} {{/if}}
diff --git a/view/tpl/settings.tpl b/view/tpl/settings.tpl index 353da9c2b..9b23d7d82 100644 --- a/view/tpl/settings.tpl +++ b/view/tpl/settings.tpl @@ -18,13 +18,14 @@
- {{include file="field_input.tpl" field=$username}} + {{include file="field_select.tpl" field=$role}} {{include file="field_select_grouped.tpl" field=$timezone}} {{include file="field_input.tpl" field=$defloc}} {{include file="field_checkbox.tpl" field=$allowloc}} {{include file="field_checkbox.tpl" field=$adult}} {{include file="field_input.tpl" field=$photo_path}} {{include file="field_input.tpl" field=$attach_path}} + {{include file="field_input.tpl" field=$expire}} {{if $basic_addon}} {{$basic_addon}} {{/if}} @@ -34,66 +35,6 @@
-
- -
-
- {{include file="field_select_grouped.tpl" field=$role}} - {{$autoperms}} -
-
- -
- - -
- -
- {{$group_select}} - {{include file="field_checkbox.tpl" field=$hide_presence}} - {{$profile_in_dir}} -
-
- {{$suggestme}} - {{include file="field_checkbox.tpl" field=$blocktags}} - {{include file="field_input.tpl" field=$expire}} -
- {{if $permcat_enable}} - {{include file="field_select.tpl" field=$defpermcat}} - {{/if}} - - {{if $sec_addon}} - {{$sec_addon}} - {{/if}} -
- -
-
-
-