diff --git a/Zotlabs/Lib/ASCollection.php b/Zotlabs/Lib/ASCollection.php index 3e5795af8..4601fb26e 100644 --- a/Zotlabs/Lib/ASCollection.php +++ b/Zotlabs/Lib/ASCollection.php @@ -7,7 +7,7 @@ use Zotlabs\Lib\Activity; /** * Class for dealing with fetching ActivityStreams collections (ordered or unordered, normal or paged). - * Construct with the object url and an optional channel to sign the request. + * Construct with either an existing object or url and an optional channel to sign requests. * $direction is 0 (default) to fetch from the beginning, and 1 to fetch from the end and reverse order the resultant array. * An optional limit to the number of records returned may also be specified. * Use $class->get() to return an array of collection members. @@ -18,22 +18,26 @@ use Zotlabs\Lib\Activity; class ASCollection { - private $url = null; private $channel = null; private $nextpage = null; private $limit = 0; private $direction = 0; // 0 = forward, 1 = reverse private $data = []; - function __construct($url,$channel = null,$direction = 0, $limit = 0) { + function __construct($obj, $channel = null, $direction = 0, $limit = 0) { - $this->url = $url; $this->channel = $channel; $this->direction = $direction; $this->limit = $limit; - $data = Activity::fetch($url,$channel); + if (is_array($obj)) { + $data = $obj; + } + if (is_string($obj)) { + $data = Activity::fetch($obj,$channel); + } + if (! is_array($data)) { return; } diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 756ec5097..14b644110 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2,6 +2,7 @@ namespace Zotlabs\Lib; +use App; use Zotlabs\Web\HTTPSig; use Zotlabs\Access\Permissions; use Zotlabs\Access\PermissionRoles; @@ -180,14 +181,57 @@ class Activity { } } - static function encode_item_collection($items,$id,$type,$activitypub = false) { + static function paged_collection_init($total,$id, $type = 'OrderedCollection') { $ret = [ 'id' => z_root() . '/' . $id, 'type' => $type, - 'totalItems' => count($items), + 'totalItems' => $total, ]; + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $ret['first'] = z_root() . '/' . App::$query_string . '?page=1'; + $ret['last'] = z_root() . '/' . App::$query_string . '?page=' . $lastpage; + + return $ret; + + } + + + static function encode_item_collection($items,$id,$type,$activitypub = false,$total = 0) { + + if ($total > 100) { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type . 'Page', + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $stripped = preg_replace('/([&|\?]page=[0-9]*)/','',$id); + $stripped = rtrim($stripped,'/'); + + $ret['partOf'] = z_root() . '/' . $stripped; + + if (App::$pager['page'] < $lastpage) { + $ret['next'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) + 1); + } + if (App::$pager['page'] > 1) { + $ret['prev'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) - 1); + } + } + else { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + } + + if ($items) { $x = []; foreach ($items as $i) { @@ -213,13 +257,37 @@ class Activity { return $ret; } - static function encode_follow_collection($items,$id,$type,$extra = null) { + static function encode_follow_collection($items,$id,$type,$total = 0,$extra = null) { - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => count($items), - ]; + if ($total > 100) { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type . 'Page', + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $stripped = preg_replace('/([&|\?]page=[0-9]*)/','',$id); + $stripped = rtrim($stripped,'/'); + + $ret['partOf'] = z_root() . '/' . $stripped; + + if (App::$pager['page'] < $lastpage) { + $ret['next'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) + 1); + } + if (App::$pager['page'] > 1) { + $ret['prev'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) - 1); + } + } + else { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + } + if ($extra) { $ret = array_merge($ret,$extra); } diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 8b79d0af8..efa930879 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -492,7 +492,7 @@ class Connedit extends Controller { Libsync::build_sync_packet(0, [ 'abook' => [ 'abook_xchan' => $orig_record['abook_xchan'], 'entry_deleted' => true ] ] ); - notice( t('Connection has been removed.') . EOL ); + info( t('Connection has been removed.') . EOL ); if (x($_SESSION,'return_url')) { goaway(z_root() . '/' . $_SESSION['return_url']); } @@ -569,7 +569,7 @@ class Connedit extends Controller { 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), 'title' => t('Block (or Unblock) all communications with this connection'), - 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), + 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked') : ''), ), 'ignore' => array( @@ -577,7 +577,7 @@ class Connedit extends Controller { 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), - 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), + 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored') : ''), ), 'censor' => array( @@ -585,7 +585,7 @@ class Connedit extends Controller { 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor', 'sel' => (intval($contact['abook_censor']) ? 'active' : ''), 'title' => t('Censor (or Uncensor) images from this connection'), - 'info' => (intval($contact['abook_censor']) ? t('This connection is censored!') : ''), + 'info' => (intval($contact['abook_censor']) ? t('This connection is censored') : ''), ), 'archive' => array( @@ -593,7 +593,7 @@ class Connedit extends Controller { 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), - 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), + 'info' => (intval($contact['abook_archived']) ? t('This connection is archived') : ''), ), 'hide' => array( @@ -601,7 +601,7 @@ class Connedit extends Controller { 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), 'title' => t('Hide or Unhide this connection from your other connections'), - 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), + 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden') : ''), ), 'delete' => array( diff --git a/Zotlabs/Module/Followers.php b/Zotlabs/Module/Followers.php index 8102c0298..964df0d64 100644 --- a/Zotlabs/Module/Followers.php +++ b/Zotlabs/Module/Followers.php @@ -40,19 +40,38 @@ class Followers extends Controller { http_status_exit(403, 'Forbidden'); } - $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", + $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ", intval($channel['channel_id']), intval($channel['channel_id']), dbesc($channel['channel_hash']) ); - + if ($t) { + App::set_pager_total($t[0]['total']); + App::set_pager_itemspage(100); + } + + if(App::$pager['unset'] && intval($t[0]['total']) > 100) { + $ret = Activity::paged_collection_init($t[0]['total'],App::$query_string); + } + else { + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + + $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); + + $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); + } + if (ActivityStreams::is_as_request()) { $x = array_merge(['@context' => [ ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection')); + ]], $ret); $headers = []; diff --git a/Zotlabs/Module/Following.php b/Zotlabs/Module/Following.php index d622b7d37..8657e2552 100644 --- a/Zotlabs/Module/Following.php +++ b/Zotlabs/Module/Following.php @@ -38,11 +38,31 @@ class Following extends Controller { http_status_exit(403, 'Forbidden'); } - $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", + $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", intval($channel['channel_id']), intval($channel['channel_id']), dbesc($channel['channel_hash']) ); + + if ($t) { + App::set_pager_total($t[0]['total']); + App::set_pager_itemspage(100); + } + + if(App::$pager['unset'] && $t[0]['total'] > 100) { + $ret = Activity::paged_collection_init($t[0]['total'],App::$query_string); + } + else { + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + + $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); + + $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); + } if (ActivityStreams::is_as_request()) { @@ -50,7 +70,7 @@ class Following extends Controller { ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection')); + ]], $ret); $headers = []; $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; diff --git a/Zotlabs/Module/Outbox.php b/Zotlabs/Module/Outbox.php index 4f0a28d25..9ef1966a6 100644 --- a/Zotlabs/Module/Outbox.php +++ b/Zotlabs/Module/Outbox.php @@ -41,36 +41,61 @@ class Outbox extends Controller { $params['type'] = 'json'; $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0); $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0); - $params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0); - $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 60); $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc'); // unimplemented $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : ''); - $params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1); + $params['compat'] = 1; - - $items = items_fetch( - [ - 'wall' => '1', - 'datequery' => $params['end'], + + $total = items_fetch( + [ + 'total' => true, + 'wall' => '1', + 'datequery' => $params['end'], 'datequery2' => $params['begin'], - 'start' => intval($params['start']), - 'records' => intval($params['records']), - 'direction' => dbesc($params['direction']), - 'pages' => $params['pages'], - 'order' => dbesc('post'), - 'top' => $params['top'], + 'direction' => dbesc($params['direction']), + 'pages' => $params['pages'], + 'order' => dbesc('post'), + 'top' => $params['top'], 'cat' => $params['cat'], - 'compat' => $params['compat'] - ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module + 'compat' => $params['compat'] + ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module ); + if ($total) { + App::set_pager_total($total); + App::set_pager_itemspage(100); + } + + if(App::$pager['unset'] && $total > 100) { + $ret = Activity::paged_collection_init($total,App::$query_string); + } + else { + $items = items_fetch( + [ + 'wall' => '1', + 'datequery' => $params['end'], + 'datequery2' => $params['begin'], + 'records' => intval(App::$pager['itemspage']), + 'start' => intval(App::$pager['start']), + 'direction' => dbesc($params['direction']), + 'pages' => $params['pages'], + 'order' => dbesc('post'), + 'top' => $params['top'], + 'cat' => $params['cat'], + 'compat' => $params['compat'] + ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module + ); + + $ret = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection',true, $total); + } + if(ActivityStreams::is_as_request()) { $x = array_merge(['@context' => [ ACTIVITYSTREAMS_JSONLD_REV, 'https://w3id.org/security/v1', z_root() . ZOT_APSCHEMA_REV - ]], Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection',true)); + ]], $ret); $headers = []; $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; diff --git a/Zotlabs/Module/Stream.php b/Zotlabs/Module/Stream.php index 00675740e..53bc6f42b 100644 --- a/Zotlabs/Module/Stream.php +++ b/Zotlabs/Module/Stream.php @@ -120,7 +120,7 @@ class Stream extends Controller { if ($update) { killme(); } - notice( t('No such group') . EOL ); + notice( t('Access list not found') . EOL ); goaway(z_root() . '/stream'); } @@ -262,7 +262,7 @@ class Stream extends Controller { if ($x) { $title = replace_macros(get_markup_template("section_title.tpl"),array( - '$title' => t('Access list: ') . $x['gname'] + '$title' => sprintf( t('Access list: %s'), $x['gname']); )); } diff --git a/boot.php b/boot.php index 8da5a72e1..3251e7cea 100755 --- a/boot.php +++ b/boot.php @@ -936,6 +936,7 @@ class App { * pagination */ + self::$pager['unset'] = ((array_key_exists('page',$_REQUEST)) ? false : true); self::$pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1); self::$pager['itemspage'] = 60; self::$pager['start'] = (self::$pager['page'] * self::$pager['itemspage']) - self::$pager['itemspage']; diff --git a/include/items.php b/include/items.php index 1396e61a8..582385776 100644 --- a/include/items.php +++ b/include/items.php @@ -3987,7 +3987,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C intval($uid) ); if(! $r) { - $result['message'] = t('Privacy group not found.'); + $result['message'] = t('Access list not found.'); return $result; } @@ -4010,7 +4010,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) "; $x = AccessList::rec_byhash($uid,$r[0]['hash']); - $result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']); + $result['headline'] = sprintf( t('Access list: %s'),$x['gname']); } elseif($arr['cid'] && $uid) { @@ -4022,7 +4022,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) $item_normal ) "; $result['headline'] = sprintf( t('Connection: %s'),$r[0]['xchan_name']); } else { - $result['message'] = t('Connection not found.'); + $result['message'] = t('Channel not found.'); return $result; } } @@ -4061,9 +4061,11 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C // only setup pagination on initial page view $pager_sql = ''; } else { - $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20); - App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + if(! $arr['total']) { + $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + } } if (isset($arr['start']) && isset($arr['records'])) @@ -4112,6 +4114,18 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C // "New Item View" - show all items unthreaded in reverse created date order + if ($arr['total']) { + $items = q("SELECT count(item.id) AS total FROM item + WHERE $item_uids $item_restrict + $simple_update + $sql_extra $sql_nets $sql_extra3" + ); + if ($items) { + return intval($items[0]['total']); + } + return 0; + } + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE $item_uids $item_restrict $simple_update @@ -4119,12 +4133,12 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C ORDER BY item.received DESC $pager_sql" ); - require_once('include/items.php'); xchan_query($items); - $items = fetch_post_tags($items,true); - } else { + + } + else { // Normal conversation view diff --git a/view/js/main.js b/view/js/main.js index adeda7a93..16ecf0537 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -598,11 +598,11 @@ function notificationsUpdate(cached_data) { $.jGrowl.defaults.closerTemplate = '
[ ' + aStr.closeAll + ']
'; $(data.notice).each(function() { - $.jGrowl(this.message, { sticky: true, theme: 'notice' }); + $.jGrowl(this.message, { sticky: false, theme: 'notice', life: 10000 }); }); $(data.info).each(function(){ - $.jGrowl(this.message, { sticky: false, theme: 'info', life: 10000 }); + $.jGrowl(this.message, { sticky: false, theme: 'info' }); }); }); } diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index b89151858..5a16dba4e 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -799,12 +799,12 @@ nav .acpopup { /* popup notifications */ div.jGrowl div.notice { - background: #511919 url("../../../../images/icons/48/notice.png") no-repeat 5px center; + background: #aa3311 url("../../../../images/icons/48/notice.png") no-repeat 5px center; color: #ffffff; padding-left: 58px; } div.jGrowl div.info { - background: #364e59 url("../../../../images/icons/48/info.png") no-repeat 5px center; + background: #2244aa url("../../../../images/icons/48/info.png") no-repeat 5px center; color: #ffffff; padding-left: 58px; }