diff options
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 1 | ||||
-rw-r--r-- | Zotlabs/Module/Request.php | 72 | ||||
-rw-r--r-- | boot.php | 2 | ||||
-rw-r--r-- | include/items.php | 71 | ||||
-rw-r--r-- | include/security.php | 20 | ||||
-rw-r--r-- | view/js/main.js | 46 | ||||
-rw-r--r-- | view/tpl/conv_item.tpl | 6 | ||||
-rw-r--r-- | view/tpl/notifications_widget.tpl | 2 |
8 files changed, 150 insertions, 70 deletions
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index ac9da29a3..f41ab7705 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -382,6 +382,7 @@ class ThreadItem { 'folders' => $body['folders'], 'text' => strip_tags($body['html']), 'id' => $this->get_id(), + 'parent' => intval($item['parent']), 'mid' => $midb64, 'mids' => $json_mids, 'parent' => $item['parent'], diff --git a/Zotlabs/Module/Request.php b/Zotlabs/Module/Request.php index 660537812..811350205 100644 --- a/Zotlabs/Module/Request.php +++ b/Zotlabs/Module/Request.php @@ -28,13 +28,17 @@ class Request extends Controller private function processSubthreadRequest() : string { $mid = $_GET['mid']; - $items = items_by_thr_parent($mid); + $parent = intval($_GET['parent']); + $module = strip_tags($_GET['module']); + + $items = items_by_thr_parent($mid, $parent); xchan_query($items,true,(($sys_item) ? local_channel() : 0)); + $items = fetch_post_tags($items,true); // $items = conv_sort($items,'created'); - $ret['html'] = conversation($items, 'network', true, 'r_preview'); + $ret['html'] = conversation($items, $module, true, 'r_preview'); json_return_and_die($ret); } @@ -43,7 +47,7 @@ class Request extends Controller { if (!local_channel()) { - killme(); + // killme(); } if ($_GET['verb'] === 'comment') { @@ -56,28 +60,60 @@ class Request extends Controller killme(); } + $parent = intval($_GET['parent']); $mid = strip_tags($_GET['mid']); - $hash = get_observer_hash(); + + $observer_hash = get_observer_hash(); $item_normal = item_normal(); - $r = q("SELECT xchan_hash, xchan_name as name, xchan_url as url, xchan_photo_s as photo FROM item - LEFT JOIN xchan ON author_xchan = xchan_hash - WHERE uid = %d - AND thr_parent = '%s' - AND verb = '%s' - AND item_thread_top = 0 - $item_normal", - intval(local_channel()), - dbesc($mid), - dbesc($verb) - ); + if (local_channel()) { + $r = q("SELECT xchan_hash, xchan_name as name, xchan_url as url, xchan_photo_s as photo FROM item + LEFT JOIN xchan ON author_xchan = xchan_hash + WHERE uid = %d + AND thr_parent = '%s' + AND verb = '%s' + AND item_thread_top = 0 + $item_normal + ORDER BY item.created", + intval(local_channel()), + dbesc($mid), + dbesc($verb) + ); + } + + if (!$r) { + $sys = get_sys_channel(); + $sql_extra = item_permissions_sql(0, $observer_hash); + + $r = q("SELECT xchan_hash, xchan_name as name, xchan_url as url, xchan_photo_s as photo FROM item + LEFT JOIN xchan ON author_xchan = xchan_hash + WHERE + -- This covers /channel/name -- This covers /pubstream + ((item.thr_parent = '%s' $sql_extra) OR (item.thr_parent = '%s' AND item.uid = %d)) + AND parent = %d + AND verb = '%s' + AND item_thread_top = 0 + $item_normal + ORDER BY item.created", + dbesc($mid), + dbesc($mid), + intval($sys['channel_id']), + intval($parent), + dbesc($verb) + ); + } $ret = [ - 'result' => $r, - 'action' => (($verb === 'Announce') ? 'jotShare' : 'dolike'), - 'action_label' => ((find_xchan_in_array($hash, $r)) ? t('- Remove yours') : t('+ Add yours')) + 'result' => $r ]; + + // TODO: check permission to like + if ($observer_hash) { + $ret['action'] = (($verb === 'Announce') ? 'jotShare' : 'dolike'); + $ret['action_label'] = ((find_xchan_in_array($observer_hash, $r)) ? t('- Remove yours') : t('+ Add yours')); + } + json_return_and_die($ret); } @@ -69,7 +69,7 @@ require_once('include/security.php'); define('PLATFORM_NAME', 'hubzilla'); -define('STD_VERSION', '10.3.5+lazy'); +define('STD_VERSION', '10.3.6+lazy'); define('ZOT_REVISION', '6.0'); define('DB_UPDATE_VERSION', 1263); diff --git a/include/items.php b/include/items.php index 617518a6b..87921b2b2 100644 --- a/include/items.php +++ b/include/items.php @@ -5431,29 +5431,62 @@ function items_by_parent_ids($ids, $sql_extra = '') { return $ret; } -function items_by_thr_parent($mid, $sql_extra = '') { +function items_by_thr_parent($mid, $parent, $sql_extra = '') { $item_normal = item_normal(); $item_normal_c = str_replace('item.', 'c.', $item_normal); $activity_sql = item_activity_sql('c'); - $ret = q( - "SELECT item.*, - $activity_sql - FROM item - LEFT JOIN item c - ON c.parent = item.parent - AND c.item_thread_top = 0 - AND c.thr_parent = item.mid - $item_normal_c - WHERE item.thr_parent = '%s' - AND item.uid = %d - AND item.verb NOT IN ('Like', 'Dislike', 'Announce') - AND item.item_thread_top = 0 - $item_normal - GROUP BY item.id", - dbesc($mid), - intval(local_channel()) - ); + + if (local_channel()) { + $ret = q( + "SELECT item.*, + $activity_sql + FROM item + LEFT JOIN item c + ON c.parent = item.parent + AND c.item_thread_top = 0 + AND c.thr_parent = item.mid + $item_normal_c + WHERE item.thr_parent = '%s' + AND item.uid = %d + AND item.verb NOT IN ('Like', 'Dislike', 'Announce') + AND item.item_thread_top = 0 + $item_normal + GROUP BY item.id + ORDER BY item.created", + dbesc($mid), + intval(local_channel()) + ); + } + + if (!$ret) { + $sys = get_sys_channel(); + $observer_hash = get_observer_hash(); + $sql_extra = item_permissions_sql(0, $observer_hash); + + $ret = q( + "SELECT item.*, + $activity_sql + FROM item + LEFT JOIN item c ON c.parent = item.parent + AND c.item_thread_top = 0 + AND c.thr_parent = item.mid + $item_normal_c + WHERE + -- This covers /channel/name -- This covers /pubstream + ((item.thr_parent = '%s' $sql_extra) OR (item.thr_parent = '%s' AND item.uid = %d)) + AND item.parent = %d + AND item.verb NOT IN ('Like', 'Dislike', 'Announce') + AND item.item_thread_top = 0 + $item_normal + GROUP BY item.id + ORDER BY item.created", + dbesc($mid), + dbesc($mid), + intval($sys['channel_id']), + intval($parent) + ); + } return $ret; } diff --git a/include/security.php b/include/security.php index 2e0497498..8e13d4195 100644 --- a/include/security.php +++ b/include/security.php @@ -432,7 +432,7 @@ function item_permissions_sql($owner_id, $remote_observer = null) { * default permissions - anonymous user */ - $sql = " AND item_private = 0 "; + $sql = " AND item.item_private = 0 "; /** * Profile owner - everything is visible @@ -492,10 +492,10 @@ function item_permissions_sql($owner_id, $remote_observer = null) { $regexop = db_getfunc('REGEXP'); $sql = sprintf( - " AND ( author_xchan = '%s' OR owner_xchan = '%s' OR - (( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s') - AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 )) - )) OR ( item_private = 1 $scope )) + " AND ( item.author_xchan = '%s' OR item.owner_xchan = '%s' OR + (( NOT (item.deny_cid $regexop '%s' OR item.deny_gid $regexop '%s') + AND ( item.allow_cid $regexop '%s' OR item.allow_gid $regexop '%s' OR ( item.allow_cid = '' AND item.allow_gid = '' AND item.item_private = 0 )) + )) OR ( item.item_private = 1 $scope )) ", dbesc($observer), dbesc($observer), @@ -518,11 +518,11 @@ function item_permissions_sql($owner_id, $remote_observer = null) { function scopes_sql($uid, $observer) { - $str = " and ( public_policy = 'authenticated' "; + $str = " and ( item.public_policy = 'authenticated' "; if (!is_foreigner($observer)) - $str .= " or public_policy = 'network: red' "; + $str .= " or item.public_policy = 'network: red' "; if (local_channel()) - $str .= " or public_policy = 'site: " . App::get_hostname() . "' "; + $str .= " or item.public_policy = 'site: " . App::get_hostname() . "' "; $ab = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($observer), @@ -531,8 +531,8 @@ function scopes_sql($uid, $observer) { if (!$ab) return $str . " ) "; if ($ab[0]['abook_pending']) - $str .= " or public_policy = 'any connections' "; - $str .= " or public_policy = 'contacts' ) "; + $str .= " or item.public_policy = 'any connections' "; + $str .= " or item.public_policy = 'contacts' ) "; return $str; } diff --git a/view/js/main.js b/view/js/main.js index b54879e40..c927e8521 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -1266,40 +1266,51 @@ function justifyPhotosAjax(id) { $('#' + id).justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; }); } -function request(id, mid, verb) { +function request(id, mid, verb, parent) { + + const loading = document.getElementById('like-rotator-' + id); + loading.style.display = 'block'; if (verb === 'comment') { - fetch('/request?verb=' + verb + '&mid=' + mid) + + document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => { + el.classList.remove('item-highlight'); + }); + + document.getElementById('thread-wrapper-' + id).classList.add('item-highlight'); + + fetch('/request?verb=' + verb + '&mid=' + mid + '&parent=' + parent + '&module=' + module) .then(response => response.json()) .then(obj => { injectWithAnimation('sub-thread-wrapper-' + id, obj.html); updateRelativeTime('.autotime'); + loading.style.display = 'none'; }) .catch(error => { console.error('Error fetching data:', error); }); } else { - const modal = new bootstrap.Modal('#reactions'); - modal.show(); - - const modal_content = document.getElementById('reactions_body'); - modal_content.innerHTML = 'Loading...'; - - const modal_title = document.getElementById('reactions_title'); - modal_title.innerHTML = verb; - - const modal_action = document.getElementById('reactions_action'); - modal_action.innerHTML = ''; - - fetch('/request?verb=' + verb + '&mid=' + mid) + fetch('/request?verb=' + verb + '&mid=' + mid + '&parent=' + parent) .then(response => response.json()) .then(obj => { + const modal = new bootstrap.Modal('#reactions'); + const modal_content = document.getElementById('reactions_body'); + const modal_title = document.getElementById('reactions_title'); + const modal_action = document.getElementById('reactions_action'); + modal_action.style.display = 'none'; + modal_title.innerHTML = verb; modal_content.innerHTML = ''; - modal_action.innerHTML = '<a href="#" onclick="' + obj.action + '(' + id + ',\'' + verb + '\'); return false;">' + obj.action_label + '</a>'; + if (obj.action) { + modal_action.innerHTML = '<a href="#" onclick="' + obj.action + '(' + id + ',\'' + verb + '\'); return false;">' + obj.action_label + '</a>'; + modal_action.style.display = 'block'; + } obj.result.forEach(e => { modal_content.innerHTML += '<a href="' + e.url + '" class="list-group-item list-group-item-action border-0"><img src="' + e.photo + '" class="menu-img-1" loading="lazy"> ' + e.name + '</a>'; }); + + modal.show(); + loading.style.display = 'none'; }) .catch(error => { console.error('Error fetching data:', error); @@ -1328,7 +1339,8 @@ function injectWithAnimation(container, html) { ], { duration: 300, delay: i * 50, - fill: 'both' + fill: 'both', + easing: 'ease-out' }); }); } diff --git a/view/tpl/conv_item.tpl b/view/tpl/conv_item.tpl index 87d2d69d4..47983eb1b 100644 --- a/view/tpl/conv_item.tpl +++ b/view/tpl/conv_item.tpl @@ -110,13 +110,11 @@ <div class="p-2 wall-item-tools d-flex justify-content-between"> <div class="wall-item-tools-left hstack gap-1" id="wall-item-tools-left-{{$item.id}}"> {{foreach $item.responses as $verb=>$response}} - {{if $item.reactions_allowed || (!$item.reactions_allowed && $response.count)}} {{if !($verb == 'comment' && $item.toplevel)}} - <button type="button" title="{{$response.count}} {{$response.button.label}}" class="btn btn-sm btn-link{{if !$item.observer_activity.$verb}} link-secondary{{/if}} wall-item-{{$response.button.class}}"{{if $item.reactions_allowed}} onclick="request({{$item.id}}, '{{$item.rawmid}}', '{{$verb}}'); return false;"{{/if}} id="wall-item-{{$verb}}-{{$item.id}}"> + <button type="button" title="{{$response.count}} {{$response.button.label}}" class="btn btn-sm btn-link{{if !$item.observer_activity.$verb}} link-secondary{{/if}} wall-item-{{$response.button.class}}" onclick="request({{$item.id}}, '{{$item.rawmid}}', '{{$verb}}', {{$item.parent}}); return false;" id="wall-item-{{$verb}}-{{$item.id}}"> <i class="bi bi-{{$response.button.icon}} generic-icons"></i>{{if $response.count}}<span style="display: inline-block; margin-top: -.25rem;" class="align-top">{{$response.count}}</span>{{/if}} </button> {{/if}} - {{/if}} {{/foreach}} {{if $item.toplevel && $item.emojis && $item.reactions}} <div class=""> @@ -220,10 +218,10 @@ </div> </div> </div> + <div id="sub-thread-wrapper-{{$item.id}}"></div> {{if $item.toplevel}} {{foreach $item.children as $child}} {{include file="{{$child.template}}" item=$child}} - <div id="sub-thread-wrapper-{{$child.id}}"></div> {{/foreach}} {{/if}} {{if $item.comment}} diff --git a/view/tpl/notifications_widget.tpl b/view/tpl/notifications_widget.tpl index 2156c1f4c..0a64abd32 100644 --- a/view/tpl/notifications_widget.tpl +++ b/view/tpl/notifications_widget.tpl @@ -631,7 +631,7 @@ noNotifications.style.display = 'none'; notifications.style.display = 'block'; } else { - notificationsBtn.style.opacity = 0.5; + if (notificationsBtn) notificationsBtn.style.opacity = 0.5; if (navbarCollapse) navbarCollapse.classList.remove('show'); noNotifications.style.display = 'block'; notifications.style.display = 'none'; |