diff options
Diffstat (limited to 'Zotlabs')
95 files changed, 1661 insertions, 484 deletions
diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php index 29efcf475..1124ead54 100644 --- a/Zotlabs/Daemon/Gprobe.php +++ b/Zotlabs/Daemon/Gprobe.php @@ -15,19 +15,31 @@ class Gprobe { return; $url = hex2bin($argv[1]); + $is_webbie = false; + $r = null; - if (!strpos($url, '@')) - return; + if (filter_var($url, FILTER_VALIDATE_EMAIL)) { + $is_webbie = true; - $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($url) - ); + $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($url) + ); + } + elseif (filter_var($url, FILTER_VALIDATE_URL)) { + $r = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($url) + ); + } if (!$r) { - $href = Webfinger::zot_url(punify($url)); - if ($href) { - $zf = Zotfinger::exec($href, null); + if ($is_webbie) { + $url = Webfinger::zot_url(punify($url)); } + + if ($url) { + $zf = Zotfinger::exec($url, null); + } + if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { Libzot::import_xchan($zf['data']); } diff --git a/Zotlabs/Lib/AccessList.php b/Zotlabs/Lib/AccessList.php index 026148c9f..f4b762eaa 100644 --- a/Zotlabs/Lib/AccessList.php +++ b/Zotlabs/Lib/AccessList.php @@ -311,55 +311,6 @@ class AccessList { return $o; } -/* deprecated - 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", - intval($_SESSION['uid']) - ); - $member_of = []; - 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' => "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), - ]; - } - } - - return replace_macros(get_markup_template('group_side.tpl'), [ - '$title' => t('Privacy Groups'), - '$edittext' => t('Edit group'), - '$createtext' => t('Create new group'), - '$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''), - '$groups' => $groups, - '$add' => t('Add'), - ]); - - } -*/ - static function expand($g) { if (!(is_array($g) && count($g))) { return []; diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index e51922c86..0c25605e7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -501,7 +501,7 @@ class Activity { $ret['attributedTo'] = $i['author']['xchan_url']; - if ($i['id'] != $i['parent']) { + if ($i['mid'] !== $i['parent_mid']) { $ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); } @@ -608,10 +608,10 @@ class Activity { $ptr = [$ptr]; } foreach ($ptr as $t) { - if (!array_key_exists('type', $t)) + if (is_array($t) && !array_key_exists('type', $t)) $t['type'] = 'Hashtag'; - if (array_key_exists('href', $t) && array_key_exists('name', $t)) { + if (is_array($t) && array_key_exists('href', $t) && array_key_exists('name', $t)) { switch ($t['type']) { case 'Hashtag': $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])]; @@ -875,7 +875,7 @@ class Activity { } } - if ($i['id'] != $i['parent']) { + if ($i['mid'] !== $i['parent_mid']) { $reply = true; // inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.), @@ -1154,9 +1154,10 @@ class Activity { $ret['url'] = $p['xchan_url']; $ret['publicKey'] = [ - 'id' => $p['xchan_url'], - 'owner' => $p['xchan_url'], - 'publicKeyPem' => $p['xchan_pubkey'] + 'id' => $p['xchan_url'], + 'owner' => $p['xchan_url'], + 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'publicKeyPem' => $p['xchan_pubkey'] ]; if ($c) { @@ -1599,6 +1600,25 @@ class Activity { return; } + public static function drop($channel, $observer, $act) { + $r = q( + "select * from item where mid = '%s' and uid = %d limit 1", + dbesc((is_array($act->obj)) ? $act->obj['id'] : $act->obj), + intval($channel['channel_id']) + ); + + if (!$r) { + return; + } + + if (in_array($observer, [$r[0]['author_xchan'], $r[0]['owner_xchan']])) { + drop_item($r[0]['id'], false); + } elseif (in_array($act->actor['id'], [$r[0]['author_xchan'], $r[0]['owner_xchan']])) { + drop_item($r[0]['id'], false); + } + } + + static function actor_store($url, $person_obj, $force = false) { if (!is_array($person_obj)) { @@ -1618,6 +1638,7 @@ class Activity { $ap_hubloc = null; $hublocs = self::get_actor_hublocs($url); + $has_zot_hubloc = false; if ($hublocs) { foreach ($hublocs as $hub) { @@ -1625,6 +1646,7 @@ class Activity { $ap_hubloc = $hub; } if ($hub['hubloc_network'] === 'zot6') { + $has_zot_hubloc = true; Libzot::update_cached_hubloc($hub); } } @@ -1648,16 +1670,18 @@ class Activity { return; } - $inbox = $person_obj['inbox']; + $inbox = $person_obj['inbox'] ?? null; - // invalid identity + // invalid AP identity if (!$inbox || strpos($inbox, z_root()) !== false) { return; } // store the actor record in XConfig - XConfig::Set($url, 'system', 'actor_record', $person_obj); + + // we already store this in Activity::fetch() + // XConfig::Set($url, 'system', 'actor_record', $person_obj); $name = $person_obj['name']; if (!$name) { @@ -1814,12 +1838,12 @@ class Activity { // Adding zot discovery urls to the actor record will cause federation to fail with the 20-30 projects which don't accept arrays in the url field. $actor_protocols = self::get_actor_protocols($person_obj); - if (in_array('zot6', $actor_protocols)) { + if (!$has_zot_hubloc && in_array('zot6', $actor_protocols)) { $zx = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6'", dbesc($url) ); - if (!$zx && $webfinger_addr) { - Master::Summon(['Gprobe', bin2hex($webfinger_addr)]); + if (!$zx) { + Master::Summon(['Gprobe', bin2hex($url)]); } } @@ -1922,11 +1946,6 @@ class Activity { } } - $abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($observer_hash), - intval($channel['channel_id']) - ); - $content = self::get_content($act->obj); if (!$content) { @@ -2004,15 +2023,23 @@ class Activity { } if ($channel['channel_system']) { - if (!MessageFilter::evaluate($s, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { + $incl = get_config('system','pubstream_incl'); + $excl = get_config('system','pubstream_excl'); + + if(($incl || $excl) && !MessageFilter::evaluate($s, $incl, $excl)) { logger('post is filtered'); return; } } + $abook = q("select * from abook where (abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", + dbesc($s['author_xchan']), + dbesc($s['owner_xchan']), + intval($channel['channel_id']) + ); if ($abook) { - if (!post_is_importable($s, $abook[0])) { + if (!post_is_importable($channel['channel_id'], $s, $abook)) { logger('post is filtered'); return; } @@ -2221,6 +2248,21 @@ class Activity { static function decode_note($act) { + $response_activity = false; + + $s = []; + + // These activities should have been handled separately in the Inbox module and should not be turned into posts + + if ( + in_array($act->type, ['Follow', 'Accept', 'Reject', 'Create', 'Update']) && + is_array($act->obj) && + array_key_exists('type', $act->obj) && + ($act->obj['type'] === 'Follow' || ActivityStreams::is_an_actor($act->obj['type'])) + ) { + return false; + } + // Within our family of projects, Follow/Unfollow of a thread is an internal activity which should not be transmitted, // hence if we receive it - ignore or reject it. // Unfollow is not defined by ActivityStreams, which prefers Undo->Follow. @@ -2230,22 +2272,31 @@ class Activity { return false; } - $response_activity = false; + if (!isset($act->actor['id'])) { + logger('No actor!'); + return false; + } - $s = []; + // ensure we store the original actor + self::actor_store($act->actor['id'], $act->actor); + + $s['owner_xchan'] = $act->actor['id']; + $s['author_xchan'] = $act->actor['id']; if (is_array($act->obj)) { $content = self::get_content($act->obj); } - $s['owner_xchan'] = $act->actor['id']; - $s['author_xchan'] = $act->actor['id']; + $s['mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); - // ensure we store the original actor - self::actor_store($act->actor['id'], $act->actor); + if (!$s['mid']) { + return false; + } + + // Friendica sends the diaspora guid in a nonstandard field via AP + // If no uuid is provided we will create an uuid v5 from the mid + $s['uuid'] = ((is_array($act->obj) && isset($act->obj['diaspora:guid'])) ? $act->obj['diaspora:guid'] : uuid_from_url($s['mid'])); - $s['mid'] = $act->obj['id']; - $s['uuid'] = $act->obj['diaspora:guid']; $s['parent_mid'] = $act->parent_id; if (array_key_exists('published', $act->data)) { @@ -2269,13 +2320,18 @@ class Activity { $s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']); } + if ($act->type === 'Invite' && is_array($act->obj) && array_key_exists('type', $act->obj) && $act->obj['type'] === 'Event') { + $s['mid'] = $s['parent_mid'] = $act->id; + } + if (ActivityStreams::is_response_activity($act->type)) { $response_activity = true; $s['mid'] = $act->id; - // $s['parent_mid'] = $act->obj['id']; - $s['uuid'] = $act->data['diaspora:guid']; + $s['uuid'] = ((is_array($act->data) && isset($act->data['diaspora:guid'])) ? $act->data['diaspora:guid'] : uuid_from_url($s['mid'])); + + $s['parent_mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); // over-ride the object timestamp with the activity @@ -2288,8 +2344,8 @@ class Activity { } $obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj)); - // ensure we store the original actor + // ensure we store the original actor self::actor_store($obj_actor['id'], $obj_actor); $mention = self::get_actor_bbmention($obj_actor['id']); @@ -2318,13 +2374,41 @@ class Activity { } if ($act->type === 'Announce') { - $content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); + $s['author_xchan'] = $obj_actor['id']; + $s['mid'] = $act->obj['id']; + $s['parent_mid'] = $act->obj['id']; } if ($act->type === 'emojiReaction') { $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); } } + $s['item_thread_top'] = 0; + $s['comment_policy'] = 'authenticated'; + + if ($s['mid'] === $s['parent_mid']) { + $s['item_thread_top'] = 1; + + // it is a parent node - decode the comment policy info if present + if (isset($act->obj['commentPolicy'])) { + $until = strpos($act->obj['commentPolicy'], 'until='); + if ($until !== false) { + $s['comments_closed'] = datetime_convert('UTC', 'UTC', substr($act->obj['commentPolicy'], $until + 6)); + if ($s['comments_closed'] < datetime_convert()) { + $s['nocomment'] = true; + } + } + + $remainder = substr($act->obj['commentPolicy'], 0, (($until) ? $until : strlen($act->obj['commentPolicy']))); + if ($remainder) { + $s['comment_policy'] = $remainder; + } + if (!(isset($item['comment_policy']) && strlen($item['comment_policy']))) { + $s['comment_policy'] = 'contacts'; + } + } + } + if (!array_key_exists('created', $s)) $s['created'] = datetime_convert(); @@ -2335,6 +2419,16 @@ class Activity { $s['summary'] = self::bb_content($content, 'summary'); $s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content')); + if (isset($act->obj['quoteUrl'])) { + $quote_bbcode = self::get_quote_bbcode($act->obj['quoteUrl']); + + if ($s['body']) { + $s['body'] .= "\r\n\r\n"; + } + + $s['body'] .= $quote_bbcode; + } + $s['verb'] = self::activity_decode_mapper($act->type); // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. @@ -2351,6 +2445,12 @@ class Activity { $s['obj_type'] = ACTIVITY_OBJ_COMMENT; } + $s['obj'] = $act->obj; + if (is_array($s['obj']) && array_path_exists('actor/id', $s['obj'])) { + $s['obj']['actor'] = $s['obj']['actor']['id']; + } + +/* $eventptr = null; if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') { @@ -2371,19 +2471,19 @@ class Activity { $s['obj']['asld'] = $eventptr; $s['obj']['type'] = ACTIVITY_OBJ_EVENT; $s['obj']['id'] = $eventptr['id']; - $s['obj']['title'] = $eventptr['name']; + $s['obj']['title'] = html2plain($eventptr['name']); if (strpos($act->obj['startTime'], 'Z')) $s['obj']['adjust'] = true; else - $s['obj']['adjust'] = false; + $s['obj']['adjust'] = true; $s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']); if ($act->obj['endTime']) $s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']); else $s['obj']['nofinish'] = true; - $s['obj']['description'] = $eventptr['content']; + $s['obj']['description'] = html2bbcode($eventptr['content']); if (array_path_exists('location/content', $eventptr)) $s['obj']['location'] = $eventptr['location']['content']; @@ -2392,6 +2492,7 @@ class Activity { else { $s['obj'] = $act->obj; } +*/ $generator = $act->get_property_obj('generator'); if ((!$generator) && (!$response_activity)) { @@ -2431,7 +2532,7 @@ class Activity { if (array_key_exists('type', $act->obj)) { if ($act->obj['type'] === 'Note' && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach'], $s['body']); + $s['body'] = self::bb_attach($s['attach'], $s['body']) . $s['body']; } if ($act->obj['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) { @@ -2459,31 +2560,57 @@ class Activity { 'video/webm' ]; - $mps = []; + $mps = []; + $poster = null; + $ptr = null; + + // try to find a poster to display on the video element + + if (array_key_exists('icon',$act->obj)) { + if (is_array($act->obj['icon'])) { + if (array_key_exists(0,$act->obj['icon'])) { + $ptr = $act->obj['icon']; + } + else { + $ptr = [ $act->obj['icon'] ]; + } + } + if ($ptr) { + foreach ($ptr as $foo) { + if (is_array($foo) && array_key_exists('type',$foo) && $foo['type'] === 'Image' && is_string($foo['url'])) { + $poster = $foo['url']; + } + } + } + } + + $tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]' ); $ptr = null; - if (array_key_exists('url', $act->obj)) { + if (array_key_exists('url',$act->obj)) { if (is_array($act->obj['url'])) { - if (array_key_exists(0, $act->obj['url'])) { + if (array_key_exists(0,$act->obj['url'])) { $ptr = $act->obj['url']; } else { - $ptr = [$act->obj['url']]; + $ptr = [ $act->obj['url'] ]; } - foreach ($ptr as $vurl) { - // peertube uses the non-standard element name 'mimeType' here - if (array_key_exists('mimeType', $vurl)) { - if (in_array($vurl['mimeType'], $vtypes)) { - if (!array_key_exists('width', $vurl)) { - $vurl['width'] = 0; - } - $mps[] = $vurl; + // handle peertube's weird url link tree if we find it here + // 0 => html link, 1 => application/x-mpegURL with 'tag' set to an array of actual media links + foreach ($ptr as $idex) { + if (is_array($idex) && array_key_exists('mediaType',$idex)) { + if ($idex['mediaType'] === 'application/x-mpegURL' && isset($idex['tag']) && is_array($idex['tag'])) { + $ptr = $idex['tag']; + break; } } - elseif (array_key_exists('mediaType', $vurl)) { + } + + foreach ($ptr as $vurl) { + if (array_key_exists('mediaType',$vurl)) { if (in_array($vurl['mediaType'], $vtypes)) { - if (!array_key_exists('width', $vurl)) { - $vurl['width'] = 0; + if (! array_key_exists('height',$vurl)) { + $vurl['height'] = 0; } $mps[] = $vurl; } @@ -2491,17 +2618,18 @@ class Activity { } } if ($mps) { - usort($mps, [__CLASS__, 'vid_sort']); + usort($mps,[ '\Zotlabs\Lib\Activity', 'vid_sort' ]); foreach ($mps as $m) { - if (intval($m['width']) < 500 && self::media_not_in_body($m['href'], $s['body'])) { - $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; + if (intval($m['height']) < 500 && Activity::media_not_in_body($m['href'],$s['body'])) { + $s['body'] = $tag . $m['href'] . '[/video]' . "\n\n" . $s['body']; break; } } } - elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { - $s['body'] .= "\n\n" . '[video]' . $act->obj['url'] . '[/video]'; + elseif (is_string($act->obj['url']) && Activity::media_not_in_body($act->obj['url'],$s['body'])) { + $s['body'] = $tag . $act->obj['url'] . '[/video]' . "\n\n" . $s['body']; } + } } @@ -2525,13 +2653,13 @@ class Activity { } foreach ($ptr as $vurl) { if (in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'], $s['body'])) { - $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; + $s['body'] = '[audio]' . $vurl['href'] . '[/audio]' . "\n\n" . $s['body']; break; } } } elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { - $s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]'; + $s['body'] = '[audio]' . $act->obj['url'] . '[/audio]' . "\n\n" . $s['body']; } } @@ -2606,7 +2734,6 @@ class Activity { } } - if (in_array($act->obj['type'], ['Note', 'Article', 'Page'])) { $ptr = null; @@ -2744,12 +2871,6 @@ class Activity { return; }*/ - // TODO: this his handled in pubcrawl atm. - // very unpleasant and imperfect way of determining a Mastodon DM - /*if ($act->raw_recips && array_key_exists('to',$act->raw_recips) && is_array($act->raw_recips['to']) && count($act->raw_recips['to']) === 1 && $act->raw_recips['to'][0] === channel_url($channel) && ! $act->raw_recips['cc']) { - $item['item_private'] = 2; - }*/ - if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { $is_child_node = true; } @@ -2914,19 +3035,23 @@ class Activity { return; if ($channel['channel_system']) { - if (!MessageFilter::evaluate($item, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { + $incl = get_config('system','pubstream_incl'); + $excl = get_config('system','pubstream_excl'); + + if(($incl || $excl) && !MessageFilter::evaluate($item, $incl, $excl)) { logger('post is filtered'); return; } } - $abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($observer_hash), + $abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", + dbesc($item['author_xchan']), + dbesc($item['owner_xchan']), intval($channel['channel_id']) ); if ($abook) { - if (!post_is_importable($item, $abook[0])) { + if (!post_is_importable($channel['channel_id'], $item, $abook)) { logger('post is filtered'); return; } @@ -2996,6 +3121,19 @@ class Activity { $item['thr_parent'] = $parent[0]['parent_mid']; } $item['parent_mid'] = $parent[0]['parent_mid']; + //$item['item_private'] = $parent[0]['item_private']; + + } + + // An ugly and imperfect way to recognise a mastodon direct message + if ( + $item['item_private'] === 1 && + !isset($act->raw_recips['cc']) && + is_array($act->raw_recips['to']) && + in_array(channel_url($channel), $act->raw_recips['to']) && + !in_array($act->actor['followers'], $act->raw_recips['to']) + ) { + $item['item_private'] = 2; } // TODO: not implemented @@ -3006,6 +3144,12 @@ class Activity { intval($item['uid']) ); if ($r) { + + // If we already have the item, dismiss its announce + if ($act->type === 'Announce') { + return; + } + if ($item['edited'] > $r[0]['edited']) { $item['id'] = $r[0]['id']; $x = item_store_update($item); @@ -3022,12 +3166,12 @@ class Activity { logger('topfetch', LOGGER_DEBUG); // if the thread owner is a connnection, we will already receive any additional comments to their posts // but if they are not we can try to fetch others in the background - $x = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash + $connected = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", intval($channel['channel_id']), dbesc($parent[0]['owner_xchan']) ); - if (!$x) { + if (!$connected) { // determine if the top-level post provides a replies collection if ($parent[0]['obj']) { $parent[0]['obj'] = json_decode($parent[0]['obj'], true); @@ -3279,6 +3423,7 @@ class Activity { } +/* this is deprecated and not used anymore static function announce_note($channel, $observer_hash, $act) { $s = []; @@ -3409,6 +3554,7 @@ class Activity { } } +*/ static function like_note($channel, $observer_hash, $act) { @@ -3629,7 +3775,49 @@ class Activity { $event['nofinish'] = true; } } +/* + $eventptr = null; + + if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') { + $eventptr = $act->obj['object']; + $s['mid'] = $s['parent_mid'] = $act->obj['id']; + } + + if ($act->obj['type'] === 'Event') { + if ($act->type === 'Invite') { + $s['mid'] = $s['parent_mid'] = $act->id; + } + $eventptr = $act->obj; + } + + if ($eventptr) { + + $s['obj'] = []; + $s['obj']['asld'] = $eventptr; + $s['obj']['type'] = ACTIVITY_OBJ_EVENT; + $s['obj']['id'] = $eventptr['id']; + $s['obj']['title'] = html2plain($eventptr['name']); + + if (strpos($act->obj['startTime'], 'Z')) + $s['obj']['adjust'] = true; + else + $s['obj']['adjust'] = true; + + $s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']); + if ($act->obj['endTime']) + $s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']); + else + $s['obj']['nofinish'] = true; + $s['obj']['description'] = html2bbcode($eventptr['content']); + if (array_path_exists('location/content', $eventptr)) + $s['obj']['location'] = $eventptr['location']['content']; + + } + else { + $s['obj'] = $act->obj; + } +*/ foreach (['name', 'summary', 'content'] as $a) { if (($x = self::get_textfield($act, $a)) !== false) { $content[$a] = $x; @@ -3786,7 +3974,7 @@ class Activity { return $ret; } - foreach ($tag as $t) { + foreach ($actor['tag'] as $t) { if ((isset($t['type']) && $t['type'] === 'PropertyValue') && (isset($t['name']) && $t['name'] === 'Protocol') && (isset($t['value']) && in_array($t['value'], ['zot6', 'activitypub', 'diaspora'])) @@ -3797,4 +3985,32 @@ class Activity { return $ret; } + + static function get_quote_bbcode($url) { + + $ret = ''; + + $a = self::fetch($url); + if ($a) { + $act = new ActivityStreams($a); + + if ($act->is_valid()) { + $content = self::get_content($act->obj); + + $ret .= "[share author='" . urlencode($act->actor['name']) . + "' profile='" . $act->actor['id'] . + "' avatar='" . $act->actor['icon']['url'] . + "' link='" . $act->obj['id'] . + "' auth='" . ((is_matrix_url($act->actor['id'])) ? 'true' : 'false') . + "' posted='" . $act->obj['published'] . + "' message_id='" . $act->obj['id'] . + "']"; + $ret .= self::bb_content($content, 'content'); + $ret .= '[/share]'; + } + } + + return $ret; + } + } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 275f6eff4..1c278f2ee 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -422,15 +422,19 @@ class ActivityStreams { static function get_accept_header_string($channel = null) { + $ret = ''; + $hookdata = []; if ($channel) $hookdata['channel'] = $channel; - $hookdata['data'] = 'application/x-zot-activity+json'; + $hookdata['data'] = ['application/x-zot-activity+json']; call_hooks('get_accept_header_string', $hookdata); - return $hookdata['data']; + $ret = implode(', ', $hookdata['data']); + + return $ret; } diff --git a/Zotlabs/Lib/Crypto.php b/Zotlabs/Lib/Crypto.php index f1794ae64..188c6bd81 100644 --- a/Zotlabs/Lib/Crypto.php +++ b/Zotlabs/Lib/Crypto.php @@ -87,6 +87,10 @@ class Crypto { return false; } + if (!$alg) { + $alg = 'sha256'; + } + try { $verify = openssl_verify($data, $sig, $key, $alg); } catch (Exception $e) { diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 2e483cb92..1421c72ae 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -845,6 +845,10 @@ class Enotify { // convert this logic into a json array just like the system notifications $who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author'); + $body = html2plain(bbcode($item['body'], ['drop_media']), 75, true); + if ($body) { + $body = htmlentities($body, ENT_QUOTES, 'UTF-8', false); + } $x = array( 'notify_link' => $item['llink'], @@ -858,7 +862,7 @@ class Enotify { //'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])), 'thread_top' => (($item['item_thread_top']) ? true : false), 'message' => bbcode(escape_tags($itemem_text)), - 'body' => htmlentities(html2plain(bbcode($item['body'], ['drop_media', true]), 75, true), ENT_QUOTES, 'UTF-8', false), + 'body' => $body, // these are for the superblock addon 'hash' => $item[$who]['xchan_hash'], 'uid' => $item['uid'], diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index 1c2095f10..00042bc7a 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -75,22 +75,23 @@ class LDSignatures { } static function hash($obj) { - - return hash('sha256',self::normalise($obj)); + return hash('sha256', self::normalise($obj)); } static function normalise($data) { + $ret = ''; + if(is_string($data)) { $data = json_decode($data); } if(! is_object($data)) - return ''; + return $ret; jsonld_set_document_loader('jsonld_document_loader'); try { - $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); + $ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); } catch (\Exception $e) { // Don't log the exception - this can exhaust memory @@ -98,7 +99,7 @@ class LDSignatures { logger('normalise error: ' . print_r($data,true)); } - return $d; + return $ret; } static function salmon_sign($data,$channel) { diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index e4d8d2275..2ed18d10b 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -676,6 +676,10 @@ class Libzot { logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG); + if (isset($arr['signing_algorithm']) && $arr['signing_algorithm']) { + set_xconfig($xchan_hash, 'system', 'signing_algorithm', $arr['signing_algorithm']); + } + $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($xchan_hash) ); @@ -1003,7 +1007,7 @@ class Libzot { $x = Crypto::unencapsulate($x, get_config('system', 'prvkey')); - if (!is_array($x)) { + if ($x && !is_array($x)) { $x = json_decode($x, true); } @@ -1227,6 +1231,16 @@ class Libzot { dbesc($AS->actor['id']) ); + if (! $r) { + // Author is unknown to this site. Perform channel discovery and try again. + $z = discover_by_webbie($AS->actor['id']); + if ($z) { + $r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s'", + dbesc($AS->actor['id']) + ); + } + } + if ($r) { $r = self::zot_record_preferred($r); $arr['author_xchan'] = $r['hubloc_hash']; @@ -1280,22 +1294,12 @@ class Libzot { if ($AS->data['hubloc']) { $arr['item_verified'] = true; + } - if (!array_key_exists('comment_policy', $arr)) { - // set comment policy depending on source hub. Unknown or osada is ActivityPub. - // Anything else we'll say is zot - which could have a range of project names - $s = q("select site_project from site where site_url = '%s' limit 1", - dbesc($r[0]['hubloc_url']) - ); - - if ((!$s) || (in_array($s[0]['site_project'], ['', 'osada']))) { - $arr['comment_policy'] = 'authenticated'; - } - else { - $arr['comment_policy'] = 'contacts'; - } - } + if (!array_key_exists('comment_policy', $arr)) { + $arr['comment_policy'] = 'authenticated'; } + if ($AS->meta['signed_data']) { IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false); } @@ -1568,7 +1572,11 @@ class Libzot { $local_public = false; continue; } - if (!MessageFilter::evaluate($arr, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { + + $incl = get_config('system','pubstream_incl'); + $excl = get_config('system','pubstream_excl'); + + if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) { $local_public = false; continue; } @@ -1743,11 +1751,13 @@ class Libzot { } } - $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", + // This is used to fetch allow/deny rules if either the sender + // or owner is a connection. post_is_importable() evaluates all of them + $abook = q("select * from abook where abook_channel = %d and ( abook_xchan = '%s' OR abook_xchan = '%s' )", intval($channel['channel_id']), - dbesc($arr['owner_xchan']) + dbesc($arr['owner_xchan']), + dbesc($arr['author_xchan']) ); - $abook = (($ab) ? $ab[0] : null); if (intval($arr['item_deleted'])) { @@ -1798,17 +1808,18 @@ class Libzot { elseif ($arr['edited'] > $r[0]['edited']) { $arr['id'] = $r[0]['id']; $arr['uid'] = $channel['channel_id']; - if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) { - $DR->update('update ignored'); - $result[] = $DR->get(); - } - else { - $item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery); - $DR->update('updated'); - $result[] = $DR->get(); - if (!$relay) - add_source_route($item_id, $sender); - } + + if (post_is_importable($channel['channel_id'], $arr, $abook)) { + $item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery); + $DR->update('updated'); + $result[] = $DR->get(); + if (!$relay) { + add_source_route($item_id, $sender); + } + } else { + $DR->update('update ignored'); + $result[] = $DR->get(); + } } else { $DR->update('update ignored'); @@ -1838,20 +1849,29 @@ class Libzot { $item_id = 0; - if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) { - $DR->update('post ignored'); - $result[] = $DR->get(); + $maxlen = get_max_import_size(); + + if ($maxlen && mb_strlen($arr['body']) > $maxlen) { + $arr['body'] = mb_substr($arr['body'], 0, $maxlen, 'UTF-8'); + logger('message length exceeds max_import_size: truncated'); } - else { + + if ($maxlen && mb_strlen($arr['summary']) > $maxlen) { + $arr['summary'] = mb_substr($arr['summary'], 0, $maxlen, 'UTF-8'); + logger('message summary length exceeds max_import_size: truncated'); + } + + if (post_is_importable($arr['uid'], $arr, $abook)) { $item_result = item_store($arr); if ($item_result['success']) { $item_id = $item_result['item_id']; - $parr = [ + $parr = [ 'item_id' => $item_id, - 'item' => $arr, - 'sender' => $sender, + 'item' => $arr, + 'sender' => $sender, 'channel' => $channel ]; + /** * @hooks activity_received * Called when an activity (post, comment, like, etc.) has been received from a zot source. @@ -1861,13 +1881,19 @@ class Libzot { * * \e array \b channel */ call_hooks('activity_received', $parr); + // don't add a source route if it's a relay or later recipients will get a route mismatch - if (!$relay) + if (!$relay) { add_source_route($item_id, $sender); + } } $DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']); $result[] = $DR->get(); + } else { + $DR->update('post ignored'); + $result[] = $DR->get(); } + } // preserve conversations with which you are involved from expiration @@ -2845,6 +2871,7 @@ class Libzot { ]; $ret['public_key'] = $e['xchan_pubkey']; + $ret['signing_algorithm'] = 'rsa-sha256'; $ret['username'] = $e['channel_address']; $ret['name'] = $e['xchan_name']; $ret['name_updated'] = $e['xchan_name_date']; diff --git a/Zotlabs/Lib/MessageFilter.php b/Zotlabs/Lib/MessageFilter.php index 21e6ca26a..95721e7c7 100644 --- a/Zotlabs/Lib/MessageFilter.php +++ b/Zotlabs/Lib/MessageFilter.php @@ -2,85 +2,104 @@ namespace Zotlabs\Lib; - +require_once('include/html2plain.php'); class MessageFilter { + public static function evaluate($item, $incl, $excl) { - static public function evaluate($item,$incl,$excl) { - - require_once('include/html2plain.php'); - - $text = prepare_text($item['body'],$item['mimetype']); + $text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/x-multicode')); $text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text); - $lang = null; - if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) { + if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) { $lang = detect_language($text); } - $tags = ((is_array($item['term']) && count($item['term'])) ? $item['term'] : false); + $tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false); // exclude always has priority - $exclude = (($excl) ? explode("\n",$excl) : null); + $exclude = (($excl) ? explode("\n", $excl) : null); - if($exclude) { - foreach($exclude as $word) { + if ($exclude) { + foreach ($exclude as $word) { $word = trim($word); - if(! $word) + if (! $word) { continue; - if(substr($word,0,1) === '#' && $tags) { - foreach($tags as $t) - if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) - return false; } - elseif(substr($word,0,1) === '$' && $tags) { - foreach($tags as $t) - if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) + if (substr($word, 0, 1) === '#' && $tags) { + foreach ($tags as $t) { + if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) { return false; - } - elseif((strpos($word,'/') === 0) && preg_match($word,$text)) + } + } + } elseif (substr($word, 0, 1) === '$' && $tags) { + foreach ($tags as $t) { + if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) { + return false; + } + } + } elseif (substr($word, 0, 2) === '?+') { + if (self::test_condition(substr($word, 2), $item['obj'])) { + return false; + } + } elseif (substr($word, 0, 1) === '?') { + if (self::test_condition(substr($word, 1), $item)) { + return false; + } + } elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) { return false; - elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0)) + } elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) { return false; - elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0)) + } elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) { return false; - elseif(stristr($text,$word) !== false) + } elseif (stristr($text, $word) !== false) { return false; + } } } - $include = (($incl) ? explode("\n",$incl) : null); + $include = (($incl) ? explode("\n", $incl) : null); - if($include) { - foreach($include as $word) { + if ($include) { + foreach ($include as $word) { $word = trim($word); - if(! $word) + if (! $word) { continue; - if(substr($word,0,1) === '#' && $tags) { - foreach($tags as $t) - if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) - return true; } - elseif(substr($word,0,1) === '$' && $tags) { - foreach($tags as $t) - if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) + if (substr($word, 0, 1) === '#' && $tags) { + foreach ($tags as $t) { + if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) { return true; - } - elseif((strpos($word,'/') === 0) && preg_match($word,$text)) + } + } + } elseif (substr($word, 0, 1) === '$' && $tags) { + foreach ($tags as $t) { + if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) { + return true; + } + } + } elseif (substr($word, 0, 2) === '?+') { + if (self::test_condition(substr($word, 2), $item['obj'])) { + return true; + } + } elseif (substr($word, 0, 1) === '?') { + if (self::test_condition(substr($word, 1), $item)) { + return true; + } + } elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) { return true; - elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0)) + } elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) { return true; - elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0)) + } elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) { return true; - elseif(stristr($text,$word) !== false) + } elseif (stristr($text, $word) !== false) { return true; + } } - } - else { + } else { return true; } @@ -88,4 +107,113 @@ class MessageFilter { } + /** + * @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche + * + * This is extensible. The first version of variable testing supports tests of the forms: + * + * - ?foo ~= baz which will check if item.foo contains the string 'baz'; + * - ?foo == baz which will check if item.foo is the string 'baz'; + * - ?foo != baz which will check if item.foo is not the string 'baz'; + * - ?foo >= 3 which will check if item.foo is greater than or equal to 3; + * - ?foo > 3 which will check if item.foo is greater than 3; + * - ?foo <= 3 which will check if item.foo is less than or equal to 3; + * - ?foo < 3 which will check if item.foo is less than 3; + * + * - ?foo {} baz which will check if 'baz' is an array element in item.foo + * - ?foo {*} baz which will check if 'baz' is an array key in item.foo + * - ?foo which will check for a return of a true condition for item.foo; + * + * The values 0, '', an empty array, and an unset value will all evaluate to false. + * + * @param string $s + * @param array $item + * @return bool + */ + + public static function test_condition($s,$item) { + + if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if (stripos($x, trim($matches[2])) !== false) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x == trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x != trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x >= trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x <= trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x > trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x < trim($matches[2])) { + return true; + } + return false; + } + + if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if (is_array($x) && in_array(trim($matches[2]), $x)) { + return true; + } + return false; + } + + if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if (is_array($x) && array_key_exists(trim($matches[2]), $x)) { + return true; + } + return false; + } + + if (preg_match('/(.*?)$/', $s, $matches)) { + $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR); + if ($x) { + return true; + } + return false; + } + + return false; + } + } diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index b39887c9e..da37c582f 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -254,21 +254,21 @@ class Directory extends Controller { $connect_link = ''; $location = ''; - if(strlen($rr['locale'])) + if(isset($rr['locale'])) $location .= $rr['locale']; - if(strlen($rr['region'])) { - if(strlen($rr['locale'])) + if(isset($rr['region'])) { + if($location) $location .= ', '; $location .= $rr['region']; } - if(strlen($rr['country'])) { - if(strlen($location)) + if(isset($rr['country'])) { + if($location) $location .= ', '; $location .= $rr['country']; } $age = ''; - if(strlen($rr['birthday'])) { + if(isset($rr['birthday'])) { if(($years = age($rr['birthday'],'UTC','')) > 0) $age = $years; } diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index 29b0df739..5001bbe62 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -27,6 +27,8 @@ class Hq extends \Zotlabs\Web\Controller { return; } + $item_hash = ''; + if(argc() > 1 && argv(1) !== 'load') { $item_hash = unpack_link_id(argv(1)); } @@ -97,7 +99,7 @@ class Hq extends \Zotlabs\Web\Controller { 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), 'default_location' => $channel['channel_location'], 'nickname' => $channel['channel_address'], - 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), 'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'permissions' => $channel_acl, 'bang' => '', @@ -112,6 +114,7 @@ class Hq extends \Zotlabs\Web\Controller { 'reset' => t('Reset form') ]; + $a = ''; $o = status_editor($a, $x, true); } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 41a4e120d..574a90c1a 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -695,6 +695,7 @@ class Item extends Controller { $expires = $orig_post['expires']; $comments_closed = $orig_post['comments_closed']; $mid = $orig_post['mid']; + $thr_parent = $orig_post['thr_parent']; $parent_mid = $orig_post['parent_mid']; $plink = $orig_post['plink']; } @@ -1092,7 +1093,7 @@ class Item extends Controller { $datarray['created'] = $created; $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); $datarray['expires'] = $expires; - $datarray['comments_closed'] = $comments_closed; + $datarray['comments_closed'] = (($nocomment) ? $created : $comments_closed); $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); $datarray['received'] = (($orig_post) ? datetime_convert() : $created); $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 016a0a309..f4f6cc8d1 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -272,15 +272,17 @@ class Network extends \Zotlabs\Web\Controller { $likes_sql = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; // This is for nouveau view public forum cid queries (if a forum notification is clicked) - $p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'", - intval(local_channel()), - intval(TERM_FORUM), - dbesc($cid_r[0]['xchan_name']) - ); - - $p_str = ids_to_querystr($p, 'parent'); - if($p_str) - $p_sql = " OR item.parent IN ( $p_str ) "; + //$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'", + //intval(local_channel()), + //intval(TERM_FORUM), + //dbesc($cid_r[0]['xchan_name']) + //); + + //$p_str = ids_to_querystr($p, 'parent'); + + $p_sql = ''; + //if($p_str) + //$p_sql = " OR item.parent IN ( $p_str ) "; $sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 $likes_sql "; } diff --git a/Zotlabs/Module/Pdledit_gui.php b/Zotlabs/Module/Pdledit_gui.php new file mode 100644 index 000000000..b550b92d3 --- /dev/null +++ b/Zotlabs/Module/Pdledit_gui.php @@ -0,0 +1,553 @@ +<?php + +namespace Zotlabs\Module; + +use App; +use Zotlabs\Web\Controller; +use Zotlabs\Render\Comanche; +use Zotlabs\Lib\Libsync; + +class Pdledit_gui extends Controller { + + function post() { + + if (!local_channel()) { + return; + } + + if (!$_REQUEST['module']) { + return; + } + + $module = $_REQUEST['module']; + + $ret = [ + 'success' => false, + 'module' => $module + ]; + + if ($_REQUEST['reset']) { + del_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl'); + Libsync::build_sync_packet(); + $ret['success'] = true; + json_return_and_die($ret); + } + + if ($_REQUEST['save']) { + if (!$_REQUEST['data']) { + return $ret; + } + + $data = json_decode($_REQUEST['data'],true); + $stored_pdl_result = self::get_pdl($module); + $pdl = $stored_pdl_result['pdl']; + + foreach ($data as $region => $entries) { + $region_pdl = ''; + foreach ($entries as $entry) { + $region_pdl .= base64_decode($entry) . "\r\n"; + } + $pdl = preg_replace('/\[region=' . $region . '\](.*?)\[\/region\]/ism', '[region=' . $region . ']' . "\r\n" . $region_pdl . "\r\n" . '[/region]', $pdl); + } + + set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl)); + Libsync::build_sync_packet(); + + $ret['success'] = true; + json_return_and_die($ret); + } + + if ($_REQUEST['save_src']) { + set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($_REQUEST['src'])); + Libsync::build_sync_packet(); + + $ret['success'] = true; + json_return_and_die($ret); + } + + if ($_REQUEST['save_template']) { + if (!$_REQUEST['data']) { + return $ret; + } + + $template = $_REQUEST['data'][0]['value']; + $pdl_result = self::get_pdl($module); + $stored_template = self::get_template($pdl_result['pdl']); + + if ($template === $stored_template) { + $ret['success'] = true; + return $ret; + } + + $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl_result['pdl'], $matches); + if ($cnt) { + $pdl = str_replace('[template]' . $stored_template . '[/template]', '[template]' . $template . '[/template]', $pdl_result['pdl']); + } + else { + $pdl = '[template]' . $template . '[/template]' . "\r\n"; + $pdl .= $pdl_result['pdl']; + } + + set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl)); + Libsync::build_sync_packet(); + + $ret['success'] = true; + json_return_and_die($ret); + } + + } + + function get() { + + if(! local_channel()) { + return EMPTY_STR; + } + + $module = argv(1); + + if (!$module) { + goaway(z_root() . '/pdledit_gui/hq'); + } + + $pdl_result = self::get_pdl($module); + + $pdl = $pdl_result['pdl']; + $modified = $pdl_result['modified']; + + if(!$pdl) { + return t('Layout not found'); + } + + $template = self::get_template($pdl); + + $template_info = self::get_template_info($template); + + if(empty($template_info['contentregion'])) { + return t('This template does not support pdledi_gui (no content regions defined)'); + } + + App::$page['template'] = $template; + + $regions = self::get_regions($pdl); + + foreach ($regions as $k => $v) { + $region_str = ''; + if (is_array($v)) { + ksort($v); + foreach ($v as $entry) { + // Get the info from the file and replace entry if we get anything useful + $widget_info = get_widget_info($entry['name']); + $entry['name'] = (($widget_info['name']) ? $widget_info['name'] : $entry['name']); + $entry['desc'] = (($widget_info['description']) ? $widget_info['description'] : $entry['desc']); + + $region_str .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [ + '$entry' => $entry + ]); + } + } + App::$layout['region_' . $k] = $region_str; + } + + $templates = self::get_templates(); + $templates_html = replace_macros(get_markup_template('pdledit_gui_templates.tpl'), [ + '$templates' => $templates, + '$active' => $template + ]); + + $items_html = ''; + + //$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [ + //'$entry' => [ + //'type' => 'content', + //'name' => t('Main page content'), + //'src' => base64_encode('$content') + //], + //'$disable_controls' => true + //]); + + foreach (self::get_widgets($module) as $entry) { + $items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [ + '$entry' => $entry, + '$disable_controls' => true + ]); + } + + foreach (self::get_menus() as $entry) { + $items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [ + '$entry' => $entry, + '$disable_controls' => true + ]); + } + + foreach (self::get_blocks() as $entry) { + $items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [ + '$entry' => $entry, + '$disable_controls' => true + ]); + } + + App::$layout['region_content'] .= replace_macros(get_markup_template('pdledit_gui.tpl'), [ + '$content_regions' => $template_info['contentregion'], + '$page_src' => base64_encode($pdl), + '$templates' => base64_encode($templates_html), + '$modules' => base64_encode(self::get_modules()), + '$items' => base64_encode($items_html), + '$module_modified' => $modified, + '$module' => $module + ]); + + } + + function get_templates() { + $ret = []; + + $files = glob('view/php/*.php'); + if($files) { + foreach($files as $f) { + $name = basename($f, '.php'); + $x = get_template_info($name); + if(!empty($x['contentregion'])) { + $ret[] = [ + 'name' => $name, + 'desc' => $x['description'] + ]; + } + } + } + + return $ret; + } + + function get_modules() { + $ret = ''; + + $files = glob('Zotlabs/Module/*.php'); + if($files) { + foreach($files as $f) { + $name = lcfirst(basename($f,'.php')); + + if ($name === 'admin' && !is_site_admin()) { + continue; + } + + $x = theme_include('mod_' . $name . '.pdl'); + if($x) { + $ret .= '<div class="mb-2"><a href="pdledit_gui/' . $name . '">' . $name . '</a></div>'; + } + } + } + + return $ret; + } + + function get_widgets($module) { + $ret = []; + + $checkpaths = [ + 'Zotlabs/Widget/*.php' + ]; + + foreach ($checkpaths as $path) { + $files = glob($path); + if($files) { + foreach($files as $f) { + $name = lcfirst(basename($f, '.php')); + + $widget_info = get_widget_info($name); + if ($widget_info['requires'] && strpos($widget_info['requires'], 'admin') !== false && !is_site_admin()) { + continue; + } + + if ($widget_info['requires'] && strpos($widget_info['requires'], $module) === false) { + continue; + } + + $ret[] = [ + 'type' => 'widget', + 'name' => $widget_info['name'] ?? $name, + 'desc' => $widget_info['description'] ?? '', + 'src' => base64_encode('[widget=' . $name . '][/widget]') + ]; + } + } + } + + return $ret; + } + + function get_menus() { + $ret = []; + + $r = q("select * from menu where menu_channel_id = %d and menu_flags = 0", + intval(local_channel()) + ); + + foreach ($r as $rr) { + $name = $rr['menu_name']; + $desc = $rr['menu_desc']; + $ret[] = [ + 'type' => 'menu', + 'name' => $name, + 'desc' => $desc, + 'src' => base64_encode('[menu]' . $name . '[/menu]') + ]; + } + + return $ret; + } + + function get_blocks() { + $ret = []; + + $r = q("select v, title, summary from item join iconfig on iconfig.iid = item.id and item.uid = %d + and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'", + intval(local_channel()) + ); + + foreach ($r as $rr) { + $name = $rr['v']; + $desc = (($rr['title']) ? $rr['title'] : $rr['summary']); + $ret[] = [ + 'type' => 'block', + 'name' => $name, + 'desc' => $desc, + 'src' => base64_encode('[block]' . $name . '[/block]') + ]; + } + + return $ret; + } + + function get_template($pdl) { + $ret = 'default'; + + $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl, $matches); + if($cnt && isset($matches[1])) { + $ret = trim($matches[1]); + } + + return $ret; + } + + function get_regions($pdl) { + $ret = []; + $supported_regions = ['aside', 'content', 'right_aside']; + + $cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $pdl, $matches, PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + if (!in_array($mtch[1], $supported_regions)) { + continue; + } + $ret[$mtch[1]] = self::parse_region($mtch[2]); + } + } + + return $ret; + } + + function parse_region($pdl) { + $ret = []; + + $cnt = preg_match_all('/\$content\b/ism', $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + if($cnt) { + foreach($matches as $mtch) { + $offset = intval($mtch[0][1]); + $name = trim($mtch[0][0]); + //$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0])); + $src = base64_encode($mtch[0][0]); + $ret[$offset] = [ + 'type' => 'content', + 'name' => t('Main page content'), + 'desc' => t('The main page content can not be edited!'), + 'src' => $src + ]; + } + } + + $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + if($cnt) { + foreach($matches as $mtch) { + $offset = intval($mtch[1][1]); + $name = trim($mtch[1][0]); + //$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0])); + $src = base64_encode($mtch[0][0]); + + $ret[$offset] = [ + 'type' => 'menu', + 'name' => $name, + 'desc' => '', + 'src' => $src + ]; + } + } + + // menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu] + // allows different menu renderings to be applied + + //$cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); + //if($cnt) { + //foreach($matches as $mtch) { + //$s = str_replace($mtch[0],$this->menu(trim($mtch[2]),$mtch[1]),$s); + //} + //} + + + $cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + if($cnt) { + foreach($matches as $mtch) { + $offset = intval($mtch[1][1]); + $name = trim($mtch[1][0]); + //$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0])); + $src = base64_encode($mtch[0][0]); + $ret[$offset] = [ + 'type' => 'block', + 'name' => $name, + 'desc' => '', + 'src' => $src + ]; + } + } + + //$cnt = preg_match_all("/\[block=(.*?)\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); + //if($cnt) { + //foreach($matches as $mtch) { + //$s = str_replace($mtch[0],$this->block(trim($mtch[2]),trim($mtch[1])),$s); + //} + //} + + //$cnt = preg_match_all("/\[js\](.*?)\[\/js\]/ism", $s, $matches, PREG_SET_ORDER); + //if($cnt) { + //foreach($matches as $mtch) { + //$s = str_replace($mtch[0],$this->js(trim($mtch[1])),$s); + //} + //} + + //$cnt = preg_match_all("/\[css\](.*?)\[\/css\]/ism", $s, $matches, PREG_SET_ORDER); + //if($cnt) { + //foreach($matches as $mtch) { + //$s = str_replace($mtch[0],$this->css(trim($mtch[1])),$s); + //} + //} + + // need to modify this to accept parameters + + $cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + + if($cnt) { + foreach($matches as $mtch) { + $offset = intval($mtch[1][1]); + $name = trim($mtch[1][0]); + //$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0])); + $src = base64_encode($mtch[0][0]); + $ret[$offset] = [ + 'type' => 'widget', + 'name' => $name, + 'desc' => '', + 'src' => $src + ]; + } + } + + return $ret; + + } + + + /** + * @brief Parse template comment in search of template info. + * + * like + * \code + * * Name: MyWidget + * * Description: A widget + * * Version: 1.2.3 + * * Author: John <profile url> + * * Author: Jane <email> + * * ContentRegionID: some_id + * * ContentRegionID: some_other_id + * * + *\endcode + * @param string $template the name of the template + * @return array with the information + */ + function get_template_info($template){ + $m = []; + $info = [ + 'name' => $template, + 'description' => '', + 'author' => [], + 'maintainer' => [], + 'version' => '', + 'contentregion' => [] + ]; + + $checkpaths = [ + 'view/php/' . $template . '.php', + ]; + + $template_found = false; + + foreach ($checkpaths as $path) { + if (is_file($path)) { + $template_found = true; + $f = file_get_contents($path); + break; + } + } + + if(!($template_found && $f)) + return $info; + + $f = escape_tags($f); + $r = preg_match('|/\*.*\*/|msU', $f, $m); + + if ($r) { + $ll = explode("\n", $m[0]); + foreach($ll as $l) { + $l = trim($l, "\t\n\r */"); + if ($l != ''){ + list($k, $v) = array_map('trim', explode(':', $l, 2)); + $k = strtolower($k); + if (in_array($k, ['author', 'maintainer'])){ + $r = preg_match('|([^<]+)<([^>]+)>|', $v, $m); + if ($r) { + $info[$k][] = array('name' => $m[1], 'link' => $m[2]); + } else { + $info[$k][] = array('name' => $v); + } + } + elseif (in_array($k, ['contentregion'])){ + $info[$k][] = array_map('trim', explode(',', $v)); + } + else { + $info[$k] = $v; + } + } + } + } + + return $info; + } + + function get_pdl($module) { + $ret = [ + 'pdl' => null, + 'modified' => true + ]; + + $pdl_path = 'mod_' . $module . '.pdl'; + + $ret['pdl'] = get_pconfig(local_channel(), 'system', $pdl_path); + + if(!$ret['pdl']) { + $pdl_path = theme_include($pdl_path); + if ($pdl_path) { + $ret['pdl'] = file_get_contents($pdl_path); + $ret['modified'] = false; + } + } + + return $ret; + } +} diff --git a/Zotlabs/Module/Settings/Calendar.php b/Zotlabs/Module/Settings/Calendar.php index ab85eb450..65240c635 100644 --- a/Zotlabs/Module/Settings/Calendar.php +++ b/Zotlabs/Module/Settings/Calendar.php @@ -11,14 +11,14 @@ class Calendar { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Calendar { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Calendar Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index a0da020b7..840efc162 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -35,6 +35,8 @@ class Channel { $pageflags = $channel['channel_pageflags']; $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); $expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0); + $incl = ((x($_POST['message_filter_incl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_incl']), ENT_QUOTES) : ''); + $excl = ((x($_POST['message_filter_excl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_excl']), ENT_QUOTES) : ''); if ($adult != $existing_adult) { $pageflags = ($pageflags ^ PAGE_ADULT); @@ -131,6 +133,8 @@ class Channel { 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); + set_pconfig(local_channel(), 'system', 'message_filter_incl', $incl); + set_pconfig(local_channel(), 'system', 'message_filter_excl', $excl); $r = q("update channel set channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_expire_days = %d @@ -277,6 +281,8 @@ class Channel { '$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.')], + '$message_filter_excl' => ['message_filter_excl', t('Do not import posts with this text'), get_pconfig(local_channel(), 'system', 'message_filter_excl', ''), t('Words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts')], + '$message_filter_incl' => ['message_filter_incl', t('Only import posts with this text'), get_pconfig(local_channel(), 'system', 'message_filter_incl', ''), t('Words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts')] ]); call_hooks('settings_form', $o); diff --git a/Zotlabs/Module/Settings/Channel_home.php b/Zotlabs/Module/Settings/Channel_home.php index e8faa7fb2..470dbe4c3 100644 --- a/Zotlabs/Module/Settings/Channel_home.php +++ b/Zotlabs/Module/Settings/Channel_home.php @@ -13,7 +13,7 @@ class Channel_home { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); @@ -25,10 +25,10 @@ class Channel_home { $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); set_pconfig(local_channel(),'system','channel_menu',$channel_menu); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -82,7 +82,7 @@ class Channel_home { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Channel Home Settings'), @@ -90,7 +90,7 @@ class Channel_home { '$extra_settings_html' => $extra_settings_html, '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Connections.php b/Zotlabs/Module/Settings/Connections.php index 4369deb27..52a95a3d1 100644 --- a/Zotlabs/Module/Settings/Connections.php +++ b/Zotlabs/Module/Settings/Connections.php @@ -11,14 +11,14 @@ class Connections { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Connections { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Connections Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Directory.php b/Zotlabs/Module/Settings/Directory.php index d1dd0677e..09ea61f60 100644 --- a/Zotlabs/Module/Settings/Directory.php +++ b/Zotlabs/Module/Settings/Directory.php @@ -11,14 +11,14 @@ class Directory { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Directory { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Directory Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Editor.php b/Zotlabs/Module/Settings/Editor.php index cf6dd2807..85c3e69ae 100644 --- a/Zotlabs/Module/Settings/Editor.php +++ b/Zotlabs/Module/Settings/Editor.php @@ -11,14 +11,14 @@ class Editor { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Editor { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Editor Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Events.php b/Zotlabs/Module/Settings/Events.php index ab393c932..0a0e3516c 100644 --- a/Zotlabs/Module/Settings/Events.php +++ b/Zotlabs/Module/Settings/Events.php @@ -11,14 +11,14 @@ class Events { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Events { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Events Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Manage.php b/Zotlabs/Module/Settings/Manage.php index cbc494cf8..6fb57eafb 100644 --- a/Zotlabs/Module/Settings/Manage.php +++ b/Zotlabs/Module/Settings/Manage.php @@ -12,14 +12,14 @@ class Manage { $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -35,14 +35,14 @@ class Manage { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Channel Manager Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Network.php b/Zotlabs/Module/Settings/Network.php index 9f5bdb2e5..eae963a25 100644 --- a/Zotlabs/Module/Settings/Network.php +++ b/Zotlabs/Module/Settings/Network.php @@ -21,10 +21,10 @@ class Network { $network_divmore_height = 50; set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -53,7 +53,7 @@ class Network { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Stream Settings'), @@ -61,7 +61,7 @@ class Network { '$extra_settings_html' => $extra_settings_html, '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Photos.php b/Zotlabs/Module/Settings/Photos.php index 8195d660b..f68c8847b 100644 --- a/Zotlabs/Module/Settings/Photos.php +++ b/Zotlabs/Module/Settings/Photos.php @@ -7,18 +7,18 @@ use Zotlabs\Lib\Libsync; class Photos { function post() { - + $module = substr(strrchr(strtolower(static::class), '\\'), 1); check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module); - + $features = get_module_features($module); process_module_features_post(local_channel(), $features, $_POST); - + Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -34,14 +34,14 @@ class Photos { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Photos Settings'), '$features' => process_module_features_get(local_channel(), $features), '$submit' => t('Submit') )); - + return $o; } diff --git a/Zotlabs/Module/Settings/Privacy.php b/Zotlabs/Module/Settings/Privacy.php index fbda78a6f..847bb3b8f 100644 --- a/Zotlabs/Module/Settings/Privacy.php +++ b/Zotlabs/Module/Settings/Privacy.php @@ -119,7 +119,7 @@ class Privacy { ], '$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')]], + '$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]] ]); return $o; diff --git a/Zotlabs/Module/Settings/Profiles.php b/Zotlabs/Module/Settings/Profiles.php index a1a1b8d96..0ff2dfb6d 100644 --- a/Zotlabs/Module/Settings/Profiles.php +++ b/Zotlabs/Module/Settings/Profiles.php @@ -23,7 +23,7 @@ class Profiles { Libsync::build_sync_packet(); - if($_POST['rpath']) + if(isset($_POST['rpath']) && is_local_url($_POST['rpath'])) goaway($_POST['rpath']); return; @@ -43,7 +43,7 @@ class Profiles { $tpl = get_markup_template("settings_module.tpl"); $o .= replace_macros($tpl, array( - '$rpath' => $rpath, + '$rpath' => escape_url($rpath), '$action_url' => 'settings/' . $module, '$form_security_token' => get_form_security_token('settings_' . $module), '$title' => t('Profiles Settings'), diff --git a/Zotlabs/Photo/PhotoDriver.php b/Zotlabs/Photo/PhotoDriver.php index 4c4f26e32..6bdb89ab1 100644 --- a/Zotlabs/Photo/PhotoDriver.php +++ b/Zotlabs/Photo/PhotoDriver.php @@ -2,7 +2,7 @@ namespace Zotlabs\Photo; -use Zotlabs\Lib\Hashpath; +use Zotlabs\Lib\Hashpath; /** * @brief Abstract photo driver class. @@ -494,11 +494,11 @@ abstract class PhotoDriver { ( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires, profile ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($p['profile'])); } - logger('Photo save imgscale ' . $p['imgscale'] . ' returned ' . intval($r)); + logger('Photo save imgscale ' . $p['imgscale'] . ' returned: ' . (($r) ? 1 : 0)); return $r; } - + /** * @brief Stores thumbnail to database or filesystem. * @@ -530,13 +530,13 @@ abstract class PhotoDriver { } else $arr['os_storage'] = 0; - + if(! $this->save($arr)) { if(array_key_exists('os_syspath', $arr)) @unlink($arr['os_syspath']); return false; } - + return true; } diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index a7a59b8cf..4177477a1 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -127,6 +127,7 @@ class HTTPSig { if (array_key_exists($h, $headers)) { $signed_data .= $h . ': ' . $headers[$h] . "\n"; } + if ($h === 'date') { $d = new DateTime($headers[$h]); $d->setTimeZone(new DateTimeZone('UTC')); @@ -142,20 +143,34 @@ class HTTPSig { $signed_data = rtrim($signed_data, "\n"); $algorithm = null; + if ($sig_block['algorithm'] === 'rsa-sha256') { $algorithm = 'sha256'; } + if ($sig_block['algorithm'] === 'rsa-sha512') { $algorithm = 'sha512'; } - if (!array_key_exists('keyId', $sig_block)) + if (!array_key_exists('keyId', $sig_block)) { return $result; + } $result['signer'] = $sig_block['keyId']; $cached_key = self::get_key($key, $keytype, $result['signer']); + if ($sig_block['algorithm'] === 'hs2019') { + if (isset($cached_key['algorithm'])) { + if (strpos($cached_key['algorithm'], 'rsa-sha256') !== false) { + $algorithm = 'sha256'; + } + + if (strpos($cached_key['algorithm'], 'rsa-sha512') !== false) { + $algorithm = 'sha512'; + } + } + } if (!($cached_key && $cached_key['public_key'])) { return $result; @@ -296,7 +311,7 @@ class HTTPSig { $best = Libzot::zot_record_preferred($x); } if ($best && $best['xchan_pubkey']) { - return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best]; + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; } } @@ -308,12 +323,38 @@ class HTTPSig { // The record wasn't in cache. Fetch it now. $r = ActivityStreams::fetch($id); + $signatureAlgorithm = EMPTY_STR; if ($r) { if (array_key_exists('publicKey', $r) && array_key_exists('publicKeyPem', $r['publicKey']) && array_key_exists('id', $r['publicKey'])) { if ($r['publicKey']['id'] === $id || $r['id'] === $id) { $portable_id = ((array_key_exists('owner', $r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR); - return ['public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => []]; + + // the w3c sec context has conflicting names and no defined values for this property except + // "http://www.w3.org/2000/09/xmldsig#rsa-sha1" + + // Since the names conflict, it could mess up LD-signatures but we will accept both, and at this + // time we will only look for the substrings 'rsa-sha256' and 'rsa-sha512' within those properties. + // We will also accept a toplevel 'sigAlgorithm' regardless of namespace with the same constraints. + // Default to rsa-sha256 if we can't figure out. If they're sending 'hs2019' we have to + // look for something. + + if (isset($r['publicKey']['signingAlgorithm'])) { + $signatureAlgorithm = $r['publicKey']['signingAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + + if (isset($r['publicKey']['signatureAlgorithm'])) { + $signatureAlgorithm = $r['publicKey']['signatureAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + + if (isset($r['sigAlgorithm'])) { + $signatureAlgorithm = $r['sigAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + + return ['public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'algorithm' => (($signatureAlgorithm) ? $signatureAlgorithm : 'rsa-sha256'), 'hubloc' => []]; } } } @@ -343,7 +384,7 @@ class HTTPSig { } if ($best && $best['xchan_pubkey']) { - return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best]; + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; } } @@ -389,7 +430,7 @@ class HTTPSig { } if ($best && $best['xchan_pubkey']) { - return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best]; + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; } } @@ -461,6 +502,9 @@ class HTTPSig { $x = self::sign($head, $prvkey, $alg); + // TODO: should we default to hs2019? + // $headerval = 'keyId="' . $keyid . '",algorithm="' . (($algorithm === 'rsa-sha256') ? 'hs2019' : $algorithm) . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"'; + $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"'; if ($encryption) { @@ -528,11 +572,14 @@ class HTTPSig { if ($head) { foreach ($head as $k => $v) { - $headers .= strtolower($k) . ': ' . trim($v) . "\n"; + $k = strtolower($k); + $v = (($v) ? trim($v) : ''); + + $headers .= $k . ': ' . $v . "\n"; if ($fields) $fields .= ' '; - $fields .= strtolower($k); + $fields .= $k; } // strip the trailing linefeed $headers = rtrim($headers, "\n"); diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php index de0d5a883..70c6eb9b8 100644 --- a/Zotlabs/Web/WebServer.php +++ b/Zotlabs/Web/WebServer.php @@ -107,7 +107,8 @@ class WebServer { $Router->Dispatch(); - $this->set_homebase(); + // TODO: this is not used for anything atm and messes up comanche templates by adding some javascript + //$this->set_homebase(); // now that we've been through the module content, see if the page reported // a permission problem and if so, a 403 response would seem to be in order. diff --git a/Zotlabs/Widget/Activity.php b/Zotlabs/Widget/Activity.php index 5d9795c7e..34e0f67dc 100644 --- a/Zotlabs/Widget/Activity.php +++ b/Zotlabs/Widget/Activity.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Activity + * * Description: Shows the unseen activity count per contact + */ + namespace Zotlabs\Widget; class Activity { diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php index b7a69752e..daaf5fb67 100644 --- a/Zotlabs/Widget/Activity_filter.php +++ b/Zotlabs/Widget/Activity_filter.php @@ -1,5 +1,12 @@ <?php +/** + * * Name: Activity filters + * * Description: Filters for the network stream + * * Requires: network + */ + + namespace Zotlabs\Widget; use App; diff --git a/Zotlabs/Widget/Activity_order.php b/Zotlabs/Widget/Activity_order.php index d3fe2a30f..e8ee11508 100644 --- a/Zotlabs/Widget/Activity_order.php +++ b/Zotlabs/Widget/Activity_order.php @@ -2,6 +2,12 @@ namespace Zotlabs\Widget; +/** + * * Name: Activity order + * * Description: Order the network stream by posted date, last commented or by date unthreaded + * * Requires: network + */ + class Activity_order { function widget($arr) { @@ -22,7 +28,7 @@ class Activity_order { switch($_GET['order']){ case 'post': $postord_active = 'active'; - set_pconfig(local_channel(), 'mod_network', 'order', 1); + set_pconfig(local_channel(), 'mod_network', 'order', 1); break; case 'comment': $commentord_active = 'active'; diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php index f349377a0..0a7a6925f 100644 --- a/Zotlabs/Widget/Admin.php +++ b/Zotlabs/Widget/Admin.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Admin menu + * * Requires: admin + */ + namespace Zotlabs\Widget; class Admin { diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php index 572af0503..e083e576c 100644 --- a/Zotlabs/Widget/Affinity.php +++ b/Zotlabs/Widget/Affinity.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Affinity Tool + * * Description: Filter the network stream by affinity, requires the Affinity Tool App + * * Requires: network + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Apps; @@ -13,7 +19,7 @@ class Affinity { if(! Apps::system_app_installed(local_channel(),'Affinity Tool')) return; - + $default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0); $default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99); @@ -54,7 +60,7 @@ class Affinity { '$refresh' => t('Refresh'), '$labels' => $label_str, )); - + $arr = array('html' => $x); call_hooks('main_slider',$arr); @@ -63,4 +69,4 @@ class Affinity { } } - + diff --git a/Zotlabs/Widget/Album.php b/Zotlabs/Widget/Album.php index f359e6d0f..003f6f49d 100644 --- a/Zotlabs/Widget/Album.php +++ b/Zotlabs/Widget/Album.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Album + * * Description: Displays an album with a title which can be defined via the 'album' and 'title' variable + * * Requires: channel, articles, cards, wiki + */ + namespace Zotlabs\Widget; require_once('include/attach.php'); @@ -99,7 +105,7 @@ class Album { '$upload_form' => $upload_form, '$usage' => $usage_message )); - + return $o; } } diff --git a/Zotlabs/Widget/Appcategories.php b/Zotlabs/Widget/Appcategories.php index e916f095f..31fb2542e 100644 --- a/Zotlabs/Widget/Appcategories.php +++ b/Zotlabs/Widget/Appcategories.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: App categories + * * Description: Shows a menu with various app categories + * * Requires: apps + */ + namespace Zotlabs\Widget; class Appcategories { diff --git a/Zotlabs/Widget/Appcloud.php b/Zotlabs/Widget/Appcloud.php index 2a4671eee..791d534c2 100644 --- a/Zotlabs/Widget/Appcloud.php +++ b/Zotlabs/Widget/Appcloud.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: App cloud + * * Description: Shows a cloud with various app categories + * * Requires: apps + */ + namespace Zotlabs\Widget; class Appcloud { diff --git a/Zotlabs/Widget/Appstore.php b/Zotlabs/Widget/Appstore.php index da05c0b62..d8499152a 100644 --- a/Zotlabs/Widget/Appstore.php +++ b/Zotlabs/Widget/Appstore.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: App store menu + * * Description: Shows a menu with links to installed and available apps + * * Requires: apps + */ + namespace Zotlabs\Widget; diff --git a/Zotlabs/Widget/Archive.php b/Zotlabs/Widget/Archive.php index 9adaac38f..e712a8236 100644 --- a/Zotlabs/Widget/Archive.php +++ b/Zotlabs/Widget/Archive.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Archive + * * Description: A menu with links to content sorted by years and months + * * Requires: channel, articles, cards + */ + namespace Zotlabs\Widget; diff --git a/Zotlabs/Widget/Bookmarkedchats.php b/Zotlabs/Widget/Bookmarkedchats.php index d64bbdb4b..5d6d000c1 100644 --- a/Zotlabs/Widget/Bookmarkedchats.php +++ b/Zotlabs/Widget/Bookmarkedchats.php @@ -1,14 +1,15 @@ <?php +/** + * * Name: Bookmarked chats + * * Description: A menu with bookmarked chats + */ + namespace Zotlabs\Widget; class Bookmarkedchats { function widget($arr) { - - if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat')) - return ''; - $h = get_observer_hash(); if(! $h) return; diff --git a/Zotlabs/Widget/Catcloud.php b/Zotlabs/Widget/Catcloud.php index c53f9bbf6..5740caab7 100644 --- a/Zotlabs/Widget/Catcloud.php +++ b/Zotlabs/Widget/Catcloud.php @@ -2,6 +2,13 @@ namespace Zotlabs\Widget; +/** + * * Name: Category cloud + * * Description: Display category links in a cloud + * * Requires: channel, cards, articles + */ + + class Catcloud { function widget($arr) { @@ -22,7 +29,7 @@ class Catcloud { return card_catblock(\App::$profile['profile_uid'], $limit, '', \App::$profile['channel_hash']); case 'articles': - + if(! perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'view_pages')) return ''; diff --git a/Zotlabs/Widget/Catcloud_wall.php b/Zotlabs/Widget/Catcloud_wall.php index 3795987cc..4ee30d023 100644 --- a/Zotlabs/Widget/Catcloud_wall.php +++ b/Zotlabs/Widget/Catcloud_wall.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Category cloud wall + * * Description: Display category links in a cloud restricted to wall posts + * * Requires: channel + */ + namespace Zotlabs\Widget; class Catcloud_wall { diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index 94ad469da..0c6996d55 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Categories + * * Description: Display a menu with links to categories + * * Requires: channel, articles, cards, cloud + */ + namespace Zotlabs\Widget; use App; diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php index ce716b455..f84f5cb04 100644 --- a/Zotlabs/Widget/Cdav.php +++ b/Zotlabs/Widget/Cdav.php @@ -1,8 +1,12 @@ <?php -namespace Zotlabs\Widget; - +/** + * * Name: CalDAV/CardDAV tools + * * Description: A widget with various CalDAV and CardDAV tools + * * Requires: cdav + */ +namespace Zotlabs\Widget; class Cdav { @@ -164,7 +168,7 @@ class Cdav { 'uri' => $sabreabook['uri'], 'displayname' => $sabreabook['{DAV:}displayname'], 'id' => $sabreabook['id'] - + ]; } diff --git a/Zotlabs/Widget/Chatroom_list.php b/Zotlabs/Widget/Chatroom_list.php index e2aad0e05..d80e40bf9 100644 --- a/Zotlabs/Widget/Chatroom_list.php +++ b/Zotlabs/Widget/Chatroom_list.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Chatroom list + * * Description: A menu with links to your chatrooms + * * Requires: chat, channel, articles, cards, wiki + */ + namespace Zotlabs\Widget; class Chatroom_list { diff --git a/Zotlabs/Widget/Chatroom_members.php b/Zotlabs/Widget/Chatroom_members.php index 8ed77fb3c..0846192ce 100644 --- a/Zotlabs/Widget/Chatroom_members.php +++ b/Zotlabs/Widget/Chatroom_members.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Chatroom members + * * Description: A widget that shows members of a chatroom + * * Requires: chat + */ + namespace Zotlabs\Widget; class Chatroom_members { diff --git a/Zotlabs/Widget/Clock.php b/Zotlabs/Widget/Clock.php index b63b5f748..3b9751cc5 100644 --- a/Zotlabs/Widget/Clock.php +++ b/Zotlabs/Widget/Clock.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Clock + * * Description: A simple widget that shows the current time + */ + namespace Zotlabs\Widget; class Clock { diff --git a/Zotlabs/Widget/Collections.php b/Zotlabs/Widget/Collections.php deleted file mode 100644 index ad1a10f4b..000000000 --- a/Zotlabs/Widget/Collections.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -namespace Zotlabs\Widget; - -use Zotlabs\Lib\AccessList; - -class Collections { - - function widget($args) { - - if(argc() < 2) - // return; - - $mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation'); - switch($mode) { - case 'conversation': - $every = argv(0); - $each = argv(0); - $edit = true; - $current = $_REQUEST['gid']; - $abook_id = 0; - $wmode = 0; - break; - case 'connections': - $every = 'connections'; - $each = 'group'; - $edit = true; - $current = $_REQUEST['gid']; - $abook_id = 0; - $wmode = 0; - case 'groups': - $every = 'connections'; - $each = argv(0); - $edit = false; - $current = intval(argv(1)); - $abook_id = 0; - $wmode = 1; - break; - case 'abook': - $every = 'connections'; - $each = 'group'; - $edit = false; - $current = 0; - $abook_id = \App::$poi['abook_xchan']; - $wmode = 1; - break; - default: - return ''; - break; - } - - return AccessList::widget($every, $each, $edit, $current, $abook_id, $wmode); - } -} diff --git a/Zotlabs/Widget/Common_friends.php b/Zotlabs/Widget/Common_friends.php index a67b9312c..6024f82f5 100644 --- a/Zotlabs/Widget/Common_friends.php +++ b/Zotlabs/Widget/Common_friends.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Common friends + * * Description: Display common friends to visitors + * * Requires: channel, articles, cards, wiki + */ + namespace Zotlabs\Widget; require_once('include/contact_widgets.php'); @@ -8,7 +14,7 @@ class Common_friends { function widget($arr) { - if((! \App::$profile['profile_uid']) + if((! \App::$profile['profile_uid']) || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_contacts'))) { return ''; } diff --git a/Zotlabs/Widget/Cover_photo.php b/Zotlabs/Widget/Cover_photo.php index 97323ea8c..11d9c4715 100644 --- a/Zotlabs/Widget/Cover_photo.php +++ b/Zotlabs/Widget/Cover_photo.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Cover photo + * * Description: Display a cover photo in the banner region + * * Requires: disabled_for_pdledit_gui + */ + namespace Zotlabs\Widget; class Cover_photo { diff --git a/Zotlabs/Widget/Design_tools.php b/Zotlabs/Widget/Design_tools.php index a15c0c98d..0f94577d8 100644 --- a/Zotlabs/Widget/Design_tools.php +++ b/Zotlabs/Widget/Design_tools.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Design tools + * * Description: Links to useful tools for webpages + * * Requires: webpages + */ + namespace Zotlabs\Widget; class Design_tools { @@ -11,4 +17,4 @@ class Design_tools { return EMPTY_STR; } -}
\ No newline at end of file +} diff --git a/Zotlabs/Widget/Dirsort.php b/Zotlabs/Widget/Dirsort.php index 2fb38b7df..569782bb9 100644 --- a/Zotlabs/Widget/Dirsort.php +++ b/Zotlabs/Widget/Dirsort.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Dirsort + * * Description: Various options to provide different vies of the directory + * * Requires: directory + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Libzotdir; diff --git a/Zotlabs/Widget/Dirtags.php b/Zotlabs/Widget/Dirtags.php index 246c47dde..183c2f20f 100644 --- a/Zotlabs/Widget/Dirtags.php +++ b/Zotlabs/Widget/Dirtags.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Directory tags + * * Description: Show directory tags in a cloud + * * Requires: directory + */ + namespace Zotlabs\Widget; class Dirtags { diff --git a/Zotlabs/Widget/Eventstools.php b/Zotlabs/Widget/Eventstools.php deleted file mode 100644 index 7efd3f72e..000000000 --- a/Zotlabs/Widget/Eventstools.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -namespace Zotlabs\Widget; - -class Eventstools { - - function widget($arr) { - - if(! local_channel()) - return; - - return replace_macros(get_markup_template('events_tools_side.tpl'), array( - '$title' => t('Events Tools'), - '$export' => t('Export Calendar'), - '$import' => t('Import Calendar'), - '$submit' => t('Submit') - )); - } -} diff --git a/Zotlabs/Widget/Filer.php b/Zotlabs/Widget/Filer.php index 5d6f96a87..6c5ac47a9 100644 --- a/Zotlabs/Widget/Filer.php +++ b/Zotlabs/Widget/Filer.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Saved folders + * * Description: A menu containing saved folders + * * Requires: network + */ + namespace Zotlabs\Widget; require_once('include/contact_widgets.php'); @@ -10,7 +16,6 @@ class Filer { if(! local_channel()) return ''; - $selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : ''); $terms = array(); diff --git a/Zotlabs/Widget/Findpeople.php b/Zotlabs/Widget/Findpeople.php index f450b96ae..45d62bb7f 100644 --- a/Zotlabs/Widget/Findpeople.php +++ b/Zotlabs/Widget/Findpeople.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Find channels + * * Description: A simple form to search for channels in the directory + */ + namespace Zotlabs\Widget; require_once('include/contact_widgets.php'); diff --git a/Zotlabs/Widget/Follow.php b/Zotlabs/Widget/Follow.php index c4aecc8e1..2a0abb027 100644 --- a/Zotlabs/Widget/Follow.php +++ b/Zotlabs/Widget/Follow.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Follow + * * Description: A simple form which allows you to enter an address and send a follow request + */ + namespace Zotlabs\Widget; @@ -24,7 +29,7 @@ class Follow { else { $abook_usage_message = ''; } - + return replace_macros(get_markup_template('follow.tpl'),array( '$connect' => t('Add New Connection'), '$desc' => t('Enter channel address'), diff --git a/Zotlabs/Widget/Forums.php b/Zotlabs/Widget/Forums.php index 2af7347f1..c40556273 100644 --- a/Zotlabs/Widget/Forums.php +++ b/Zotlabs/Widget/Forums.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Forums + * * Description: A list of forum channels with unseen item counts + */ + namespace Zotlabs\Widget; class Forums { @@ -21,35 +26,7 @@ class Forums { $unseen = 1; $perms_sql = item_permissions_sql(local_channel()) . item_normal(); - - $xf = false; - - $x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = '0'", - intval(local_channel()) - ); - if($x1) { - $xc = ids_to_querystr($x1,'xchan',true); - - $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ", - intval(local_channel()) - ); - - if($x2) { - $xf = ids_to_querystr($x2,'xchan',true); - - // private forums - $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") and not xchan in (" . $xf . ") ", - intval(local_channel()) - ); - if($x3) { - $xf = ids_to_querystr(array_merge($x2,$x3),'xchan',true); - } - } - } - - $sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 "); - - + $sql_extra = " and xchan_pubforum = 1 "; $r1 = q("select abook_id, xchan_hash, 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 $sql_extra order by xchan_name $limit ", intval(local_channel()) diff --git a/Zotlabs/Widget/Fullprofile.php b/Zotlabs/Widget/Fullprofile.php index e8ed13811..edff88e31 100644 --- a/Zotlabs/Widget/Fullprofile.php +++ b/Zotlabs/Widget/Fullprofile.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Full profile + * * Description: Profile card with extended profile info + * * Requires: channel, articles, cards, wiki, cloud, photos + */ + namespace Zotlabs\Widget; class Fullprofile { diff --git a/Zotlabs/Widget/Helpindex.php b/Zotlabs/Widget/Helpindex.php index 6c8748194..fbcd8c8b2 100644 --- a/Zotlabs/Widget/Helpindex.php +++ b/Zotlabs/Widget/Helpindex.php @@ -1,11 +1,18 @@ <?php +/** + * * Name: Help index + * * Description: Help pages index + */ + namespace Zotlabs\Widget; class Helpindex { function widget($arr) { + require_once('include/help.php'); + $o .= '<div class="widget">'; $level_0 = get_help_content('sitetoc'); diff --git a/Zotlabs/Widget/Hq_controls.php b/Zotlabs/Widget/Hq_controls.php index 91335fd76..7b1fe817d 100644 --- a/Zotlabs/Widget/Hq_controls.php +++ b/Zotlabs/Widget/Hq_controls.php @@ -1,5 +1,12 @@ <?php +/** + * * Name: HQ Controls + * * Description: Control buttons for the HQ module + * * Author: Mario Vavti + * * Requires: hq + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Apps; diff --git a/Zotlabs/Widget/Item.php b/Zotlabs/Widget/Item.php index 273d5649c..9fd703dfe 100644 --- a/Zotlabs/Widget/Item.php +++ b/Zotlabs/Widget/Item.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Item + * * Description: Display a webpage by title or mid, + * * Requires: channel, articles, cards, wiki + */ + namespace Zotlabs\Widget; require_once('include/security.php'); @@ -35,7 +41,7 @@ class Item { ); } else { - $r = q("select * from item where mid = '%s' and uid = %d and item_type = " + $r = q("select * from item where mid = '%s' and uid = %d and item_type = " . intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1", dbesc($arr['mid']), intval($channel_id) diff --git a/Zotlabs/Widget/Menu_preview.php b/Zotlabs/Widget/Menu_preview.php index 51218f6cf..ddeb4d12c 100644 --- a/Zotlabs/Widget/Menu_preview.php +++ b/Zotlabs/Widget/Menu_preview.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Menu preview + * * Description: Shows a preview of the current menu + * * Requires: mitem + */ + namespace Zotlabs\Widget; require_once('include/menu.php'); diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php index 71f4bd310..d045ae85b 100644 --- a/Zotlabs/Widget/Messages.php +++ b/Zotlabs/Widget/Messages.php @@ -1,5 +1,13 @@ <?php +/** + * * Name: HQ Messages + * * Description: Quick access to messages, direct messages, starred messages (if enabled) and notifications + * * Author: Mario Vavti + * * Requires: hq + */ + + namespace Zotlabs\Widget; use App; @@ -17,8 +25,8 @@ class Messages { $tpl = get_markup_template('messages_widget.tpl'); $o = replace_macros($tpl, [ - '$entries' => $page['entries'], - '$offset' => $page['offset'], + '$entries' => $page['entries'] ?? [], + '$offset' => $page['offset'] ?? 0, '$feature_star' => feature_enabled(local_channel(), 'star_posts'), '$strings' => [ 'messages_title' => t('Public and restricted messages'), @@ -37,11 +45,11 @@ class Messages { if (!local_channel()) return; - if ($options['offset'] == -1) { + if (isset($options['offset']) && $options['offset'] == -1) { return; } - if ($options['type'] == 'notification') { + if (isset($options['type']) && $options['type'] == 'notification') { return self::get_notices_page($options); } @@ -103,13 +111,20 @@ class Messages { if (!$summary) { $summary = $item['summary']; } + if (!$summary) { - $summary = htmlentities(html2plain(bbcode($item['body'], ['drop_media' => true]), 75, true), ENT_QUOTES, 'UTF-8', false); + $summary = html2plain(bbcode($item['body'], ['drop_media' => true]), 75, true); + if ($summary) { + $summary = htmlentities($summary, ENT_QUOTES, 'UTF-8', false); + } } + if (!$summary) { $summary = '...'; } - $summary = substr_words($summary, 68); + else { + $summary = substr_words($summary, 68); + } switch(intval($item['item_private'])) { case 1: diff --git a/Zotlabs/Widget/Newmember.php b/Zotlabs/Widget/Newmember.php index 224f7a8a2..70a858fb0 100644 --- a/Zotlabs/Widget/Newmember.php +++ b/Zotlabs/Widget/Newmember.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: New member + * * Description: Display useful links for new members to help them get started + */ + namespace Zotlabs\Widget; class Newmember { @@ -29,7 +34,7 @@ class Newmember { $options = [ t('Profile Creation'), - [ + [ 'profile_photo' => t('Upload profile photo'), 'cover_photo' => t('Upload cover photo'), 'profiles' => t('Edit your profile'), @@ -84,4 +89,4 @@ class Newmember { } - + diff --git a/Zotlabs/Widget/Notes.php b/Zotlabs/Widget/Notes.php index 659b62390..2e8e04e93 100644 --- a/Zotlabs/Widget/Notes.php +++ b/Zotlabs/Widget/Notes.php @@ -1,5 +1,13 @@ <?php +/** + * * Name: Notes + * * Description: A simple notes widget, requires the Notes App + * * Author: Mike Macgirvin + * * Author: Mario Vavti + * * Maintainer: Mario Vavti + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Apps; @@ -33,9 +41,6 @@ class Notes { ] )); - - - return $o; } } diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php index a818ae40a..0e02d5cc1 100644 --- a/Zotlabs/Widget/Notifications.php +++ b/Zotlabs/Widget/Notifications.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Notifications + * * Description: Shows all kind of notifications + * * Author: Mario Vavti + */ + namespace Zotlabs\Widget; class Notifications { diff --git a/Zotlabs/Widget/Permcats.php b/Zotlabs/Widget/Permcats.php index a908f6220..9226b3c71 100644 --- a/Zotlabs/Widget/Permcats.php +++ b/Zotlabs/Widget/Permcats.php @@ -1,5 +1,12 @@ <?php +/** + * * Name: Contact roles + * * Description: Display a menu with all defined contact roles and contacts which are assigned to the selected role + * * Author: Mario Vavti + * * Requires: permcats + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Permcat; diff --git a/Zotlabs/Widget/Photo.php b/Zotlabs/Widget/Photo.php index 10031f028..5ad6c604c 100644 --- a/Zotlabs/Widget/Photo.php +++ b/Zotlabs/Widget/Photo.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Photo + * * Description: Displays a single photo + */ + + namespace Zotlabs\Widget; diff --git a/Zotlabs/Widget/Photo_albums.php b/Zotlabs/Widget/Photo_albums.php index 6df8ddf3c..2ce916048 100644 --- a/Zotlabs/Widget/Photo_albums.php +++ b/Zotlabs/Widget/Photo_albums.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Photo albums + * * Description: Displays a menu with links to existing photo albums + * * Requires: photos + */ + namespace Zotlabs\Widget; require_once('include/photos.php'); diff --git a/Zotlabs/Widget/Photo_rand.php b/Zotlabs/Widget/Photo_rand.php index af80a3b9f..cfe026b19 100644 --- a/Zotlabs/Widget/Photo_rand.php +++ b/Zotlabs/Widget/Photo_rand.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Random photo + * * Description: Display a random photo + */ + namespace Zotlabs\Widget; require_once('include/photos.php'); @@ -40,15 +45,15 @@ class Photo_rand { if(strpos($url, 'http') !== 0) return ''; - + if(array_key_exists('style', $arr) && isset($arr['style'])) $style = $arr['style']; - + // ensure they can't sneak in an eval(js) function if(strpos($style,'(') !== false) return ''; - + $url = zid($url); $o = '<div class="widget">'; diff --git a/Zotlabs/Widget/Pinned.php b/Zotlabs/Widget/Pinned.php index 66d06bbd3..83036e98c 100644 --- a/Zotlabs/Widget/Pinned.php +++ b/Zotlabs/Widget/Pinned.php @@ -1,11 +1,14 @@ <?php namespace Zotlabs\Widget; -/* - * Show pinned content - * +/** + * * Name: Pinned items + * * Description: Display pinned items + * * Author: Max Kostikov + * * Requires: disabled_for_pdledit_gui */ + class Pinned { private $allowed_types = 0; diff --git a/Zotlabs/Widget/Portfolio.php b/Zotlabs/Widget/Portfolio.php index 0cd043246..a06f56e30 100644 --- a/Zotlabs/Widget/Portfolio.php +++ b/Zotlabs/Widget/Portfolio.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Portfolio + * * Description: Display a photo album in a portfolio style + * * Requires: channel, articles, cards, wiki + */ + namespace Zotlabs\Widget; require_once('include/attach.php'); @@ -8,11 +14,9 @@ class Portfolio { function widget($args) { - $owner_uid = \App::$profile_uid; $sql_extra = permissions_sql($owner_uid); - if(! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage')) return ''; @@ -112,7 +116,7 @@ class Portfolio { '$upload_form' => $upload_form, '$usage' => $usage_message )); - + return $o; } } diff --git a/Zotlabs/Widget/Privacygroups.php b/Zotlabs/Widget/Privacygroups.php index a6b16c552..62f343ea6 100644 --- a/Zotlabs/Widget/Privacygroups.php +++ b/Zotlabs/Widget/Privacygroups.php @@ -1,5 +1,12 @@ <?php +/** + * * Name: Privacy Groups + * * Description: Display a menu with links to existing privacy groups + * * Requires: group + */ + + namespace Zotlabs\Widget; use Zotlabs\Lib\AccessList; diff --git a/Zotlabs/Widget/Profile.php b/Zotlabs/Widget/Profile.php index 0e5444a56..a0bb1a66a 100644 --- a/Zotlabs/Widget/Profile.php +++ b/Zotlabs/Widget/Profile.php @@ -1,5 +1,12 @@ <?php +/** + * * Name: Profile + * * Description: Your profile card + * * Requires: channel, articles, cards, wiki, cloud, photos + */ + + namespace Zotlabs\Widget; use App; diff --git a/Zotlabs/Widget/Pubsites.php b/Zotlabs/Widget/Pubsites.php deleted file mode 100644 index 958ba68c2..000000000 --- a/Zotlabs/Widget/Pubsites.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace Zotlabs\Widget; - -class Pubsites { - - // used by site ratings pages to provide a return link - - function widget($arr) { - if(\App::$poi) - return; - return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>'; - } -} - - diff --git a/Zotlabs/Widget/Pubtagcloud.php b/Zotlabs/Widget/Pubtagcloud.php index 826e3e6ae..db7ea02e7 100644 --- a/Zotlabs/Widget/Pubtagcloud.php +++ b/Zotlabs/Widget/Pubtagcloud.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Public stream tags + * * Description: Display public stream tags in a cloud + */ + namespace Zotlabs\Widget; class Pubtagcloud { diff --git a/Zotlabs/Widget/Random_block.php b/Zotlabs/Widget/Random_block.php index 465a51f97..9052bea03 100644 --- a/Zotlabs/Widget/Random_block.php +++ b/Zotlabs/Widget/Random_block.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Random block + * * Description: Display a random block item + */ + namespace Zotlabs\Widget; class Random_block { diff --git a/Zotlabs/Widget/Rating.php b/Zotlabs/Widget/Rating.php index 5e09f457b..20c27ff1c 100644 --- a/Zotlabs/Widget/Rating.php +++ b/Zotlabs/Widget/Rating.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Rating + * * Description: Deprecated rating tool + * * Requires: disabled_for_pdledit_gui + */ + namespace Zotlabs\Widget; class Rating { diff --git a/Zotlabs/Widget/Savedsearch.php b/Zotlabs/Widget/Savedsearch.php index 378c27139..660fd6d81 100644 --- a/Zotlabs/Widget/Savedsearch.php +++ b/Zotlabs/Widget/Savedsearch.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Saved searches + * * Description: A search form which also displays saved searches if the feature is enabled + * * Requires: network + */ + namespace Zotlabs\Widget; class Savedsearch { diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php index 4d0f1d2dd..ef269d84b 100644 --- a/Zotlabs/Widget/Settings_menu.php +++ b/Zotlabs/Widget/Settings_menu.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Settings menu + * * Description: Display the channel settings menu + */ + namespace Zotlabs\Widget; class Settings_menu { diff --git a/Zotlabs/Widget/Shortprofile.php b/Zotlabs/Widget/Shortprofile.php deleted file mode 100644 index 9c2a46e75..000000000 --- a/Zotlabs/Widget/Shortprofile.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace Zotlabs\Widget; - -class Shortprofile { - - function widget($arr) { - - if(! \App::$profile['profile_uid']) - return; - - $block = observer_prohibited(); - - return profile_sidebar(\App::$profile, $block, true, true); - } - -} - diff --git a/Zotlabs/Widget/Sitesearch.php b/Zotlabs/Widget/Sitesearch.php index b3a25d76a..a5f1a5935 100644 --- a/Zotlabs/Widget/Sitesearch.php +++ b/Zotlabs/Widget/Sitesearch.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Search + * * Description: A search form + * * Requires: search, network, channel + */ + namespace Zotlabs\Widget; diff --git a/Zotlabs/Widget/Suggestedchats.php b/Zotlabs/Widget/Suggestedchats.php index 7df42944d..75df0c9e6 100644 --- a/Zotlabs/Widget/Suggestedchats.php +++ b/Zotlabs/Widget/Suggestedchats.php @@ -1,14 +1,18 @@ <?php +/** + * * Name: Suggested chats + * * Description: A menu with chatroom suggestions + * * Requires: disabled_due_to_reasons + */ + + namespace Zotlabs\Widget; class Suggestedchats { function widget($arr) { - if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat')) - return ''; - // There are reports that this tool does not ever remove chatrooms on dead sites, // and also will happily link to private chats which you cannot enter. // For those reasons, it will be disabled until somebody decides it's worth diff --git a/Zotlabs/Widget/Suggestions.php b/Zotlabs/Widget/Suggestions.php index b4f384e9d..e7d23bda4 100644 --- a/Zotlabs/Widget/Suggestions.php +++ b/Zotlabs/Widget/Suggestions.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Suggestions + * * Description: Display suggestions for new contacts + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\Apps; @@ -12,7 +17,7 @@ class Suggestions { function widget($arr) { - if((! local_channel()) || (! Apps::system_app_installed(local_channel(), 'Suggest Channels'))) + if(! local_channel()) return EMPTY_STR; $r = suggestion_query(local_channel(),get_observer_hash(),0,20); @@ -23,14 +28,14 @@ class Suggestions { $arr = array(); - // Get two random entries from the top 20 returned. + // Get four random entries from the top 20 returned. // We'll grab the first one and the one immediately following. // This will throw some entropy intot he situation so you won't // be looking at the same two mug shots every time the widget runs - $index = ((count($r) > 2) ? mt_rand(0,count($r) - 2) : 0); + $index = ((count($r) > 4) ? mt_rand(0,count($r) - 4) : 0); - for($x = $index; $x <= ($index+1); $x ++) { + for($x = $index; $x <= ($index+3); $x ++) { $rr = $r[$x]; if(! $rr['xchan_url']) break; diff --git a/Zotlabs/Widget/Tagcloud.php b/Zotlabs/Widget/Tagcloud.php index f79bd59ad..00456f24f 100644 --- a/Zotlabs/Widget/Tagcloud.php +++ b/Zotlabs/Widget/Tagcloud.php @@ -2,6 +2,11 @@ namespace Zotlabs\Widget; +/** + * * Name: Tag cloud + * * Description: Display hashtags of your network items in a cloud + * * Requires: network, hq + */ class Tagcloud { diff --git a/Zotlabs/Widget/Tagcloud_wall.php b/Zotlabs/Widget/Tagcloud_wall.php index 7cff6ce09..20def4ab1 100644 --- a/Zotlabs/Widget/Tagcloud_wall.php +++ b/Zotlabs/Widget/Tagcloud_wall.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Tag cloud wall + * * Description: Display hashtags of your channel wall items in a cloud if the feature is enabled + * * Requires: channel + */ + namespace Zotlabs\Widget; class Tagcloud_wall { diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php index 56342bd17..5ecfd5a27 100644 --- a/Zotlabs/Widget/Tasklist.php +++ b/Zotlabs/Widget/Tasklist.php @@ -1,8 +1,11 @@ <?php -namespace Zotlabs\Widget; +/** + * * Name: Task list + * * Description: Simple task list mangager + */ -require_once('include/event.php'); +namespace Zotlabs\Widget; class Tasklist { @@ -20,7 +23,7 @@ class Tasklist { } </script>'; - $o .= '<div class="widget">' . '<h3>' . t('Tasks') . '</h3><div class="tasklist-tasks">'; + $o .= '<div class="widget">' . '<h3>' . t('Tasks') . '</h3><div class="tasklist-tasks mb-1">'; $o .= '</div><form id="tasklist-new-form" action="" ><input class="form-control" id="tasklist-new-summary" type="text" name="summary" value="" /></form>'; $o .= '</div>'; return $o; diff --git a/Zotlabs/Widget/Tokens.php b/Zotlabs/Widget/Tokens.php index 8c31003fc..69452d628 100644 --- a/Zotlabs/Widget/Tokens.php +++ b/Zotlabs/Widget/Tokens.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Tokens + * * Description: Display a menu with links to existing guest access tokens + * * Requires: tokens + */ + namespace Zotlabs\Widget; class Tokens { diff --git a/Zotlabs/Widget/Vcard.php b/Zotlabs/Widget/Vcard.php index cab05dfdd..25bb8592c 100644 --- a/Zotlabs/Widget/Vcard.php +++ b/Zotlabs/Widget/Vcard.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Vcard + * * Description: Your default profile card + */ + namespace Zotlabs\Widget; class Vcard { diff --git a/Zotlabs/Widget/Website_portation_tools.php b/Zotlabs/Widget/Website_portation_tools.php index 1cf3bb78a..61fe48169 100644 --- a/Zotlabs/Widget/Website_portation_tools.php +++ b/Zotlabs/Widget/Website_portation_tools.php @@ -1,7 +1,12 @@ <?php -namespace Zotlabs\Widget; +/** + * * Name: Website import/export + * * Description: Tools to import and export websites + * * Requires: website + */ +namespace Zotlabs\Widget; class Website_portation_tools { diff --git a/Zotlabs/Widget/Wiki_list.php b/Zotlabs/Widget/Wiki_list.php index 64c988ee7..217ab8706 100644 --- a/Zotlabs/Widget/Wiki_list.php +++ b/Zotlabs/Widget/Wiki_list.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Wiki list + * * Description: A list of existing wikis + */ + namespace Zotlabs\Widget; class Wiki_list { diff --git a/Zotlabs/Widget/Wiki_page_history.php b/Zotlabs/Widget/Wiki_page_history.php index dbb322dc3..3c9f5ed1a 100644 --- a/Zotlabs/Widget/Wiki_page_history.php +++ b/Zotlabs/Widget/Wiki_page_history.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Wiki page history + * * Description: History of an existing wiki page + * * Requires: wiki + */ + namespace Zotlabs\Widget; class Wiki_page_history { @@ -10,7 +16,7 @@ class Wiki_page_history { $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : ''); $pageHistory = \Zotlabs\Lib\NativeWikiPage::page_history([ - 'channel_id' => \App::$profile_uid, + 'channel_id' => \App::$profile_uid, 'observer_hash' => get_observer_hash(), 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php index dee0a2229..ece712334 100644 --- a/Zotlabs/Widget/Wiki_pages.php +++ b/Zotlabs/Widget/Wiki_pages.php @@ -1,5 +1,11 @@ <?php +/** + * * Name: Wiki pages + * * Description: A list of existing pages of a wiki + * * Requires: wiki + */ + namespace Zotlabs\Widget; use Zotlabs\Lib\NativeWiki; @@ -34,7 +40,7 @@ class Wiki_pages { '$addnew' => t('Add new page'), '$typelock' => $typelock, '$lockedtype' => $w['mimeType'], - '$mimetype' => mimetype_select(0,$w['mimeType'], + '$mimetype' => mimetype_select(0,$w['mimeType'], [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]), '$pageName' => array('missingPageName', 'Create Page' , $pageName), '$refresh' => $arr['refresh'], @@ -91,7 +97,7 @@ class Wiki_pages { '$addnew' => t('Add new page'), '$typelock' => $typelock, '$lockedtype' => $w['mimeType'], - '$mimetype' => mimetype_select(0,$w['mimeType'], + '$mimetype' => mimetype_select(0,$w['mimeType'], [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]), '$pageName' => array('pageName', t('Page name')), '$refresh' => $arr['refresh'], diff --git a/Zotlabs/Widget/Zcard.php b/Zotlabs/Widget/Zcard.php index 12e53eaab..35362c50e 100644 --- a/Zotlabs/Widget/Zcard.php +++ b/Zotlabs/Widget/Zcard.php @@ -1,5 +1,10 @@ <?php +/** + * * Name: Zcard + * * Description: Your default profile card including your cover photo + */ + namespace Zotlabs\Widget; class Zcard { |