diff options
author | Hilmar R <u02@u29lx193> | 2021-01-22 01:38:43 +0100 |
---|---|---|
committer | Hilmar R <u02@u29lx193> | 2021-01-22 01:38:43 +0100 |
commit | 523765b968a5d94a98eee12854fc527d5abbc2e7 (patch) | |
tree | a71caba8943c674917821a4afd333eb39ac92b2e /Zotlabs | |
parent | 78f150cfbc1b713bfba3101fdc3f1fd624120637 (diff) | |
parent | 254e30bea173e350a24756cbd8cf4acdfe32933e (diff) | |
download | volse-hubzilla-523765b968a5d94a98eee12854fc527d5abbc2e7.tar.gz volse-hubzilla-523765b968a5d94a98eee12854fc527d5abbc2e7.tar.bz2 volse-hubzilla-523765b968a5d94a98eee12854fc527d5abbc2e7.zip |
Merge branch 'master' into air.5
Diffstat (limited to 'Zotlabs')
64 files changed, 2419 insertions, 1787 deletions
diff --git a/Zotlabs/Daemon/Checksites.php b/Zotlabs/Daemon/Checksites.php index a2081967a..3bcfdd7cf 100644 --- a/Zotlabs/Daemon/Checksites.php +++ b/Zotlabs/Daemon/Checksites.php @@ -2,8 +2,7 @@ namespace Zotlabs\Daemon; -require_once('include/zot.php'); - +require_once('include/hubloc.php'); class Checksites { diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index 07533cc6e..a6daad051 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -2,6 +2,8 @@ namespace Zotlabs\Daemon; +use Zotlabs\Lib\Libzotdir; + class Cron_daily { static public function run($argc,$argv) { @@ -14,12 +16,11 @@ class Cron_daily { */ - require_once('include/dir_fns.php'); - check_upstream_directory(); + Libzotdir::check_upstream_directory(); // Fire off the Cron_weekly process if it's the correct day. - + $d3 = intval(datetime_convert('UTC','UTC','now','N')); if($d3 == 7) { Master::Summon(array('Cron_weekly')); @@ -80,15 +81,14 @@ class Cron_daily { downgrade_accounts(); // If this is a directory server, request a sync with an upstream - // directory at least once a day, up to once every poll interval. + // directory at least once a day, up to once every poll interval. // Pull remote changes and push local changes. - // potential issue: how do we keep from creating an endless update loop? + // potential issue: how do we keep from creating an endless update loop? $dirmode = get_config('system','directory_mode'); if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { - require_once('include/dir_fns.php'); - sync_directories($dirmode); + Libzotdir::sync_directories($dirmode); } diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php index 43f426eb7..c853af6a8 100644 --- a/Zotlabs/Daemon/Deliver.php +++ b/Zotlabs/Daemon/Deliver.php @@ -2,12 +2,8 @@ namespace Zotlabs\Daemon; -use Zotlabs\Lib\DReport; - -require_once('include/zot.php'); require_once('include/queue_fn.php'); - class Deliver { static public function run($argc,$argv) { @@ -22,72 +18,16 @@ class Deliver { if(! $argv[$x]) continue; - $dresult = null; - $r = q("select * from outq where outq_hash = '%s' limit 1", + $r = q("select * from outq where outq_hash = '%s'", dbesc($argv[$x]) ); - if($r) { - - $notify = json_decode($r[0]['outq_notify'],true); - - // Messages without an outq_msg will need to go via the web, even if it's a - // local delivery. This includes conversation requests and refresh packets. - - if(($r[0]['outq_posturl'] === z_root() . '/post') && ($r[0]['outq_msg'])) { - logger('deliver: local delivery', LOGGER_DEBUG); - - // local delivery - // we should probably batch these and save a few delivery processes - - if($r[0]['outq_msg']) { - $m = json_decode($r[0]['outq_msg'],true); - if(array_key_exists('message_list',$m)) { - foreach($m['message_list'] as $mm) { - $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $mm))))); - zot_import($msg,z_root()); - } - } - else { - $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m))))); - $dresult = zot_import($msg,z_root()); - } - - remove_queue_item($r[0]['outq_hash']); - - if($dresult && is_array($dresult)) { - - // delivery reports for local deliveries do not require encryption - - foreach($dresult as $xx) { - if(is_array($xx) && array_key_exists('message_id',$xx)) { - if(DReport::is_storable($xx)) { - q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - dbesc($xx['message_id']), - dbesc($xx['location']), - dbesc($xx['recipient']), - dbesc(($xx['name']) ? $xx['name'] : EMPTY_STR), - dbesc($xx['status']), - dbesc(datetime_convert($xx['date'])), - dbesc($xx['sender']) - ); - } - } - } - } - - q("delete from dreport where dreport_queue = '%s'", - dbesc($argv[$x]) - ); - - continue; - } - } - - // otherwise it's a remote delivery - call queue_deliver() with the $immediate flag + if($r) { queue_deliver($r[0],true); - } + } + } + } diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php index c698995c2..ab58432de 100644 --- a/Zotlabs/Daemon/Directory.php +++ b/Zotlabs/Daemon/Directory.php @@ -58,7 +58,8 @@ class Directory { // otherwise send the changes upstream $directory = Libzotdir::find_upstream_directory($dirmode); - $url = $directory['url'] . '/post'; + + $url = $directory['url'] . '/zot'; // ensure the upstream directory is updated diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php index 6951aa1d4..9e74eb8b5 100644 --- a/Zotlabs/Daemon/Gprobe.php +++ b/Zotlabs/Daemon/Gprobe.php @@ -19,7 +19,7 @@ class Gprobe { if(! strpos($url,'@')) return; - $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1", dbesc($url) ); diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 8ea75af61..626299661 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -4,6 +4,7 @@ namespace Zotlabs\Daemon; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Activity; +use Zotlabs\Lib\Queue; require_once('include/queue_fn.php'); require_once('include/html2plain.php'); @@ -16,26 +17,26 @@ require_once('include/bbcode.php'); /* * This file was at one time responsible for doing all deliveries, but this caused - * big problems on shared hosting systems, where the process might get killed by the - * hosting provider and nothing would get delivered. + * big problems on shared hosting systems, where the process might get killed by the + * hosting provider and nothing would get delivered. * It now only delivers one message under certain cases, and invokes a queued - * delivery mechanism (include/deliver.php) to deliver individual contacts at + * delivery mechanism (include/deliver.php) to deliver individual contacts at * controlled intervals. * This has a much better chance of surviving random processes getting killed - * by the hosting provider. + * by the hosting provider. * * The basic flow is: * Identify the type of message * Collect any information that needs to be sent * Convert it into a suitable generic format for sending - * Figure out who the recipients are and if we need to relay + * Figure out who the recipients are and if we need to relay * through a conversation owner - * Once we know what recipients are involved, collect a list of + * Once we know what recipients are involved, collect a list of * destination sites * Build and store a queue item for each unique site and invoke * a delivery process for each site or a small number of sites (1-3) * and add a slight delay between each delivery invocation if desired (usually) - * + * */ /* @@ -60,7 +61,7 @@ require_once('include/bbcode.php'); * * and ITEM_ID is the id of the item in the database that needs to be sent to others. * - * ZOT + * ZOT * permission_create abook_id * permission_accept abook_id * permission_reject abook_id @@ -166,7 +167,7 @@ class Notifier { $normal_mode = false; } elseif(in_array($cmd, [ 'permission_update', 'permission_reject', 'permission_accept', 'permission_create' ])) { - // Get the (single) recipient + // Get the (single) recipient $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0", intval($item_id) ); @@ -175,7 +176,7 @@ class Notifier { // Get the sender $channel = channelx_by_n($uid); if($channel) { - $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => ''); + $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => ''); if($cmd === 'permission_create') call_hooks('permissions_create',$perm_update); @@ -191,7 +192,7 @@ class Notifier { $deliveries[] = $perm_update['deliveries']; do_delivery($deliveries); } - return; + return; } else { $recipients[] = $r[0]['abook_xchan']; @@ -235,7 +236,7 @@ class Notifier { } } - $encoded_item = array('locations' => zot_encode_locations($channel),'type' => 'location', 'encoding' => 'zot'); + $encoded_item = array('locations' => Libzot::encode_locations($channel),'type' => 'location', 'encoding' => 'zot'); $target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']); $private = false; $packet_type = 'location'; @@ -292,7 +293,7 @@ class Notifier { xchan_query($r); $r = fetch_post_tags($r); - + $target_item = $r[0]; if(in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) { @@ -328,7 +329,7 @@ class Notifier { // Check for non published items, but allow an exclusion for transmitting hidden file activities if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || - intval($target_item['item_blocked']) || + intval($target_item['item_blocked']) || ( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) { logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG); return; @@ -371,7 +372,7 @@ class Notifier { xchan_query($r); $r = fetch_post_tags($r); - + $parent_item = $r[0]; $top_level_post = false; } @@ -396,7 +397,7 @@ class Notifier { z_root() . ZOT_APSCHEMA_REV ]], Activity::encode_activity($target_item) ); - } + } logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG); logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG); @@ -404,11 +405,11 @@ class Notifier { // Send comments to the owner to re-deliver to everybody in the conversation // We only do this if the item in question originated on this site. This prevents looping. // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay. - // Relaying should never be initiated on a post that arrived from elsewhere. + // Relaying should never be initiated on a post that arrived from elsewhere. // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at - // the hostname in the message_id and provides a second (fallback) opinion. + // the hostname in the message_id and provides a second (fallback) opinion. $relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false); @@ -425,9 +426,9 @@ class Notifier { // tag_deliver'd post which needs to be sent back to the original author if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) { - logger('notifier: uplink'); + logger('notifier: uplink'); $uplink = true; - } + } if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) { logger('notifier: followup relay', LOGGER_DEBUG); @@ -444,8 +445,8 @@ class Notifier { logger('notifier: owner relay'); $upstream = false; // if our parent is a tag_delivery recipient, uplink to the original author causing - // a delivery fork. - + // a delivery fork. + if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) { // don't uplink a relayed post to the relay owner if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) { @@ -461,21 +462,14 @@ class Notifier { if ($top_level_post) { // remove clones who will receive the post via sync $recipients = array_diff($recipients, [ $target_item['owner_xchan'] ]); - } + } // FIXME add any additional recipients such as mentions, etc. - // don't send deletions onward for other people's stuff - // TODO verify this is needed - copied logic from same place in old code - - if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) { - logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE); - return; - } } } - $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false); + $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false); // Generic delivery section, we have an encoded item and recipients // Now start the delivery process @@ -504,7 +498,7 @@ class Notifier { if($details) { foreach($details as $d) { - $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; + $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; if($private) { $env_recips[] = [ 'guid' => $d['xchan_guid'], @@ -556,19 +550,19 @@ class Notifier { // shouldn't happen logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE); } - + logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG); - + // Now we have collected recipients (except for external mentions, FIXME) // Let's reduce this to a set of hubs; checking that the site is not dead. - $hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url - where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ") + $hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url + where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ") and hubloc_error = 0 and hubloc_deleted = 0" ); - // public posts won't make it to the local public stream unless there's a recipient on this site. + // public posts won't make it to the local public stream unless there's a recipient on this site. // This code block sees if it's a public post and localhost is missing, and if so adds an entry for the local sys channel to the $hubs list if (! $private) { @@ -582,7 +576,7 @@ class Notifier { } } if (! $found_localhost) { - $localhub = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc + $localhub = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url where hubloc_id_url = '%s' and hubloc_error = 0 and hubloc_deleted = 0", dbesc(z_root() . '/channel/sys') ); @@ -591,14 +585,14 @@ class Notifier { } } } - + if(! $hubs) { logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE); return; } /** - * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, + * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, * since it may have been a re-install which has not yet been detected and pruned. * For other networks which don't have or require sitekeys, we'll have to use the URL */ @@ -628,7 +622,7 @@ class Notifier { } } } - + if($hub['hubloc_network'] == 'zot') { if(! in_array($hub['hubloc_sitekey'],$keys)) { @@ -639,9 +633,16 @@ class Notifier { } else { if(! in_array($hub['hubloc_url'],$urls)) { - $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network']; - $dhubs[] = $hub; - $urls[] = $hub['hubloc_url']; + if($hub['hubloc_url'] === z_root()) { + //deliver to local hub first + array_unshift($hublist, $hub['hubloc_host'] . ' ' . $hub['hubloc_network']); + array_unshift($dhubs, $hub); + } + else { + $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network']; + $dhubs[] = $hub; + } + $urls[] = $hub['hubloc_url']; } } } @@ -706,8 +707,8 @@ class Notifier { } // Do not change this to a uuid as long as we have traditional zot servers - // in the loop. The signature verification step can't handle dashes in the - // hashes. + // in the loop. The signature verification step can't handle dashes in the + // hashes. $hash = random_string(48); @@ -734,15 +735,17 @@ class Notifier { } if($packet) { - queue_insert(array( - 'hash' => $hash, - 'account_id' => $channel['channel_account_id'], - 'channel_id' => $channel['channel_id'], - 'posturl' => $hub['hubloc_callback'], - 'driver' => $hub['hubloc_network'], - 'notify' => $packet, - 'msg' => (($pmsg) ? json_encode($pmsg) : '') - )); + Queue::insert( + [ + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $hub['hubloc_callback'], + 'driver' => $hub['hubloc_network'], + 'notify' => $packet, + 'msg' => (($pmsg) ? json_encode($pmsg) : '') + ] + ); } else { $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); @@ -756,13 +759,13 @@ class Notifier { } } - $packet_type = (($upstream || $uplink) ? 'response' : 'activity'); + $packet_type = (($upstream || $uplink) ? 'response' : 'activity'); // block zot private reshares from zot6, as this could cause a number of privacy issues // due to parenting differences between the reshare implementations. In zot a reshare is // a standalone parent activity and in zot6 it is a followup/child of the original activity. // For public reshares, some comments to the reshare on the zot fork will not make it to zot6 - // due to these different message models. This cannot be prevented at this time. + // due to these different message models. This cannot be prevented at this time. if($packet_type === 'activity' && $activity['type'] === 'Announce' && intval($target_item['item_private'])) { continue; @@ -772,7 +775,7 @@ class Notifier { } else { // currently zot6 delivery is only performed on normal items and not sync items or mail or anything else - // Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing + // Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing // with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report // to trigger dequeue'ing @@ -803,7 +806,7 @@ class Notifier { } } - queue_insert( + Queue::insert( [ 'hash' => $hash, 'account_id' => $target_item['aid'], @@ -829,9 +832,9 @@ class Notifier { } } - $deliveries[] = $hash; + $deliveries[] = $hash; } - + if($normal_mode) { $x = q("select * from hook where hook = 'notifier_normal'"); if($x) { @@ -847,7 +850,7 @@ class Notifier { if ($dead) { foreach ($dead as $deceased) { if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) { - q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue ) + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ", dbesc($target_item['mid']), dbesc($deceased['hubloc_host']), diff --git a/Zotlabs/Daemon/Onedirsync.php b/Zotlabs/Daemon/Onedirsync.php index cc16c0b58..a952b8117 100644 --- a/Zotlabs/Daemon/Onedirsync.php +++ b/Zotlabs/Daemon/Onedirsync.php @@ -2,6 +2,9 @@ namespace Zotlabs\Daemon; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Libzotdir; + require_once('include/zot.php'); require_once('include/dir_fns.php'); @@ -11,7 +14,7 @@ class Onedirsync { static public function run($argc,$argv) { logger('onedirsync: start ' . intval($argv[1])); - + if(($argc > 1) && (intval($argv[1]))) $update_id = intval($argv[1]); @@ -19,7 +22,7 @@ class Onedirsync { logger('onedirsync: no update'); return; } - + $r = q("select * from updates where ud_id = %d limit 1", intval($update_id) ); @@ -50,10 +53,13 @@ class Onedirsync { // ignore doing an update if this ud_addr refers to a known dead hubloc - $h = q("select * from hubloc where hubloc_addr = '%s' limit 1", + $h = q("select * from hubloc where hubloc_addr = '%s'", dbesc($r[0]['ud_addr']) ); - if(($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) { + + $h = Libzot::zot_record_preferred($h); + + if(($h) && ($h['hubloc_status'] & HUBLOC_OFFLINE)) { $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ", intval(UPDATE_FLAGS_UPDATED), dbesc($r[0]['ud_addr']), @@ -63,13 +69,13 @@ class Onedirsync { return; } - // we might have to pull this out some day, but for now update_directory_entry() + // we might have to pull this out some day, but for now update_directory_entry() // runs zot_finger() and is kind of zot specific - if($h && $h[0]['hubloc_network'] !== 'zot') + if($h && ! in_array($h['hubloc_network'], ['zot6', 'zot'])) return; - update_directory_entry($r[0]); + Libzotdir::update_directory_entry($r[0]); return; } diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php index ebc0584ba..dfa628193 100644 --- a/Zotlabs/Daemon/Poller.php +++ b/Zotlabs/Daemon/Poller.php @@ -55,7 +55,6 @@ class Poller { $force = true; } - $sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : ""); reload_plugins(); @@ -86,7 +85,6 @@ class Poller { ); if($contacts) { - foreach($contacts as $contact) { $update = false; @@ -174,6 +172,8 @@ class Poller { } } + $dirmode = intval(get_config('system', 'directory_mode')); + if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) { $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ", intval(UPDATE_FLAGS_UPDATED), diff --git a/Zotlabs/Daemon/Ratenotif.php b/Zotlabs/Daemon/Ratenotif.php index c7bf79854..8afde2c4c 100644 --- a/Zotlabs/Daemon/Ratenotif.php +++ b/Zotlabs/Daemon/Ratenotif.php @@ -10,6 +10,11 @@ class Ratenotif { static public function run($argc,$argv) { + + // Deprecated + return; + + require_once("datetime.php"); require_once('include/items.php'); diff --git a/Zotlabs/Identity/BasicId.php b/Zotlabs/Identity/BasicId.php index 3c149808f..a7fb109cd 100644 --- a/Zotlabs/Identity/BasicId.php +++ b/Zotlabs/Identity/BasicId.php @@ -1,6 +1,6 @@ <?php -namespace Zotlabs\Identity\BasicId; +namespace Zotlabs\Identity; class BasicId { diff --git a/Zotlabs/Identity/ProfilePhoto.php b/Zotlabs/Identity/ProfilePhoto.php index 2891136c7..9c3ad81a5 100644 --- a/Zotlabs/Identity/ProfilePhoto.php +++ b/Zotlabs/Identity/ProfilePhoto.php @@ -1,5 +1,5 @@ <?php -namespace Zotlabs\Identity\ProfilePhoto; +namespace Zotlabs\Identity; class ProfilePhoto { diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 48714a48d..807216400 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -168,7 +168,7 @@ class Activity { ); if($r) { xchan_query($r,true); - $r = fetch_post_tags($r,true); + $r = fetch_post_tags($r); if (in_array($r[0]['verb'], ['Create', 'Invite']) && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) { $r[0]['verb'] = 'Invite'; return self::encode_activity($r[0]); @@ -713,7 +713,7 @@ class Activity { ); if($p) { xchan_query($p,true); - $p = fetch_post_tags($p,true); + $p = fetch_post_tags($p); $i['obj'] = self::encode_item($p[0]); // convert to zot6 emoji reaction encoding which uses the target object to indicate the @@ -800,7 +800,7 @@ class Activity { $is_directmessage = false; $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - if(in_array($i['author']['xchan_url'], $recips['to'])) { + if(array_path_exists('to', $recips) && in_array($i['author']['xchan_url'], $recips['to'])) { $reply_url = $d[0]['xchan_url']; $is_directmessage = true; } @@ -1493,6 +1493,14 @@ class Activity { if(! is_array($person_obj)) return; + $inbox = $person_obj['inbox']; + + // invalid identity + + if (! $inbox || strpos($inbox,z_root()) !== false) { + return; + } + $name = $person_obj['name']; if(! $name) $name = $person_obj['preferredUsername']; @@ -1540,8 +1548,6 @@ class Activity { $profile = $url; } - $inbox = $person_obj['inbox']; - $collections = []; if($inbox) { @@ -2137,7 +2143,7 @@ class Activity { if(! $s['edited']) $s['edited'] = $s['created']; - $s['title'] = self::bb_content($content,'name'); + $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content,'name')); $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')); @@ -2642,7 +2648,7 @@ class Activity { $current_item = $item; while($current_item['parent_mid'] !== $current_item['mid']) { - $n = ActivityStreams::fetch($current_item['parent_mid'], $channel); + $n = self::fetch($current_item['parent_mid'], $channel); if(! $n) { break; } @@ -2654,6 +2660,10 @@ class Activity { break; } + if (is_array($a->actor) && array_key_exists('id',$a->actor)) { + self::actor_store($a->actor['id'],$a->actor); + } + $replies = null; if(isset($a->obj['replies']['first']['items'])) { $replies = $a->obj['replies']['first']['items']; @@ -2719,7 +2729,7 @@ class Activity { foreach($arr as $url) { - $n = ActivityStreams::fetch($url, $channel); + $n = self::fetch($url, $channel); if(! $n) { break; } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index a0ba52aa6..f877fbb45 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -49,7 +49,7 @@ class ActivityStreams { if($this->data) { // verify and unpack JSalmon signature if present - + if(is_array($this->data) && array_key_exists('signed',$this->data)) { $ret = JSalmon::verify($this->data); $tmp = JSalmon::unpack($this->data['data']); @@ -103,7 +103,7 @@ class ActivityStreams { } // fetch recursive or embedded activities - + if ($this->obj && is_array($this->obj) && array_key_exists('object',$this->obj)) { $this->obj['object'] = $this->get_compound_property($this->obj['object']); } @@ -115,10 +115,10 @@ class ActivityStreams { $this->parent_id = $this->get_property_obj('inReplyTo'); - if((! $this->parent_id) && is_array($this->obj)) { + if((! $this->parent_id) && is_array($this->obj)) { $this->parent_id = $this->obj['inReplyTo']; } - if((! $this->parent_id) && is_array($this->obj)) { + if((! $this->parent_id) && is_array($this->obj)) { $this->parent_id = $this->obj['id']; } } @@ -286,7 +286,7 @@ class ActivityStreams { if (! $s) { return false; } - return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ])); + return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ])); } /** @@ -302,7 +302,7 @@ class ActivityStreams { $x = $this->get_property_obj($property, $base, $namespace); if($this->is_url($x)) { - // SECURITY: If we have already stored the actor profile, re-generate it + // SECURITY: If we have already stored the actor profile, re-generate it // from cached data - don't refetch it from the network $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", @@ -344,7 +344,7 @@ class ActivityStreams { } // verify and unpack JSalmon signature if present - + if(is_array($x) && array_key_exists('signed',$x)) { $ret = JSalmon::verify($x); $tmp = JSalmon::unpack($x['data']); diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index c78325ee3..3a24cd349 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -64,7 +64,7 @@ class Enotify { $sitename = get_config('system','sitename'); $site_admin = sprintf( t('%s Administrator'), $sitename); $opt_out1 = sprintf( t('This email was sent by %1$s at %2$s.'), t('$Projectname'), \App::get_hostname()); - $opt_out2 = sprintf( t('To stop receiving these messages, please adjust your Notification Settings at %s'), z_root() . '/settings'); + $opt_out2 = sprintf( t('To stop receiving these messages, please adjust your Notification Settings at %s'), z_root() . '/settings'); $hopt_out2 = sprintf( t('To stop receiving these messages, please adjust your %s.'), '<a href="' . z_root() . '/settings' . '">' . t('Notification Settings') . '</a>'); $sender_name = $product; $hostname = \App::get_hostname(); @@ -80,7 +80,7 @@ class Enotify { $sender_email = get_config('system','from_email'); if(! $sender_email) $sender_email = 'Administrator' . '@' . $hostname; - + $sender_name = get_config('system','from_email_name'); if(! $sender_name) $sender_name = \Zotlabs\Lib\System::get_site_name(); @@ -108,7 +108,7 @@ class Enotify { logger('notification invoked for an old item which may have been refetched.',LOGGER_DEBUG,LOG_INFO); return; } - } + } else { $title = $body = ''; } @@ -181,7 +181,7 @@ class Enotify { pop_lang(); return; } - + // if it's a post figure out who's post it is. @@ -219,7 +219,7 @@ class Enotify { $itemlink, $p[0]['author']['xchan_name'], $item_post_type); - + // "your post" if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall'])) $dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'), @@ -230,15 +230,15 @@ class Enotify { // Some mail softwares relies on subject field for threading. // So, we cannot have different subjects for notifications of the same thread. - // Before this we have the name of the replier on the subject rendering + // Before this we have the name of the replier on the subject rendering // differents subjects for messages on the same thread. if($moderated) $subject = sprintf( t('[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); else $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); - $preamble = sprintf( t('%1$s commented on an item/conversation you have been following.'), $sender['xchan_name']); - $epreamble = $dest_str; + $preamble = sprintf( t('%1$s commented on an item/conversation you have been following.'), $sender['xchan_name']); + $epreamble = $dest_str; $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); @@ -247,7 +247,7 @@ class Enotify { $tsitelink .= "\n\n" . sprintf( t('Please visit %s to approve or reject this comment.'), z_root() . '/moderate' ); $hsitelink .= "<br><br>" . sprintf( t('Please visit %s to approve or reject this comment.'), '<a href="' . z_root() . '/moderate">' . z_root() . '/moderate</a>' ); } - + } if ($params['type'] == NOTIFY_LIKE) { @@ -278,7 +278,7 @@ class Enotify { pop_lang(); return; } - + // if it's a post figure out who's post it is. @@ -314,12 +314,12 @@ class Enotify { // Some mail softwares relies on subject field for threading. // So, we cannot have different subjects for notifications of the same thread. - // Before this we have the name of the replier on the subject rendering + // Before this we have the name of the replier on the subject rendering // differents subjects for messages on the same thread. $subject = sprintf( t('[$Projectname:Notify] Like received to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); - $preamble = sprintf( t('%1$s liked an item/conversation you created.'), $sender['xchan_name']); - $epreamble = $dest_str; + $preamble = sprintf( t('%1$s liked an item/conversation you created.'), $sender['xchan_name']); + $epreamble = $dest_str; $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); @@ -335,7 +335,7 @@ class Enotify { $epreamble = sprintf( t('%1$s posted to [zrl=%2$s]your wall[/zrl]') , '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', - $params['link']); + $params['link']); $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); @@ -355,12 +355,12 @@ class Enotify { pop_lang(); return; } - + $subject = sprintf( t('[$Projectname:Notify] %s tagged you') , $sender['xchan_name']); $preamble = sprintf( t('%1$s tagged you at %2$s') , $sender['xchan_name'], $sitename); $epreamble = sprintf( t('%1$s [zrl=%2$s]tagged you[/zrl].') , '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', - $params['link']); + $params['link']); $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); @@ -373,7 +373,7 @@ class Enotify { $preamble = sprintf( t('%1$s poked you at %2$s') , $sender['xchan_name'], $sitename); $epreamble = sprintf( t('%1$s [zrl=%2$s]poked you[/zrl].') , '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', - $params['link']); + $params['link']); $subject = str_replace('poked', t($params['activity']), $subject); $preamble = str_replace('poked', t($params['activity']), $preamble); @@ -390,7 +390,7 @@ class Enotify { $preamble = sprintf( t('%1$s tagged your post at %2$s'),$sender['xchan_name'], $sitename); $epreamble = sprintf( t('%1$s tagged [zrl=%2$s]your post[/zrl]') , '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', - $itemlink); + $itemlink); $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); @@ -400,10 +400,10 @@ class Enotify { if ($params['type'] == NOTIFY_INTRO) { $subject = sprintf( t('[$Projectname:Notify] Introduction received')); - $preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename); + $preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename); $epreamble = sprintf( t('You\'ve received [zrl=%1$s]a new connection request[/zrl] from %2$s.'), $siteurl . '/connections/ifpending', - '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]'); + '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]'); $body = sprintf( t('You may visit their profile at %s'),$sender['xchan_url']); $sitelink = t('Please visit %s to approve or reject the connection request.'); @@ -414,11 +414,11 @@ class Enotify { if ($params['type'] == NOTIFY_SUGGEST) { $subject = sprintf( t('[$Projectname:Notify] Friend suggestion received')); - $preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename); + $preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename); $epreamble = sprintf( t('You\'ve received [zrl=%1$s]a friend suggestion[/zrl] for %2$s from %3$s.'), $itemlink, '[zrl=' . $params['item']['url'] . ']' . $params['item']['name'] . '[/zrl]', - '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]'); + '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]'); $body = t('Name:') . ' ' . $params['item']['name'] . "\n"; $body .= t('Photo:') . ' ' . $params['item']['photo'] . "\n"; @@ -462,7 +462,7 @@ class Enotify { $sitelink = $h['sitelink']; $tsitelink = $h['tsitelink']; $hsitelink = $h['hsitelink']; - $itemlink = $h['itemlink']; + $itemlink = $h['itemlink']; require_once('include/html2bbcode.php'); @@ -510,7 +510,7 @@ class Enotify { // Mark some notifications as seen right away // Note! The notification have to be created, because they are used to send emails // So easiest solution to hide them from Notices is to mark them as seen right away. - // Another option would be to not add them to the DB, and change how emails are handled + // Another option would be to not add them to the DB, and change how emails are handled // (probably would be better that way) if (!$always_show_in_notices) { @@ -555,7 +555,7 @@ class Enotify { // wretched hack, but we don't want to duplicate all the preamble variations and we also don't want to screw up a translation if ((\App::$language === 'en' || (! \App::$language)) && strpos($msg,', ')) - $msg = substr($msg,strpos($msg,', ')+1); + $msg = substr($msg,strpos($msg,', ')+1); $datarray['id'] = $notify_id; $datarray['msg'] = $msg; @@ -587,12 +587,12 @@ class Enotify { $htmlversion = bbcode(stripslashes(str_replace(array("\\r","\\n"), array("","<br />\n"),$body))); - // use $_SESSION['zid_override'] to force zid() to use + // use $_SESSION['zid_override'] to force zid() to use // the recipient address instead of the current observer $_SESSION['zid_override'] = channel_reddress($recip); $_SESSION['zrl_override'] = z_root() . '/channel/' . $recip['channel_address']; - + $textversion = zidify_links($textversion); $htmlversion = zidify_links($htmlversion); @@ -754,7 +754,7 @@ class Enotify { return $params['result']; } - $fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8'); + $fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8'); $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8'); // generate a mime boundary @@ -767,8 +767,8 @@ class Enotify { $messageHeader = $params['additionalMailHeader'] . "From: $fromName <{$params['fromEmail']}>" . PHP_EOL . - "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL . - "MIME-Version: 1.0" . PHP_EOL . + "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL . + "MIME-Version: 1.0" . PHP_EOL . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\""; // assemble the final multipart message body with the text and html types included @@ -782,7 +782,7 @@ class Enotify { $textBody . PHP_EOL . "--" . $mimeBoundary . PHP_EOL . // text/html section "Content-Type: text/html; charset=UTF-8" . PHP_EOL . - "Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL . + "Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL . $htmlBody . PHP_EOL . "--" . $mimeBoundary . "--" . PHP_EOL; // message ending @@ -803,7 +803,7 @@ class Enotify { require_once('include/conversation.php'); - // Call localize_item to get a one line status for activities. + // Call localize_item to get a one line status for activities. // This should set $item['localized'] to indicate we have a brief summary. // and perhaps $item['shortlocalized'] for an even briefer summary @@ -860,7 +860,7 @@ class Enotify { //'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])), 'thread_top' => (($item['item_thread_top']) ? true : false), 'message' => bbcode(escape_tags($itemem_text)), - 'body' => htmlentities(html2plain(bbcode($item['body']), 75, true), ENT_COMPAT, 'UTF-8', false), + 'body' => htmlentities(html2plain(bbcode($item['body']), 75, true), ENT_QUOTES, 'UTF-8', false), // these are for the superblock addon 'hash' => $item[$who]['xchan_hash'], 'uid' => $item['uid'], diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php index 48a4e649b..7f63cf914 100644 --- a/Zotlabs/Lib/JSalmon.php +++ b/Zotlabs/Lib/JSalmon.php @@ -40,15 +40,15 @@ class JSalmon { $ret = [ 'results' => [] ]; if(! is_array($x)) { - return $false; + return false; } if(! ( array_key_exists('signed',$x) && $x['signed'])) { - return $false; + return false; } - $signed_data = preg_replace('/\s+/','',$x['data']) . '.' - . base64url_encode($x['data_type'],true) . '.' - . base64url_encode($x['encoding'],true) . '.' + $signed_data = preg_replace('/\s+/','',$x['data']) . '.' + . base64url_encode($x['data_type'],true) . '.' + . base64url_encode($x['encoding'],true) . '.' . base64url_encode($x['alg'],true); $key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id'])); diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index cff320e11..7b968532a 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -42,7 +42,7 @@ class Libsync { $channel = $r[0]; - // don't provide these in the export + // don't provide these in the export unset($channel['channel_active']); unset($channel['channel_password']); @@ -245,7 +245,7 @@ class Libsync { if(array_key_exists('app',$arr) && $arr['app']) sync_apps($channel,$arr['app']); - + if(array_key_exists('addressbook',$arr) && $arr['addressbook']) sync_addressbook($channel,$arr['addressbook']); @@ -260,7 +260,7 @@ class Libsync { if(array_key_exists('mail',$arr) && $arr['mail']) sync_mail($channel,$arr['mail']); - + if(array_key_exists('event',$arr) && $arr['event']) sync_events($channel,$arr['event']); @@ -269,7 +269,7 @@ class Libsync { if(array_key_exists('item',$arr) && $arr['item']) sync_items($channel,$arr['item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); - + // deprecated, maintaining for a few months for upward compatibility // this should sync webpages, but the logic is a bit subtle @@ -278,7 +278,7 @@ class Libsync { if(array_key_exists('menu',$arr) && $arr['menu']) sync_menus($channel,$arr['menu']); - + if(array_key_exists('file',$arr) && $arr['file']) sync_files($channel,$arr['file']); @@ -293,7 +293,7 @@ class Libsync { if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { // Several pageflags are site-specific and cannot be sync'd. - // Only allow those bits which are shareable from the remote and then + // Only allow those bits which are shareable from the remote and then // logically OR with the local flags $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN|PAGE_AUTOCONNECT|PAGE_APPLICATION|PAGE_PREMIUM|PAGE_ADULT); @@ -562,7 +562,7 @@ class Libsync { // our group list is already synchronised if($x) { foreach($x as $y) { - + // for each group, loop on members list we just received if(isset($y['hash']) && isset($members[$y['hash']])) { foreach($members[$y['hash']] as $member) { @@ -574,9 +574,9 @@ class Libsync { ); if($z) $found = true; - + // if somebody is in the group that wasn't before - add them - + if(! $found) { q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", @@ -587,7 +587,7 @@ class Libsync { } } } - + // now retrieve a list of members we have on this site $m = q("select xchan from pgrp_member where gid = %d and uid = %d", intval($y['id']), @@ -615,7 +615,7 @@ class Libsync { $disallowed = array('id','aid','uid','guid'); foreach($arr['profile'] as $profile) { - + $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']) @@ -628,7 +628,7 @@ class Libsync { 'profile_guid' => $profile['profile_guid'], ] ); - + $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']) @@ -713,7 +713,7 @@ class Libsync { if($arr['locations']) { if($absolute) - self::check_location_move($sender['hash'],$arr['locations']); + Libzot::check_location_move($sender['hash'],$arr['locations']); $xisting = q("select * from hubloc where hubloc_hash = '%s'", dbesc($sender['hash']) @@ -775,14 +775,14 @@ class Libsync { ); if($r) { logger('Hub exists: ' . $location['url'], LOGGER_DEBUG); - + // update connection timestamp if this is the site we're talking to // This only happens when called from import_xchan $current_site = false; $t = datetime_convert('UTC','UTC','now - 15 minutes'); - + if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) { q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'", dbesc(datetime_convert()), @@ -903,12 +903,14 @@ class Libsync { $changed = true; if($location['primary']) { - $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1", + $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s'", dbesc($location['address']), dbesc($location['sitekey']) ); - if($r) - hubloc_change_primary($r[0]); + if($r) { + $r = Libzot::zot_record_preferred($r); + hubloc_change_primary($r); + } } } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index f0fe3ab24..4291ce518 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -421,7 +421,7 @@ class Libzot { if($new_connection) { if(! Permissions::PermsCompare($new_perms,$previous_perms)) - Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); + Master::Summon([ 'Notifier', 'permission_create', $new_connection[0]['abook_id'] ]); Enotify::submit( [ 'type' => NOTIFY_INTRO, @@ -1489,9 +1489,9 @@ class Libzot { $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); if(($act) && ($act->obj) && (! is_array($act->obj))) { - // The initial object fetch failed using the sys channel credentials. + // The initial object fetch failed using the sys channel credentials. // Try again using the delivery channel credentials. - // We will also need to re-parse the $item array, + // We will also need to re-parse the $item array, // but preserve any values that were set during anonymous parsing. $o = Activity::fetch($act->obj,$channel); @@ -1505,7 +1505,7 @@ class Libzot { $result[] = $DR->get(); continue; } - } + } /** * We need to block normal top-level message delivery from our clones, as the delivered @@ -1634,7 +1634,7 @@ class Libzot { // have the copy and we don't want the request to loop. // Also don't do this if this comment came from a conversation request packet. // It's possible that comments are allowed but posting isn't and that could - // cause a conversation fetch loop. + // cause a conversation fetch loop. // We'll also check the send_stream permission - because if it isn't allowed, // the top level post is unlikely to be imported and // this is just an exercise in futility. @@ -2295,7 +2295,7 @@ class Libzot { * * @see import_directory_profile() * - * @param string $sender + * @param string $sender * @param array $arr * @param array $deliveries (unused) * @return void @@ -2316,7 +2316,7 @@ class Libzot { /** * @brief * - * @param string $sender + * @param string $sender * @param array $arr * @param array $deliveries (unused) deliveries is irrelevant * @return void diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index b02516a98..d4c5398ee 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -19,7 +19,6 @@ class Libzotdir { */ static function find_upstream_directory($dirmode) { - global $DIRECTORY_FALLBACK_SERVERS; $preferred = get_config('system','directory_server'); @@ -31,7 +30,7 @@ class Libzotdir { ); if(($r) && ($r[0]['site_flags'] & DIRECTORY_MODE_STANDALONE)) { $preferred = ''; - } + } } @@ -42,19 +41,21 @@ class Libzotdir { * from our list of directory servers. However, if we're a directory * server ourself, point at the local instance * We will then set this value so this should only ever happen once. - * Ideally there will be an admin setting to change to a different + * Ideally there will be an admin setting to change to a different * directory server if you don't like our choice or if circumstances change. */ + $directory_fallback_servers = get_directory_fallback_servers(); + $dirmode = intval(get_config('system','directory_mode')); if ($dirmode == DIRECTORY_MODE_NORMAL) { - $toss = mt_rand(0,count($DIRECTORY_FALLBACK_SERVERS)); - $preferred = $DIRECTORY_FALLBACK_SERVERS[$toss]; + $toss = mt_rand(0,count($directory_fallback_servers)); + $preferred = $directory_fallback_servers[$toss]; if(! $preferred) { $preferred = DIRECTORY_FALLBACK_MASTER; } set_config('system','directory_server',$preferred); - } + } else { set_config('system','directory_server',z_root()); } @@ -108,7 +109,7 @@ class Libzotdir { $ret = get_config('directory', $setting); - // 'safemode' is the default if there is no observer or no established preference. + // 'safemode' is the default if there is no observer or no established preference. if($setting === 'safemode' && $ret === false) $ret = 1; @@ -175,8 +176,8 @@ class Libzotdir { * * Checks the directory mode of this hub to see if it is some form of directory server. If it is, * get the directory realm of this hub. Fetch a list of all other directory servers in this realm and request - * a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB. - * In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored + * a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB. + * In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored * directly if the rater's signature matches. * * @param int $dirmode; @@ -188,16 +189,17 @@ class Libzotdir { return; $realm = get_directory_realm(); + if ($realm == DIRECTORY_REALM) { - $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d and ( site_realm = '%s' or site_realm = '') ", + $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d and ( site_realm = '%s' or site_realm = '') and site_dead = 0", intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY), dbesc(z_root()), intval(SITE_TYPE_ZOT), dbesc($realm) ); - } + } else { - $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' and site_type = %d ", + $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' and site_type = %d and site_dead = 0", intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY), dbesc(z_root()), dbesc(protect_sprintf('%' . $realm . '%')), @@ -205,6 +207,8 @@ class Libzotdir { ); } + + // If there are no directory servers, setup the fallback master /** @FIXME What to do if we're in a different realm? */ @@ -214,14 +218,14 @@ class Libzotdir { [ 'site_url' => DIRECTORY_FALLBACK_MASTER, 'site_flags' => DIRECTORY_MODE_PRIMARY, - 'site_update' => NULL_DATE, + 'site_update' => NULL_DATE, 'site_directory' => DIRECTORY_FALLBACK_MASTER . '/dirsearch', 'site_realm' => DIRECTORY_REALM, 'site_valid' => 1, ] ); - $r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d ", + $r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d and site_dead = 0", intval(DIRECTORY_MODE_PRIMARY), intval(DIRECTORY_MODE_SECONDARY), dbesc(z_root()), @@ -245,7 +249,6 @@ class Libzotdir { $syncdate = (($rr['site_sync'] <= NULL_DATE) ? datetime_convert('UTC','UTC','now - 2 days') : $rr['site_sync']); $x = z_fetch_url($rr['site_directory'] . '?f=&sync=' . urlencode($syncdate) . (($token) ? '&t=' . $token : '')); - if (! $x['success']) continue; @@ -273,7 +276,7 @@ class Libzotdir { $ud_flags |= UPDATE_FLAGS_DELETED; if (is_array($t['flags']) && in_array('forced',$t['flags'])) $ud_flags |= UPDATE_FLAGS_FORCED; - + $z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' ) ", dbesc($t['hash']), @@ -338,7 +341,7 @@ class Libzotdir { static function local_dir_update($uid, $force) { - + logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); $p = q("select channel.channel_hash, channel_address, channel_timezone, channel_portable_id, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", @@ -354,7 +357,7 @@ class Libzotdir { $profile['description'] = $p[0]['pdesc']; $profile['birthday'] = $p[0]['dob']; - if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) + if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) $profile['age'] = $age; $profile['gender'] = $p[0]['gender']; @@ -415,7 +418,7 @@ class Libzotdir { dbesc($legacy_hash) ); } - + } $ud_hash = random_string() . '@' . \App::get_hostname(); @@ -446,7 +449,7 @@ class Libzotdir { $arr['xprof_hash'] = $hash; $arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year $arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0); - $arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : ''); @@ -641,7 +644,7 @@ class Libzotdir { dbesc(datetime_convert()), intval($flags), dbesc($addr) - ); + ); } else { q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ", diff --git a/Zotlabs/Lib/NativeWiki.php b/Zotlabs/Lib/NativeWiki.php index 3ec032075..c3032d02c 100644 --- a/Zotlabs/Lib/NativeWiki.php +++ b/Zotlabs/Lib/NativeWiki.php @@ -9,7 +9,7 @@ define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' ); class NativeWiki { - static public function listwikis($channel, $observer_hash) { + public static function listwikis($channel, $observer_hash) { $sql_extra = item_permissions_sql($channel['channel_id'], $observer_hash); $wikis = q("SELECT * FROM item @@ -40,7 +40,7 @@ class NativeWiki { } - function create_wiki($channel, $observer_hash, $wiki, $acl) { + public static function create_wiki($channel, $observer_hash, $wiki, $acl) { $resource_id = new_uuid(); $uuid = new_uuid(); @@ -101,7 +101,7 @@ class NativeWiki { } } - function update_wiki($channel_id, $observer_hash, $arr, $acl) { + public static function update_wiki($channel_id, $observer_hash, $arr, $acl) { $w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']); $item = $w['wiki']; @@ -156,7 +156,7 @@ class NativeWiki { } } - static public function sync_a_wiki_item($uid,$id,$resource_id) { + public static function sync_a_wiki_item($uid,$id,$resource_id) { $r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ", @@ -185,7 +185,7 @@ class NativeWiki { } } - function delete_wiki($channel_id,$observer_hash,$resource_id) { + public static function delete_wiki($channel_id,$observer_hash,$resource_id) { $w = self::get_wiki($channel_id,$observer_hash,$resource_id); $item = $w['wiki']; @@ -202,7 +202,7 @@ class NativeWiki { } - static public function get_wiki($channel_id, $observer_hash, $resource_id) { + public static function get_wiki($channel_id, $observer_hash, $resource_id) { $sql_extra = item_permissions_sql($channel_id,$observer_hash); @@ -236,7 +236,7 @@ class NativeWiki { } - static public function exists_by_name($uid, $urlName) { + public static function exists_by_name($uid, $urlName) { $sql_extra = item_permissions_sql($uid); @@ -258,7 +258,7 @@ class NativeWiki { } - static public function get_permissions($resource_id, $owner_id, $observer_hash) { + public static function get_permissions($resource_id, $owner_id, $observer_hash) { // TODO: For now, only the owner can edit $sql_extra = item_permissions_sql($owner_id, $observer_hash); diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index e0206bd43..fb95b0504 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -2,6 +2,8 @@ namespace Zotlabs\Module; +use Zotlabs\Lib\Libzotdir; + require_once 'include/acl_selectors.php'; require_once 'include/group.php'; @@ -46,20 +48,20 @@ class Acl extends \Zotlabs\Web\Controller { // 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos) // 'x' => nav search bar autocomplete (match any xchan) // $_REQUEST['query'] contains autocomplete search text. - - // List of channels whose connections to also suggest, + + // List of channels whose connections to also suggest, // e.g. currently viewed channel or channels mentioned in a post $extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array()); - + // The different autocomplete libraries use different names for the search text // parameter. Internally we'll use $search to represent the search text no matter - // what request variable it was attached to. - + // what request variable it was attached to. + if(array_key_exists('query',$_REQUEST)) { $search = $_REQUEST['query']; } - + if( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ]))) killme(); @@ -68,7 +70,7 @@ class Acl extends \Zotlabs\Web\Controller { if(in_array($type, [ 'm', 'a', 'c', 'f' ])) { // These queries require permission checking. We'll create a simple array of xchan_hash for those with - // the requisite permissions which we can check against. + // the requisite permissions which we can check against. $x = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = '%s' and v = '1'", intval(local_channel()), @@ -85,34 +87,34 @@ class Acl extends \Zotlabs\Web\Controller { $sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") "; $sql_extra2_xchan = "AND ( xchan_name LIKE " . protect_sprintf( "'" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") "; - // This horrible mess is needed because position also returns 0 if nothing is found. + // This horrible mess is needed because position also returns 0 if nothing is found. // Would be MUCH easier if it instead returned a very large value - // Otherwise we could just + // Otherwise we could just // order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)). - $order_extra2 = "CASE WHEN xchan_name LIKE " - . protect_sprintf( "'%" . dbesc($search) . "%'" ) - . " then POSITION('" . protect_sprintf(dbesc($search)) + $order_extra2 = "CASE WHEN xchan_name LIKE " + . protect_sprintf( "'%" . dbesc($search) . "%'" ) + . " then POSITION('" . protect_sprintf(dbesc($search)) . "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, "; $sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) "; - + } else { $sql_extra = $sql_extra2 = $sql_extra3 = ""; } - - + + $groups = array(); $contacts = array(); - + if($type == '' || $type == 'g') { // virtual groups based on private profile viewing ability $r = q("select id, profile_guid, profile_name from profile where is_default = 0 and uid = %d", intval(local_channel()) - ); + ); if($r) { foreach($r as $rv) { $groups[] = array( @@ -130,19 +132,19 @@ class Acl extends \Zotlabs\Web\Controller { // Normal privacy groups $r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname - FROM pgrp, pgrp_member - WHERE pgrp.deleted = 0 AND pgrp.uid = %d + FROM pgrp, pgrp_member + WHERE pgrp.deleted = 0 AND pgrp.uid = %d AND pgrp_member.gid = pgrp.id $sql_extra GROUP BY pgrp.id - ORDER BY pgrp.gname + ORDER BY pgrp.gname LIMIT %d OFFSET %d", intval(local_channel()), intval($count), intval($start) ); - if($r) { + if($r) { foreach($r as $g){ // logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id'])); $groups[] = array( @@ -157,10 +159,10 @@ class Acl extends \Zotlabs\Web\Controller { } } } - + if($type == '' || $type == 'c' || $type === 'f') { - $extra_channels_sql = ''; + $extra_channels_sql = ''; // Only include channels who allow the observer to view their connections if($extra_channels) { @@ -172,7 +174,7 @@ class Acl extends \Zotlabs\Web\Controller { } } } - + // Getting info from the abook is better for local users because it contains info about permissions if(local_channel()) { if($extra_channels_sql != '') @@ -199,7 +201,7 @@ class Acl extends \Zotlabs\Web\Controller { $r2 = array(); foreach($r1 as $rr) { $x = atoken_xchan($rr); - $r2[] = [ + $r2[] = [ 'id' => 'a' . $rr['atoken_id'] , 'hash' => $x['xchan_hash'], 'name' => $x['xchan_name'], @@ -211,12 +213,12 @@ class Acl extends \Zotlabs\Web\Controller { 'abook_self' => 0 ]; } - } + } // add connections - - $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self - FROM abook left join xchan on abook_xchan = xchan_hash + + $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self + FROM abook left join xchan on abook_xchan = xchan_hash WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" , intval(local_channel()) ); @@ -225,28 +227,28 @@ class Acl extends \Zotlabs\Web\Controller { } else { // Visitors - $r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self + $r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self FROM xchan left join xlink on xlink_link = xchan_hash WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2_xchan order by $order_extra2 xchan_name asc" , dbesc(get_observer_hash()) ); - + // Find contacts of extra channels // This is probably more complicated than it needs to be if($extra_channels_sql) { // Build a list of hashes that we got previously so we don't get them again $known_hashes = array("'".get_observer_hash()."'"); if($r) - foreach($r as $rr) + foreach($r as $rr) $known_hashes[] = "'".$rr['hash']."'"; $known_hashes_sql = 'AND xchan_hash not in ('.join(',',$known_hashes).')'; - - $r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self - FROM abook left join xchan on abook_xchan = xchan_hash + + $r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self + FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel IN ($extra_channels_sql) $known_hashes_sql AND abook_blocked = 0 and abook_pending = 0 and abook_hidden = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc"); if($r2) $r = array_merge($r,$r2); - + // Sort accoring to match position, then alphabetically. This could be avoided if the above two SQL queries could be combined into one, and the sorting could be done on the SQl server (like in the case of a local user) $matchpos = function($x) use($search) { $namepos = strpos($x['name'],$search); @@ -269,22 +271,22 @@ class Acl extends \Zotlabs\Web\Controller { } } if((count($r) < 100) && $type == 'c') { - $r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self - FROM xchan + $r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self + FROM xchan WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2_xchan order by $order_extra2 xchan_name asc" ); if($r2) { $r = array_merge($r,$r2); $r = unique_multidim_array($r,'hash'); - } + } } } elseif($type == 'm') { $r = array(); - $z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url + $z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d + WHERE abook_channel = %d and xchan_deleted = 0 and xchan_network IN ('zot', 'diaspora', 'friendica-over-diaspora') $sql_extra3 @@ -298,18 +300,18 @@ class Acl extends \Zotlabs\Web\Controller { } } } - + } elseif($type == 'a') { - - $r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash + + $r = q("SELECT abook_id as id, xchan_name as name, xchan_network as net, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and xchan_deleted = 0 $sql_extra3 ORDER BY xchan_name ASC ", intval(local_channel()) ); - + } elseif($type == 'x') { $r = $this->navbar_complete($a); @@ -323,7 +325,7 @@ class Acl extends \Zotlabs\Web\Controller { ); } } - + $o = array( 'start' => $start, 'count' => $count, @@ -334,27 +336,34 @@ class Acl extends \Zotlabs\Web\Controller { } else $r = array(); - + if($r) { + $i = count($contacts); + $x = []; foreach($r as $g) { - - if(in_array($g['network'],['rss','anon','unknown']) && ($type != 'a')) + + if(in_array($g['net'],['rss','anon','unknown']) && ($type != 'a')) continue; $g['hash'] = urlencode($g['hash']); - + if(! $g['nick']) { $g['nick'] = $g['url']; } + $clink = ($g['nick']) ? $g['nick'] : $g['url']; + $lkey = md5($clink); + if (! array_key_exists($lkey, $x)) + $x[$lkey] = $i; + if(in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) { - $contacts[] = array( + $contacts[$i] = array( "type" => "c", "photo" => "images/twopeople.png", "name" => $g['name'], "id" => urlencode($g['id']), "xid" => $g['hash'], - "link" => (($g['nick']) ? $g['nick'] : $g['url']), + "link" => $clink, "nick" => substr($g['nick'],0,strpos($g['nick'],'@')), "self" => (intval($g['abook_self']) ? 'abook-self' : ''), "taggable" => 'taggable', @@ -362,24 +371,28 @@ class Acl extends \Zotlabs\Web\Controller { ); } if($type !== 'f') { - $contacts[] = array( - "type" => "c", - "photo" => $g['micro'], - "name" => $g['name'], - "id" => urlencode($g['id']), - "xid" => $g['hash'], - "link" => (($g['nick']) ? $g['nick'] : $g['url']), - "nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']), - "self" => (intval($g['abook_self']) ? 'abook-self' : ''), - "taggable" => '', - "label" => '', - ); + if (! array_key_exists($x[$lkey], $contacts) || ($contacts[$x[$lkey]]['net'] !== 'zot6' && ($g['net'] == 'zot6' || $g['net'] == 'zot'))) { + $contacts[$x[$lkey]] = array( + "type" => "c", + "photo" => $g['micro'], + "name" => $g['name'], + "id" => urlencode($g['id']), + "xid" => $g['hash'], + "link" => $clink, + "nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']), + "self" => (intval($g['abook_self']) ? 'abook-self' : ''), + "taggable" => '', + "label" => '', + "net" => $g['net'] + ); + } } - } + $i++; + } } - + $items = array_merge($groups, $contacts); - + $o = array( 'start' => $start, 'count' => $count, @@ -393,50 +406,50 @@ class Acl extends \Zotlabs\Web\Controller { function navbar_complete(&$a) { - + // logger('navbar_complete'); - + if(observer_prohibited()) { return; } - + $dirmode = intval(get_config('system','directory_mode')); $search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : ''); if(! $search || mb_strlen($search) < 2) return array(); - + $star = false; $address = false; - + if(substr($search,0,1) === '@') $search = substr($search,1); - + if(substr($search,0,1) === '*') { $star = true; $search = substr($search,1); } - + if(strpos($search,'@') !== false) { $address = true; } - + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { $url = z_root() . '/dirsearch'; } - + if(! $url) { require_once("include/dir_fns.php"); - $directory = find_upstream_directory($dirmode); + $directory = Libzotdir::find_upstream_directory($dirmode); $url = $directory['url'] . '/dirsearch'; } $token = get_config('system','realm_token'); - + $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100); if($url) { $query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : ''); $query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : ''); - + $x = z_fetch_url($query); if($x['success']) { $t = 0; diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index 4bb34b7b7..011bf3ce4 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -62,6 +62,9 @@ class Site { $from_email = ((array_key_exists('from_email',$_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . \App::get_hostname()); $from_email_name = ((array_key_exists('from_email_name',$_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : \Zotlabs\Lib\System::get_site_name()); + + $sse_enabled = ((x($_POST,'sse_enabled')) ? true : false); + $verifyssl = ((x($_POST,'verifyssl')) ? True : False); $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : ''); $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : ''); @@ -151,6 +154,9 @@ class Site { set_config('system','no_community_page', $no_community_page); set_config('system','no_utf', $no_utf); + + set_config('system','sse_enabled', $sse_enabled); + set_config('system','verifyssl', $verifyssl); set_config('system','proxyuser', $proxyuser); set_config('system','proxy', $proxy); @@ -331,6 +337,8 @@ class Site { '$directory_server' => (($dir_choices) ? array('directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices) : null), + '$sse_enabled' => array('sse_enabled', t('Enable SSE Notifications'), get_config('system', 'sse_enabled', 0), t('If disabled, traditional polling will be used. Warning: this setting might not be suited for shared hosting')), + '$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""), '$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""), '$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")), diff --git a/Zotlabs/Module/Attach.php b/Zotlabs/Module/Attach.php index 490d5edd0..172f6a4bc 100644 --- a/Zotlabs/Module/Attach.php +++ b/Zotlabs/Module/Attach.php @@ -1,61 +1,187 @@ <?php namespace Zotlabs\Module; +use ZipArchive; +use Zotlabs\Web\Controller; +use Zotlabs\Lib\Verify; + require_once('include/security.php'); require_once('include/attach.php'); +class Attach extends Controller { + + function post() { + + $attach_ids = ((x($_REQUEST, 'attach_ids')) ? $_REQUEST['attach_ids'] : []); + $attach_path = ((x($_REQUEST, 'attach_path')) ? $_REQUEST['attach_path'] : ''); + $channel_id = ((x($_REQUEST, 'channel_id')) ? intval($_REQUEST['channel_id']) : 0); + $channel = channelx_by_n($channel_id); + + if (! $channel) { + notice(t('Channel not found.') . EOL); + return; + } + + $strip_str = '/cloud/' . $channel['channel_address'] . '/'; + $count = strlen($strip_str); + $attach_path = substr($attach_path, $count); + + if ($attach_ids) { + + $zip_dir = 'store/[data]/' . $channel['channel_address'] . '/tmp'; + if (! is_dir($zip_dir)) + mkdir($zip_dir, STORAGE_DEFAULT_PERMISSIONS, true); + + $token = random_string(32); + + $zip_file = 'download_' . $token . '.zip'; + $zip_path = $zip_dir . '/' . $zip_file; + + $zip = new ZipArchive(); + + if ($zip->open($zip_path, ZipArchive::CREATE) === true) { + + $zip_filename = self::zip_archive_handler($zip, $attach_ids, $attach_path); + + $zip->close(); + + $meta = [ + 'zip_filename' => $zip_filename, + 'zip_path' => $zip_path + ]; -class Attach extends \Zotlabs\Web\Controller { + Verify::create('zip_token', 0, $token, json_encode($meta)); + + json_return_and_die([ + 'success' => true, + 'token' => $token + ]); + + } + } + } + + function get() { - function init() { - if(argc() < 2) { notice( t('Item not available.') . EOL); return; } - + + $token = ((x($_REQUEST, 'token')) ? $_REQUEST['token'] : ''); + + if(argv(1) === 'download') { + $meta = Verify::get_meta('zip_token', 0, $token); + + if(! $meta) + killme(); + + $meta = json_decode($meta, true); + + header('Content-Type: application/zip'); + header('Content-Disposition: attachment; filename="'. $meta['zip_filename'] . '"'); + header('Content-Length: ' . filesize($meta['zip_path'])); + + $istream = fopen($meta['zip_path'], 'rb'); + $ostream = fopen('php://output', 'wb'); + if($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + + unlink($meta['zip_path']); + killme(); + } + $r = attach_by_hash(argv(1),get_observer_hash(),((argc() > 2) ? intval(argv(2)) : 0)); - + if(! $r['success']) { notice( $r['message'] . EOL); return; } - + $c = q("select channel_address from channel where channel_id = %d limit 1", intval($r['data']['uid']) ); - + if(! $c) return; - - + $unsafe_types = array('text/html','text/css','application/javascript'); - + if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($r['data']['uid']))) { - header('Content-type: text/plain'); + header('Content-Type: text/plain'); } else { - header('Content-type: ' . $r['data']['filetype']); + header('Content-Type: ' . $r['data']['filetype']); } - - header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"'); + + header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"'); if(intval($r['data']['os_storage'])) { - $fname = dbunescbin($r['data']['content']); + $fname = $r['data']['content']; if(strpos($fname,'store') !== false) $istream = fopen($fname,'rb'); else $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname,'rb'); $ostream = fopen('php://output','wb'); if($istream && $ostream) { - pipe_streams($istream,$ostream); + pipe_streams($istream, $ostream); fclose($istream); fclose($ostream); } } else - echo dbunescbin($r['data']['content']); + echo $r['data']['content']; killme(); - + } - + + public function zip_archive_handler($zip, $attach_ids, $attach_path, $pass = 1) { + + $observer_hash = get_observer_hash(); + $single = ((count($attach_ids) == 1) ? true : false); + $download_name = 'download.zip'; + + foreach($attach_ids as $attach_id) { + + $r = attach_by_id($attach_id, $observer_hash); + + if (! $r['success']) { + continue; + } + + if ($r['data']['is_dir'] && $single && $pass === 1) + $download_name = $r['data']['filename'] . '.zip'; + + $zip_path = $r['data']['display_path']; + + if ($attach_path) { + $strip_str = $attach_path . '/'; + $count = strlen($strip_str); + $zip_path = substr($r['data']['display_path'], $count); + } + + if ($r['data']['is_dir']) { + $zip->addEmptyDir($zip_path); + + $d = q("SELECT id FROM attach WHERE folder = '%s'", + dbesc($r['data']['hash']) + ); + + $attach_ids = ids_to_array($d); + self::zip_archive_handler($zip, $attach_ids, $attach_path, $pass++); + } + else { + $file_path = $r['data']['content']; + $zip->addFile($file_path, $zip_path); + // compressing can be ressource intensive - just store the data + $zip->setCompressionName($zip_path, ZipArchive::CM_STORE); + } + + } + + return $download_name; + } + } diff --git a/Zotlabs/Module/Attach_edit.php b/Zotlabs/Module/Attach_edit.php new file mode 100644 index 000000000..5880d8f13 --- /dev/null +++ b/Zotlabs/Module/Attach_edit.php @@ -0,0 +1,203 @@ +<?php +namespace Zotlabs\Module; +/** + * @file Zotlabs/Module/Attach_edit.php + * + */ + +use App; +use Zotlabs\Web\Controller; +use Zotlabs\Lib\Libsync; +use Zotlabs\Access\AccessList; + +class Attach_edit extends Controller { + + function post() { + + if (!local_channel() && !remote_channel()) { + return; + } + + $attach_ids = ((x($_POST, 'attach_ids')) ? $_POST['attach_ids'] : []); + $attach_id = ((x($_POST, 'attach_id')) ? intval($_POST['attach_id']) : 0); + $channel_id = ((x($_POST, 'channel_id')) ? intval($_POST['channel_id']) : 0); + $dnd = ((x($_POST, 'dnd')) ? intval($_POST['dnd']) : 0); + $permissions = ((x($_POST, 'permissions')) ? intval($_POST['permissions']) : 0); + $return_path = ((x($_POST, 'return_path')) ? notags($_POST['return_path']) : 'cloud'); + $delete = ((x($_POST, 'delete')) ? intval($_POST['delete']) : 0); + $newfolder = ((x($_POST, 'newfolder_' . $attach_id)) ? notags($_POST['newfolder_' . $attach_id]) : ''); + if(! $newfolder) + $newfolder = ((x($_POST, 'newfolder')) ? notags($_POST['newfolder']) : ''); + $newfilename = ((x($_POST, 'newfilename_' . $attach_id)) ? notags($_POST['newfilename_' . $attach_id]) : ''); + $recurse = ((x($_POST, 'recurse_' . $attach_id)) ? intval($_POST['recurse_' . $attach_id]) : 0); + if(! $recurse) + $recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0); + $notify = ((x($_POST, 'notify_edit_' . $attach_id)) ? intval($_POST['notify_edit_' . $attach_id]) : 0); + $copy = ((x($_POST, 'copy_' . $attach_id)) ? intval($_POST['copy_' . $attach_id]) : 0); + if(! $copy) + $copy = ((x($_POST, 'copy')) ? intval($_POST['copy']) : 0); + + $categories = ((x($_POST, 'categories_' . $attach_id)) ? notags($_POST['categories_' . $attach_id]) : ''); + if(! $categories) + $categories = ((x($_POST, 'categories')) ? notags($_POST['categories']) : ''); + + if($attach_id) + $attach_ids[] = $attach_id; + + $single = ((count($attach_ids) === 1) ? true : false); + + $channel = channelx_by_n($channel_id); + + if (! $channel) { + notice(t('Channel not found.') . EOL); + return; + } + + $nick = $channel['channel_address']; + $observer = App::get_observer(); + $observer_hash = (($observer) ? $observer['xchan_hash'] : ''); + $is_owner = ((local_channel() == $channel_id) ? true : false); + + $ids_str = implode(',', $attach_ids); + + $r = q("SELECT id, uid, hash, creator, folder, filename, is_photo, is_dir FROM attach WHERE id IN ( %s ) AND uid = %d", + dbesc($ids_str), + intval($channel_id) + ); + + if (! $r) { + notice(t('File not found.') . EOL); + return; + } + + foreach ($r as $rr) { + $actions_done = ''; + $attach_id = $rr['id']; + $resource = $rr['hash']; + $creator = $rr['creator']; + $folder = $rr['folder']; + $filename = $rr['filename']; + $is_photo = intval($rr['is_photo']); + $is_dir = intval($rr['is_dir']); + $admin_delete = false; + + $is_creator = (($creator == $observer_hash) ? true : false); + $move = ((! $copy && ($folder !== $newfolder || (($single) ? $filename !== $newfilename : false))) ? true : false); + + $perms = get_all_perms($channel_id, $observer_hash); + + if (! ($perms['view_storage'] || is_site_admin())) { + notice( t('Permission denied.') . EOL); + continue; + } + + if (! $perms['write_storage']) { + if (is_site_admin()) { + $admin_delete = true; + } + else { + notice( t('Permission denied.') . EOL); + continue; + } + } + + if (!$is_owner && !$admin_delete) { + if(! $is_creator) { + notice( t('Permission denied.') . EOL); + continue; + } + } + + if ($delete) { + attach_delete($channel_id, $resource, $is_photo); + $actions_done .= 'delete,'; + } + + if ($copy) { + if($is_dir && $resource == $newfolder) { + notice( t('Can not copy folder into itself.') . EOL); + continue; + } + $x = attach_copy($channel_id, $resource, $newfolder, (($single) ? $newfilename : '')); + if ($x['success']) + $resource = $x['resource_id']; + + $actions_done .= 'copy,'; + + } + + if ($move) { + if($is_dir && $resource == $newfolder) { + notice( sprintf(t('Can not move folder "%s" into itself.'), $filename) . EOL); + continue; + } + $x = attach_move($channel_id, $resource, $newfolder, (($single) ? $newfilename : '')); + + $actions_done .= 'move,'; + + } + + if(! $delete && ! $dnd) { + if ($single || (! $single && $categories)) { + q("DELETE FROM term WHERE uid = %d AND oid = %d AND otype = %d", + intval($channel_id), + intval($attach_id), + intval(TERM_OBJ_FILE) + ); + $cat = explode(',', $categories); + if ($cat) { + foreach($cat as $term) { + $term = trim(escape_tags($term)); + if ($term) { + $term_link = z_root() . '/cloud/' . $nick . '/?cat=' . $term; + store_item_tag($channel_id, $attach_id, TERM_OBJ_FILE, TERM_CATEGORY, $term, $term_link); + } + } + $actions_done .= 'cat_add,'; + } + } + else { + q("DELETE FROM term WHERE uid = %d AND oid = %d AND otype = %d", + intval($channel_id), + intval($attach_id), + intval(TERM_OBJ_FILE) + ); + $actions_done .= 'cat_remove,'; + } + + if ($is_owner && ($single || (! $single && $permissions))) { + $acl = new AccessList($channel); + $acl->set_from_array($_REQUEST); + $x = $acl->get(); + + attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true); + $actions_done .= 'permissions,'; + + if ($notify) { + attach_store_item($channel, $observer, $resource); + $actions_done .= 'notify,'; + } + } + } + + if (! $admin_delete && $actions_done) { + $sync = attach_export_data($channel, $resource, (($delete) ? true : false)); + + if ($sync) { + Libsync::build_sync_packet($channel_id, ['file' => [$sync]]); + } + } + + logger('attach_edit: ' . $actions_done); + + } + + if($dnd || $delete) { + json_return_and_die([ 'success' => true ]); + } + + goaway($return_path); + + } + +} diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index d7d57664c..f5c5f4384 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -5,6 +5,9 @@ use App; use Zotlabs\Lib\Apps; use Zotlabs\Web\Controller; use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Libsync; + require_once('include/event.php'); @@ -47,11 +50,12 @@ class Cdav extends Controller { if($sigblock) { $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { - $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select * from hubloc where hubloc_id_url = '%s'", dbesc($keyId) ); if($r) { - $c = channelx_by_hash($r[0]['hubloc_hash']); + $r = Libzot::zot_record_preferred($r); + $c = channelx_by_hash($r['hubloc_hash']); if($c) { $a = q("select * from account where account_id = %d limit 1", intval($c['channel_account_id']) @@ -157,10 +161,10 @@ class Cdav extends Controller { } } - + // Track CDAV updates from remote clients - $httpmethod = $_SERVER['REQUEST_METHOD']; + $httpmethod = $_SERVER['REQUEST_METHOD']; if($httpmethod === 'PUT' || $httpmethod === 'DELETE') { @@ -190,12 +194,12 @@ class Cdav extends Controller { if($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) { $cdavdata = $this->get_cdav_data($x['id'], $cdavtable); - + $etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false); - + // delete if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ $sync => [ 'action' => 'delete_card', 'uri' => $cdavdata['uri'], @@ -206,7 +210,7 @@ class Cdav extends Controller { if($etag) { // update if($cdavdata['etag'] !== $etag) - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ $sync => [ 'action' => 'update_card', 'uri' => $cdavdata['uri'], @@ -217,7 +221,7 @@ class Cdav extends Controller { } else { // new - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ $sync => [ 'action' => 'import', 'uri' => $cdavdata['uri'], @@ -337,7 +341,7 @@ class Cdav extends Controller { // set new calendar to be visible set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'create', 'uri' => $calendarUri, @@ -413,7 +417,7 @@ class Cdav extends Controller { $calendarData = $vcalendar->serialize(); $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'import', 'uri' => $cdavdata['uri'], @@ -444,7 +448,7 @@ class Cdav extends Controller { $caldavBackend->updateCalendar($id, $patch); $patch->commit(); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'edit', 'uri' => $cdavdata['uri'], @@ -510,7 +514,7 @@ class Cdav extends Controller { $calendarData = $vcalendar->serialize(); $caldavBackend->updateCalendarObject($id, $uri, $calendarData); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'update_card', 'uri' => $cdavdata['uri'], @@ -536,7 +540,7 @@ class Cdav extends Controller { $caldavBackend->deleteCalendarObject($id, $uri); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'delete_card', 'uri' => $cdavdata['uri'], @@ -594,7 +598,7 @@ class Cdav extends Controller { $calendarData = $vcalendar->serialize(); $caldavBackend->updateCalendarObject($id, $uri, $calendarData); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'update_card', 'uri' => $cdavdata['uri'], @@ -653,7 +657,7 @@ class Cdav extends Controller { $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'create', 'uri' => $addressbookUri, @@ -680,7 +684,7 @@ class Cdav extends Controller { $carddavBackend->updateAddressBook($id, $patch); $patch->commit(); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'edit', 'uri' => $cdavdata['uri'], @@ -724,7 +728,7 @@ class Cdav extends Controller { $cardData = $vcard->serialize(); $carddavBackend->createCard($id, $uri, $cardData); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'import', 'uri' => $cdavdata['uri'], @@ -762,8 +766,8 @@ class Cdav extends Controller { $cardData = $vcard->serialize(); $carddavBackend->updateCard($id, $uri, $cardData); - - build_sync_packet($channel['channel_id'], [ + + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'update_card', 'uri' => $cdavdata['uri'], @@ -788,7 +792,7 @@ class Cdav extends Controller { $carddavBackend->deleteCard($id, $uri); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'delete_card', 'uri' => $cdavdata['uri'], @@ -804,7 +808,7 @@ class Cdav extends Controller { $src = $_FILES['userfile']['tmp_name']; if($src) { - + $carddata = @file_get_contents($src); if($_REQUEST['c_upload']) { @@ -840,14 +844,14 @@ class Cdav extends Controller { $objects = new \Sabre\VObject\Splitter\VCard($carddata); $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; $backend = new \Sabre\CardDAV\Backend\PDO($pdo); - + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); } - + $ids = []; import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true); - - build_sync_packet($channel['channel_id'], [ + + Libsync::build_sync_packet($channel['channel_id'], [ $sync => [ 'action' => 'import', 'uri' => $cdavdata['uri'], @@ -1013,7 +1017,7 @@ class Cdav extends Controller { $catsenabled = feature_enabled(local_channel(), 'categories'); require_once('include/acl_selectors.php'); - + $accesslist = new \Zotlabs\Access\AccessList($channel); $perm_defaults = $accesslist->get(); @@ -1167,7 +1171,7 @@ class Cdav extends Controller { set_pconfig(local_channel(), 'cdav_calendar', $id, argv(4)); - build_sync_packet(local_channel(), [ + Libsync::build_sync_packet(local_channel(), [ 'calendar' => [ 'action' => 'switch', 'uri' => $cdavdata['uri'], @@ -1190,7 +1194,7 @@ class Cdav extends Controller { $caldavBackend->deleteCalendar($id); - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'calendar' => [ 'action' => 'drop', 'uri' => $cdavdata['uri'] @@ -1409,7 +1413,7 @@ class Cdav extends Controller { $carddavBackend->deleteAddressBook($id); if($cdavdata) - build_sync_packet($channel['channel_id'], [ + Libsync::build_sync_packet($channel['channel_id'], [ 'addressbook' => [ 'action' => 'drop', 'uri' => $cdavdata['uri'] @@ -1427,7 +1431,7 @@ class Cdav extends Controller { return; $uri = 'principals/' . $channel['channel_address']; - + $r = q("select * from principals where uri = '%s' limit 1", dbesc($uri) diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index dc8e9e1c5..7ff394750 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -130,9 +130,6 @@ class Channel extends Controller { $noscript_content = get_config('system', 'noscript_content', '1'); - if($load) - $_SESSION['loadtime'] = datetime_convert(); - $category = $datequery = $datequery2 = ''; $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); @@ -152,7 +149,6 @@ class Channel extends Controller { $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); $order = ((x($_GET,'order')) ? notags($_GET['order']) : 'post'); - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); $search = ((x($_GET,'search')) ? $_GET['search'] : EMPTY_STR); $groups = array(); @@ -187,8 +183,6 @@ class Channel extends Controller { nav_set_selected('Channel Home'); - $static = channel_manual_conv_update(App::$profile['profile_uid']); - // search terms header if($search) { $o .= replace_macros(get_markup_template("section_title.tpl"),array( @@ -255,7 +249,9 @@ class Channel extends Controller { $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; - $simple_update = (($update) ? " AND item_unseen = 1 " : ''); + $simple_update = ''; + if($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; if($search) { $search = escape_tags($search); @@ -270,7 +266,6 @@ class Channel extends Controller { } } - head_add_link([ 'rel' => 'alternate', 'type' => 'application/json+oembed', @@ -278,14 +273,6 @@ class Channel extends Controller { 'title' => 'oembed' ]); - if($update && $_SESSION['loadtime']) - $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; - if($load) - $simple_update = ''; - - if($static && $simple_update) - $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - if(($update) && (! $load)) { if($mid) { @@ -294,7 +281,6 @@ class Channel extends Controller { dbesc($mid . '%'), intval(App::$profile['profile_uid']) ); - $_SESSION['loadtime'] = datetime_convert(); } else { $r = q("SELECT parent AS item_id from item @@ -306,9 +292,7 @@ class Channel extends Controller { ORDER BY created DESC", intval(App::$profile['profile_uid']) ); - $_SESSION['loadtime'] = datetime_convert(); } - } else { @@ -406,7 +390,7 @@ class Channel extends Controller { $o .= '<div id="live-channel"></div>' . "\r\n"; $o .= "<script> var profile_uid = " . App::$profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . App::$pager['page'] - . "; divmore_height = " . intval($maxheight) . "; </script>\r\n"; + . "; divmore_height = " . intval($maxheight) . ";</script>\r\n"; App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( '$baseurl' => z_root(), @@ -424,7 +408,6 @@ class Channel extends Controller { '$wall' => '1', '$fh' => '0', '$dm' => '0', - '$static' => $static, '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), '$search' => $search, '$xchan' => '', @@ -437,7 +420,8 @@ class Channel extends Controller { '$verb' => '', '$net' => '', '$dend' => $datequery, - '$dbegin' => $datequery2 + '$dbegin' => $datequery2, + '$conv_mode' => 'channel' )); } @@ -476,6 +460,8 @@ class Channel extends Controller { if($mid) $o .= '<div id="content-complete"></div>'; + $_SESSION['loadtime'] = datetime_convert(); + return $o; } } diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index f595e0fac..39ae0f92f 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -8,7 +8,11 @@ namespace Zotlabs\Module; */ use Sabre\DAV as SDAV; -use \Zotlabs\Storage; +use \Zotlabs\Web\Controller; +use \Zotlabs\Storage\BasicAuth; +use \Zotlabs\Storage\Directory; +use \Zotlabs\Storage\Browser; + // composer autoloader for SabreDAV require_once('vendor/autoload.php'); @@ -20,7 +24,7 @@ require_once('include/attach.php'); * @brief Cloud Module. * */ -class Cloud extends \Zotlabs\Web\Controller { +class Cloud extends Controller { /** * @brief Fires up the SabreDAV server. @@ -42,7 +46,7 @@ class Cloud extends \Zotlabs\Web\Controller { - $auth = new \Zotlabs\Storage\BasicAuth(); + $auth = new BasicAuth(); $ob_hash = get_observer_hash(); @@ -72,7 +76,7 @@ class Cloud extends \Zotlabs\Web\Controller { if($x !== \App::$query_string) goaway(z_root() . '/' . $x); - $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); + $rootDirectory = new Directory('/', [], $auth); // A SabreDAV server-object $server = new SDAV\Server($rootDirectory); @@ -85,7 +89,7 @@ class Cloud extends \Zotlabs\Web\Controller { $is_readable = false; // provide a directory view for the cloud in Hubzilla - $browser = new \Zotlabs\Storage\Browser($auth); + $browser = new Browser($auth); $auth->setBrowserPlugin($browser); $server->addPlugin($browser); @@ -105,13 +109,13 @@ class Cloud extends \Zotlabs\Web\Controller { if($browser->build_page) construct_page(); - + killme(); } function DAVException($err) { - + if($err instanceof \Sabre\DAV\Exception\NotFound) { notice( t('Not found') . EOL); } @@ -126,7 +130,7 @@ class Cloud extends \Zotlabs\Web\Controller { } construct_page(); - + killme(); } diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php index adab25e45..82d773139 100644 --- a/Zotlabs/Module/Dav.php +++ b/Zotlabs/Module/Dav.php @@ -51,11 +51,12 @@ class Dav extends \Zotlabs\Web\Controller { if($sigblock) { $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { - $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select * from hubloc where hubloc_id_url = '%s'", dbesc($keyId) ); if($r) { - $c = channelx_by_hash($r[0]['hubloc_hash']); + $r = Libzot::zot_record_preferred($r); + $c = channelx_by_hash($r['hubloc_hash']); if($c) { $a = q("select * from account where account_id = %d limit 1", intval($c['channel_account_id']) @@ -99,7 +100,7 @@ class Dav extends \Zotlabs\Web\Controller { $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV'); - $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); + $rootDirectory = new \Zotlabs\Storage\Directory('/', [], $auth); // A SabreDAV server-object $server = new SDAV\Server($rootDirectory); diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index e1bf0f6cf..7295f3099 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -4,6 +4,8 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; +use Zotlabs\Lib\Libzotdir; + require_once('include/socgraph.php'); require_once('include/dir_fns.php'); @@ -15,7 +17,7 @@ class Directory extends Controller { function init() { App::set_pager_itemspage(30); - + if(local_channel() && x($_GET,'ignore')) { q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", intval(local_channel()), @@ -26,12 +28,12 @@ class Directory extends Controller { if(local_channel()) App::$profile_uid = local_channel(); - + $observer = get_observer_hash(); $global_changed = false; $safe_changed = false; $pubforums_changed = false; - + if(array_key_exists('global',$_REQUEST)) { $globaldir = intval($_REQUEST['global']); $global_changed = true; @@ -41,7 +43,7 @@ class Directory extends Controller { if($observer) set_xconfig($observer,'directory','globaldir',$globaldir); } - + if(array_key_exists('safe',$_REQUEST)) { $safemode = intval($_REQUEST['safe']); $safe_changed = true; @@ -51,8 +53,8 @@ class Directory extends Controller { if($observer) set_xconfig($observer,'directory','safemode',$safemode); } - - + + if(array_key_exists('pubforums',$_REQUEST)) { $pubforums = intval($_REQUEST['pubforums']); $pubforums_changed = true; @@ -64,52 +66,52 @@ class Directory extends Controller { } } - + function get() { - + if(observer_prohibited()) { notice( t('Public access denied.') . EOL); return; } - + if(get_config('system','block_public_directory',false) && (! get_observer_hash())) { notice( t('Public access denied.') . EOL); return; } - + $observer = get_observer_hash(); - - $globaldir = get_directory_setting($observer, 'globaldir'); + + $globaldir = Libzotdir::get_directory_setting($observer, 'globaldir'); // override your personal global search pref if we're doing a navbar search of the directory if(intval($_REQUEST['navsearch'])) $globaldir = 1; - - $safe_mode = get_directory_setting($observer, 'safemode'); - - $pubforums = get_directory_setting($observer, 'pubforums'); - + + $safe_mode = Libzotdir::get_directory_setting($observer, 'safemode'); + + $pubforums = Libzotdir::get_directory_setting($observer, 'pubforums'); + $o = ''; nav_set_selected('Directory'); - + if(x($_POST,'search')) $search = notags(trim($_POST['search'])); else $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); - - + + if(strpos($search,'=') && local_channel() && feature_enabled(local_channel(), 'advanced_dirsearch')) $advanced = $search; - + $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); - + // Suggest channels if no search terms or keywords are given $suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : ''; - + if($suggest) { // the directory options have no effect in suggestion mode - + $globaldir = 1; $safe_mode = 1; $type = 0; @@ -120,7 +122,7 @@ class Directory extends Controller { notice( t('No default suggestions were found.') . EOL); return; } - + // Remember in which order the suggestions were $addresses = array(); $common = array(); @@ -129,7 +131,7 @@ class Directory extends Controller { $common[$rr['xchan_addr']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0); $addresses[$rr['xchan_addr']] = $index++; } - + // Build query to get info about suggested people $advanced = ''; foreach(array_keys($addresses) as $address) { @@ -137,13 +139,13 @@ class Directory extends Controller { } // Remove last space in the advanced query $advanced = rtrim($advanced); - + } - + $tpl = get_markup_template('directory_header.tpl'); - + $dirmode = intval(get_config('system','directory_mode')); - + $directory_admin = false; if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { @@ -154,19 +156,19 @@ class Directory extends Controller { } if(! $url) { - $directory = find_upstream_directory($dirmode); + $directory = Libzotdir::find_upstream_directory($dirmode); if((! $directory) || (! array_key_exists('url',$directory)) || (! $directory['url'])) logger('CRITICAL: No directory server URL'); $url = $directory['url'] . '/dirsearch'; } - + $token = get_config('system','realm_token'); - - + + logger('mod_directory: URL = ' . $url, LOGGER_DEBUG); - + $contacts = array(); - + if(local_channel()) { $x = q("select abook_xchan from abook where abook_channel = %d", intval(local_channel()) @@ -176,24 +178,24 @@ class Directory extends Controller { $contacts[] = $xx['abook_xchan']; } } - + if($url) { - + $numtags = get_config('system','directorytags'); - + $kw = ((intval($numtags) > 0) ? intval($numtags) : 50); - + if(get_config('system','disable_directory_keywords')) $kw = 0; - + $query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : ''); - + if($token) $query .= '&t=' . $token; - + if(! $globaldir) $query .= '&hub=' . App::get_hostname(); - + if($search) $query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search); if(strpos($search,'@')) @@ -204,29 +206,29 @@ class Directory extends Controller { $query .= '&query=' . urlencode($advanced); if(! is_null($pubforums)) $query .= '&pubforums=' . intval($pubforums); - + $directory_sort_order = get_config('system','directory_sort_order'); if(! $directory_sort_order) $directory_sort_order = 'date'; - + $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : $directory_sort_order); - + if($sort_order) $query .= '&order=' . urlencode($sort_order); - + if(App::$pager['page'] != 1) $query .= '&p=' . App::$pager['page']; - + logger('mod_directory: query: ' . $query); - + $x = z_fetch_url($query); logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA); - + if($x['success']) { $t = 0; $j = json_decode($x['body'],true); if($j) { - + if($j['results']) { $results = $j['results']; @@ -235,23 +237,23 @@ class Directory extends Controller { } $entries = array(); - + $photo = 'thumb'; - + foreach($results as $rr) { - + $profile_link = chanlink_url($rr['url']); - + $pdesc = (($rr['description']) ? $rr['description'] . '<br />' : ''); - $connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); - + $connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); + // Checking status is disabled ATM until someone checks the performance impact more carefully //$online = remote_online_status($rr['address']); $online = ''; - + if(in_array($rr['hash'],$contacts)) $connect_link = ''; - + $location = ''; if(strlen($rr['locale'])) $location .= $rr['locale']; @@ -265,53 +267,53 @@ class Directory extends Controller { $location .= ', '; $location .= $rr['country']; } - + $age = ''; if(strlen($rr['birthday'])) { if(($years = age($rr['birthday'],'UTC','')) > 0) $age = $years; } - + $page_type = ''; - + $rating_enabled = get_config('system','rating_enabled'); if($rr['total_ratings'] && $rating_enabled) $total_ratings = sprintf( tt("%d rating", "%d ratings", $rr['total_ratings']), $rr['total_ratings']); else $total_ratings = ''; - + $profile = $rr; - + if ((x($profile,'locale') == 1) || (x($profile,'region') == 1) || (x($profile,'postcode') == 1) || (x($profile,'country') == 1)) - + $gender = ((x($profile,'gender') == 1) ? t('Gender: ') . $profile['gender']: False); - + $marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False); - + $homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False); - $homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : ''); - + $homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : ''); + $hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False); - + $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False); if ($about && $safe_mode) { $about = html2plain($about); } - + $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); - + $out = ''; - + if($keywords) { $keywords = str_replace(',',' ', $keywords); $keywords = str_replace(' ',' ', $keywords); $karr = explode(' ', $keywords); - + if($karr) { if(local_channel()) { $r = q("select keywords from profile where uid = %d and is_default = 1 limit 1", @@ -332,9 +334,9 @@ class Directory extends Controller { $out .= '<a href="' . z_root() . '/directory/f=&keywords=' . urlencode($k) .'">' . $k . '</a>'; } } - + } - + $entry = array( 'id' => ++$t, 'profile_link' => $profile_link, @@ -366,7 +368,7 @@ class Directory extends Controller { 'about' => $about, 'about_label' => t('About:'), 'conn_label' => t('Connect'), - 'forum_label' => t('Public Forum:'), + 'forum_label' => t('Public Forum:'), 'connect' => $connect_link, 'online' => $online, 'kw' => (($out) ? t('Keywords: ') : ''), @@ -378,36 +380,36 @@ class Directory extends Controller { 'common_count' => intval($common[$rr['address']]), 'safe' => $safe_mode ); - + $arr = array('contact' => $rr, 'entry' => $entry); - + call_hooks('directory_item', $arr); - + unset($profile); unset($location); - + if(! $arr['entry']) { continue; - } - + } + if($sort_order == '' && $suggest) { $entries[$addresses[$rr['address']]] = $arr['entry']; // Use the same indexes as originally to get the best suggestion first } - + else { $entries[] = $arr['entry']; } } - + ksort($entries); // Sort array by key so that foreach-constructs work as expected - + if($j['keywords']) { App::$data['directory_keywords'] = $j['keywords']; } - + logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA); - - + + if($_REQUEST['aj']) { if($entries) { $o = replace_macros(get_markup_template('directajax.tpl'),array( @@ -422,9 +424,9 @@ class Directory extends Controller { } else { $maxheight = 94; - + $dirtitle = (($globaldir) ? t('Global Directory') : t('Local Directory')); - + $o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; divmore_height = " . intval($maxheight) . "; </script>"; $o .= replace_macros($tpl, array( '$search' => $search, @@ -442,10 +444,10 @@ class Directory extends Controller { '$reversedate' => t('Oldest to Newest'), '$suggest' => $suggest ? '&suggest=1' : '' )); - - + + } - + } else { if($_REQUEST['aj']) { @@ -463,7 +465,7 @@ class Directory extends Controller { } return $o; } - + static public function reorder_results($results,$suggests) { if(! $suggests) diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php index c15b13a90..804d7af5c 100644 --- a/Zotlabs/Module/Dirsearch.php +++ b/Zotlabs/Module/Dirsearch.php @@ -192,7 +192,7 @@ class Dirsearch extends Controller { else { $qlimit = " LIMIT " . intval($perpage) . " OFFSET " . intval($startrec); if($return_total) { - $r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra and xchan_network = 'zot' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql "); + $r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra and xchan_network = 'zot6' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql "); if($r) { $ret['total_items'] = $r[0]['total']; } @@ -261,7 +261,7 @@ class Dirsearch extends Controller { else { $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash - where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot' and xchan_system = 0 and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 + where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot6' and xchan_system = 0 and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql $order $qlimit " ); diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 3d61d7018..81ac0f7b8 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -22,9 +22,6 @@ class Display extends \Zotlabs\Web\Controller { $module_format = 'html'; } - if($load) - $_SESSION['loadtime'] = datetime_convert(); - if(observer_prohibited()) { notice( t('Public access denied.') . EOL); return; @@ -183,22 +180,11 @@ class Display extends \Zotlabs\Web\Controller { return ''; } - - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - - $simple_update = (($update) ? " AND item_unseen = 1 " : ''); - + $simple_update = ''; if($update && $_SESSION['loadtime']) $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; - if($load) - $simple_update = ''; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - - if((! $update) && (! $load)) { - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); + if((! $update) && (! $load)) { // if the target item is not a post (eg a like) we want to address its thread parent @@ -229,7 +215,6 @@ class Display extends \Zotlabs\Web\Controller { '$dm' => '0', '$nouveau' => '0', '$wall' => '0', - '$static' => $static, '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1), '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$search' => '', @@ -315,7 +300,6 @@ class Display extends \Zotlabs\Web\Controller { dbesc($target_item['parent_mid']) ); } - if($r === null) { // in case somebody turned off public access to sys channel content using permissions // make that content unsearchable by ensuring the owner_xchan can't match @@ -335,7 +319,6 @@ class Display extends \Zotlabs\Web\Controller { intval($sysid) ); } - $_SESSION['loadtime'] = datetime_convert(); } else { @@ -448,6 +431,8 @@ class Display extends \Zotlabs\Web\Controller { } + $_SESSION['loadtime'] = datetime_convert(); + return $o; } diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php index 1735e9487..e18067e20 100644 --- a/Zotlabs/Module/File_upload.php +++ b/Zotlabs/Module/File_upload.php @@ -11,17 +11,16 @@ require_once('include/photos.php'); class File_upload extends \Zotlabs\Web\Controller { function post() { - logger('file upload: ' . print_r($_REQUEST,true)); logger('file upload: ' . print_r($_FILES,true)); - + $channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null); - + if(! $channel) { logger('channel not found'); killme(); } - + $_REQUEST['source'] = 'file_upload'; if($channel['channel_id'] != local_channel()) { @@ -40,13 +39,11 @@ class File_upload extends \Zotlabs\Web\Controller { $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST); if($r['success']) { $hash = $r['data']['hash']; - $sync = attach_export_data($channel,$hash); if($sync) { Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync))); } - goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']); - + goaway(z_root() . '/' . $_REQUEST['return_url']); } } else { @@ -54,8 +51,6 @@ class File_upload extends \Zotlabs\Web\Controller { $matches = []; $partial = false; - - if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); if($pm) { @@ -69,7 +64,7 @@ class File_upload extends \Zotlabs\Web\Controller { if($x['partial']) { header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($result); + json_return_and_die($x); } else { header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); @@ -83,7 +78,7 @@ class File_upload extends \Zotlabs\Web\Controller { ]; } } - else { + else { if(! array_key_exists('userfile',$_FILES)) { $_FILES['userfile'] = [ 'name' => $_FILES['files']['name'], @@ -103,8 +98,9 @@ class File_upload extends \Zotlabs\Web\Controller { } } + goaway(z_root() . '/' . $_REQUEST['return_url']); - + } - + } diff --git a/Zotlabs/Module/Filer.php b/Zotlabs/Module/Filer.php index af59f28fb..c2747e6c2 100644 --- a/Zotlabs/Module/Filer.php +++ b/Zotlabs/Module/Filer.php @@ -31,7 +31,8 @@ class Filer extends \Zotlabs\Web\Controller { intval(local_channel()) ); if($r) { - $x = q("update item set item_retained = 1 where id = %d and uid = %d", + $x = q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d", + dbesc(datetime_convert()), intval($r[0]['parent']), intval(local_channel()) ); diff --git a/Zotlabs/Module/Filerm.php b/Zotlabs/Module/Filerm.php index cbf6a118d..9fdfe6c46 100644 --- a/Zotlabs/Module/Filerm.php +++ b/Zotlabs/Module/Filerm.php @@ -28,10 +28,14 @@ class Filerm extends \Zotlabs\Web\Controller { intval($item_id), dbesc($term) ); + + $x = q("update item set item_retained = 0, changed = '%s' where id = %d and uid = %d", + dbesc(datetime_convert()), + intval($item_id), + intval(local_channel()) + ); + } - - if(x($_SESSION,'return_url')) - goaway(z_root() . '/' . $_SESSION['return_url']); killme(); } diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php index 0c6233493..0d132e998 100644 --- a/Zotlabs/Module/Filestorage.php +++ b/Zotlabs/Module/Filestorage.php @@ -11,6 +11,9 @@ class Filestorage extends \Zotlabs\Web\Controller { function post() { + notice( t('Deprecated!') . EOL); + return; + $channel_id = ((x($_POST, 'uid')) ? intval($_POST['uid']) : 0); if((! $channel_id) || (! local_channel()) || ($channel_id != local_channel())) { @@ -47,6 +50,9 @@ class Filestorage extends \Zotlabs\Web\Controller { function get() { + notice( t('Deprecated!') . EOL); + return; + if(argc() > 1) $which = argv(1); else { @@ -88,7 +94,7 @@ class Filestorage extends \Zotlabs\Web\Controller { } else { notice( t('Permission denied.') . EOL); - if($json_return) + if($json_return) json_return_and_die([ 'success' => false ]); return; } @@ -102,24 +108,23 @@ class Filestorage extends \Zotlabs\Web\Controller { if(! $r) { notice( t('File not found.') . EOL); - if($json_return) + if($json_return) json_return_and_die([ 'success' => false ]); goaway(z_root() . '/cloud/' . $which); } - if(local_channel() !== $owner) { + if((local_channel() !== $owner) && !$admin_delete) { if($r[0]['creator'] && $r[0]['creator'] !== $ob_hash) { notice( t('Permission denied.') . EOL); - if($json_return) + if($json_return) json_return_and_die([ 'success' => false ]); goaway(z_root() . '/cloud/' . $which); } } - $f = $r[0]; $channel = channelx_by_n($owner); @@ -138,7 +143,7 @@ class Filestorage extends \Zotlabs\Web\Controller { if($json_return) json_return_and_die([ 'success' => true ]); - goaway(dirname($url)); + //goaway(dirname($url)); } diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php index 6d31d23fd..20cc23ac0 100644 --- a/Zotlabs/Module/Getfile.php +++ b/Zotlabs/Module/Getfile.php @@ -2,23 +2,24 @@ namespace Zotlabs\Module; use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Libzot; /** * module: getfile - * + * * used for synchronising files and photos across clones - * + * * The site initiating the file operation will send a sync packet to known clones. * They will respond by building the DB structures they require, then will provide a * post request to this site to grab the file data. This is sent as a stream direct to * disk at the other end, avoiding memory issues. * * Since magic-auth cannot easily be used by the CURL process at the other end, - * we will require a signed request which includes a timestamp. This should not be - * used without SSL and is potentially vulnerable to replay if an attacker decrypts + * we will require a signed request which includes a timestamp. This should not be + * used without SSL and is potentially vulnerable to replay if an attacker decrypts * the SSL traffic fast enough. The amount of time slop is configurable but defaults * to 3 minutes. - * + * */ @@ -53,13 +54,13 @@ class Getfile extends \Zotlabs\Web\Controller { $keyId = $sigblock['keyId']; if($keyId) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where hubloc_addr = '%s' limit 1", + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash + where hubloc_id_url = '%s'", dbesc(str_replace('acct:','',$keyId)) ); if($r) { - $hubloc = $r[0]; - $verified = HTTPSig::verify('',$hubloc['xchan_pubkey']); + $hubloc = Libzot::zot_record_preferred($r); + $verified = HTTPSig::verify('',$hubloc['xchan_pubkey']); if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) { $header_verified = true; } @@ -73,15 +74,15 @@ class Getfile extends \Zotlabs\Web\Controller { logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO); if($header_verified) { logger('HTTPSig verified'); - } - + } + $channel = channelx_by_hash($hash); if((! $channel) || (! $time) || (! $sig)) { logger('error: missing info'); killme(); } - + if(isset($_POST['resolution'])) $resolution = intval($_POST['resolution']); elseif(substr($resource,-2,1) == '-') { @@ -90,21 +91,21 @@ class Getfile extends \Zotlabs\Web\Controller { } else { $resolution = (-1); - } + } $slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop')); if($slop < 1) $slop = 3; - + $d1 = datetime_convert('UTC','UTC',"now + $slop minutes"); - $d2 = datetime_convert('UTC','UTC',"now - $slop minutes"); - + $d2 = datetime_convert('UTC','UTC',"now - $slop minutes"); + if(! $header_verified) { if(($time > $d1) || ($time < $d2)) { logger('time outside allowable range'); killme(); } - + if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) { logger('verify failed.'); killme(); @@ -136,20 +137,20 @@ class Getfile extends \Zotlabs\Web\Controller { else { echo dbunescbin($r[0]['content']); } - } + } killme(); } $r = attach_by_hash($resource,$channel['channel_hash'],$revision); - + if(! $r['success']) { logger('attach_by_hash failed: ' . $r['message']); notice( $r['message'] . EOL); return; } - + $unsafe_types = array('text/html','text/css','application/javascript'); - + if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($channel['channel_id']))) { header('Content-type: text/plain'); } diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index e2678c07f..4c2067299 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -38,9 +38,6 @@ class Hq extends \Zotlabs\Web\Controller { if(!local_channel()) return; - if($load) - $_SESSION['loadtime'] = datetime_convert(); - if(argc() > 1 && argv(1) !== 'load') { $item_hash = argv(1); } @@ -87,15 +84,9 @@ class Hq extends \Zotlabs\Web\Controller { goaway(z_root() . '/moderate/' . $target_item['id']); } - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - - $simple_update = (($update) ? " AND item_unseen = 1 " : ''); - + $simple_update = ''; if($update && $_SESSION['loadtime']) $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; $sys = get_sys_channel(); $sql_extra = item_permissions_sql($sys['channel_id']); @@ -148,8 +139,6 @@ class Hq extends \Zotlabs\Web\Controller { nav_set_selected('HQ'); - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - if($target_item) { // if the target item is not a post (eg a like) we want to address its thread parent //$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); @@ -182,8 +171,7 @@ class Hq extends \Zotlabs\Web\Controller { '$dm' => '0', '$nouveau' => '0', '$wall' => '0', - '$static' => $static, - '$page' => 1, + '$page' => '1', '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$search' => '', '$xchan' => '', @@ -249,8 +237,6 @@ class Hq extends \Zotlabs\Web\Controller { intval($sys['channel_id']) ); } - - $_SESSION['loadtime'] = datetime_convert(); } else { $r = []; @@ -275,6 +261,8 @@ class Hq extends \Zotlabs\Web\Controller { $o .= '<div id="content-complete"></div>'; + $_SESSION['loadtime'] = datetime_convert(); + return $o; } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index 2c6e09fa7..f8fc366e0 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -68,7 +68,7 @@ class Import extends \Zotlabs\Web\Controller { notice( t('Nothing to import.') . EOL); return; } else if(strpos($old_address, 'ï¼ ')) { - // if you copy the identity address from your profile page, make it work for convenience - WARNING: this is a utf-8 variant and NOT an ASCII ampersand. Please do not edit. + // if you copy the identity address from your profile page, make it work for convenience - WARNING: this is a utf-8 variant and NOT an ASCII ampersand. Please do not edit. $old_address = str_replace('ï¼ ', '@', $old_address); } @@ -231,7 +231,8 @@ class Import extends \Zotlabs\Web\Controller { 'hubloc_host' => \App::get_hostname(), 'hubloc_callback' => z_root() . '/post', 'hubloc_sitekey' => get_config('system','pubkey'), - 'hubloc_updated' => datetime_convert() + 'hubloc_updated' => datetime_convert(), + 'hubloc_id_url' => channel_url($channel) ] ); @@ -442,7 +443,7 @@ class Import extends \Zotlabs\Web\Controller { if(array_key_exists('abook_instance',$abook) && $abook['abook_instance'] && strpos($abook['abook_instance'],z_root()) === false) { $abook['abook_not_here'] = 1; - } + } if($abook['abook_self']) { $role = get_pconfig($channel['channel_id'],'system','permissions_role'); @@ -584,11 +585,6 @@ class Import extends \Zotlabs\Web\Controller { if(array_key_exists('item_id',$data) && $data['item_id']) import_item_ids($channel,$data['item_id']); - // send out refresh requests - // notify old server that it may no longer be primary. - - \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id'])); - // This will indirectly perform a refresh_all *and* update the directory \Zotlabs\Daemon\Master::Summon(array('Directory', $channel['channel_id'])); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 922a2ef06..83424a50d 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -20,22 +20,23 @@ use App; require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/security.php'); +require_once('include/conversation.php'); /** * * This is the POST destination for most all locally posted - * text stuff. This function handles status, wall-to-wall status, - * local comments, and remote coments that are posted on this site + * text stuff. This function handles status, wall-to-wall status, + * local comments, and remote coments that are posted on this site * (as opposed to being delivered in a feed). - * Also processed here are posts and comments coming through the - * statusnet/twitter API. - * All of these become an "item" which is our basic unit of + * Also processed here are posts and comments coming through the + * statusnet/twitter API. + * All of these become an "item" which is our basic unit of * information. - * Posts that originate externally or do not fall into the above - * posting categories go through item_store() instead of this function. + * Posts that originate externally or do not fall into the above + * posting categories go through item_store() instead of this function. * - */ + */ class Item extends Controller { @@ -106,7 +107,7 @@ class Item extends Controller { } $parents_str = ids_to_querystr($i,'item_id'); - + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal order by item.id asc", dbesc($parents_str) ); @@ -284,7 +285,7 @@ class Item extends Controller { // This will change. Figure out who the observer is and whether or not // they have permission to post here. Else ignore the post. - + if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'anonname'))) return; @@ -292,24 +293,25 @@ class Item extends Controller { $channel = null; $observer = null; $datarray = []; - - + + /** * Is this a reply to something? */ - + $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); $parent_mid = ((x($_REQUEST,'parent_mid')) ? trim($_REQUEST['parent_mid']) : ''); - + $mode = (($_REQUEST['conv_mode'] === 'channel') ? 'channel' : 'network'); + $remote_xchan = ((x($_REQUEST,'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false); $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($remote_xchan) ); if($r) $remote_observer = $r[0]; - else + else $remote_xchan = $remote_observer = false; - + $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); require_once('include/channel.php'); @@ -319,7 +321,7 @@ class Item extends Controller { $channel = $sys; $observer = $sys; } - + if(x($_REQUEST,'dropitems')) { require_once('include/items.php'); $arr_drop = explode(',',$_REQUEST['dropitems']); @@ -328,36 +330,36 @@ class Item extends Controller { echo json_encode($json); killme(); } - + call_hooks('post_local_start', $_REQUEST); - + // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); - + $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); - + $consensus = intval($_REQUEST['consensus']); $nocomment = intval($_REQUEST['nocomment']); $is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false); // 'origin' (if non-zero) indicates that this network is where the message originated, - // for the purpose of relaying comments to other conversation members. + // for the purpose of relaying comments to other conversation members. // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset. // If the API is used from another network with its own distribution - // and deliveries, you may wish to set origin to 0 or false and allow the other + // and deliveries, you may wish to set origin to 0 or false and allow the other // network to relay comments. - - // If you are unsure, it is prudent (and important) to leave it unset. - + + // If you are unsure, it is prudent (and important) to leave it unset. + $origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); - + // To represent message-ids on other networks - this will create an iconfig record - + $namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); - + $owner_hash = null; - + $message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); $created = ((x($_REQUEST,'created')) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['created']) : datetime_convert()); $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); @@ -371,49 +373,49 @@ class Item extends Controller { $layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): ''); $plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); $obj_type = ((x($_REQUEST,'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); - - // allow API to bulk load a bunch of imported items with sending out a bunch of posts. + + // allow API to bulk load a bunch of imported items with sending out a bunch of posts. $nopush = ((x($_REQUEST,'nopush')) ? intval($_REQUEST['nopush']) : 0); - + /* * Check service class limits */ if ($uid && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) { $ret = $this->item_check_service_class($uid,(($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); - if (!$ret['success']) { + if (!$ret['success']) { notice( t($ret['message']) . EOL) ; if($api_source) - return ( [ 'success' => false, 'message' => 'service class exception' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'service class exception' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } } - + if($pagetitle) { require_once('library/urlify/URLify.php'); $pagetitle = strtolower(\URLify::transliterate($pagetitle)); } - - + + $item_flags = $item_restrict = 0; $expires = NULL_DATE; - + $route = ''; $parent_item = null; $parent_contact = null; $thr_parent = ''; $parid = 0; $r = false; - + if($parent || $parent_mid) { - + if(! x($_REQUEST,'type')) $_REQUEST['type'] = 'net-comment'; - + if($obj_type == ACTIVITY_OBJ_NOTE) $obj_type = ACTIVITY_OBJ_COMMENT; - + if($parent) { $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", intval($parent) @@ -436,7 +438,7 @@ class Item extends Controller { ); } - // if interacting with a pubstream item, + // if interacting with a pubstream item, // create a copy of the parent in your stream if($r[0]['uid'] === $sys['channel_id'] && local_channel()) { @@ -447,8 +449,8 @@ class Item extends Controller { if(! $r) { notice( t('Unable to locate original post.') . EOL); if($api_source) - return ( [ 'success' => false, 'message' => 'invalid post id' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'invalid post id' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } @@ -459,15 +461,15 @@ class Item extends Controller { $parent = $r[0]['id']; // multi-level threading - preserve the info but re-parent to our single level threading - + $thr_parent = $parent_mid; - + $route = $parent_item['route']; - + } $moderated = false; - + if(! $observer) { $observer = \App::get_observer(); if(! $observer) { @@ -477,13 +479,13 @@ class Item extends Controller { $remote_xchan = $remote_observer = $observer; } } - } - + } + if(! $observer) { notice( t('Permission denied.') . EOL) ; if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'permission denied' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } @@ -497,12 +499,12 @@ class Item extends Controller { if((array_key_exists('owner',$parent_item)) && intval($parent_item['owner']['abook_self'])==1 ) $can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments'); } - + if(! $can_comment) { notice( t('Permission denied.') . EOL) ; if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'permission denied' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } @@ -511,30 +513,30 @@ class Item extends Controller { if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],($webpage) ? 'write_pages' : 'post_wall')) { notice( t('Permission denied.') . EOL) ; if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'permission denied' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } } - - + + // is this an edited post? - + $orig_post = null; - + if($namespace && $remote_id) { // It wasn't an internally generated post - see if we've got an item matching this remote service id $i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1", dbesc($namespace), - dbesc($remote_id) + dbesc($remote_id) ); if($i) - $post_id = $i[0]['iid']; + $post_id = $i[0]['iid']; } - + $iconfig = null; - + if($post_id) { $i = q("SELECT * FROM item WHERE uid = %d AND id = %d LIMIT 1", intval($profile_uid), @@ -547,8 +549,8 @@ class Item extends Controller { intval($post_id) ); } - - + + if(! $channel) { if($uid && $uid == $profile_uid) { $channel = \App::get_channel(); @@ -562,19 +564,19 @@ class Item extends Controller { $channel = $r[0]; } } - - + + if(! $channel) { logger("mod_item: no channel."); if($api_source) - return ( [ 'success' => false, 'message' => 'no channel' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'no channel' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } - + $owner_xchan = null; - + $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($channel['channel_hash']) ); @@ -584,50 +586,50 @@ class Item extends Controller { else { logger("mod_item: no owner."); if($api_source) - return ( [ 'success' => false, 'message' => 'no owner' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'no owner' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } - + $walltowall = false; $walltowall_comment = false; - + if($remote_xchan && ! $moderated) $observer = $remote_observer; - + if($observer) { logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); - + // wall-to-wall detection. // For top-level posts, if the author and owner are different it's a wall-to-wall // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally. - + if($observer['xchan_name'] != $owner_xchan['xchan_name']) { if(($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { $walltowall_comment = true; $walltowall = true; } if(! $parent) { - $walltowall = true; + $walltowall = true; } } } - + $acl = new \Zotlabs\Access\AccessList($channel); - $view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'); + $view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'); $comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'); - + $public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy,true)); if($webpage) $public_policy = ''; if($public_policy) $private = 1; - + if($orig_post) { $private = 0; - // webpages are allowed to change ACLs after the fact. Normal conversation items aren't. + // webpages are allowed to change ACLs after the fact. Normal conversation items aren't. if($webpage) { $acl->set_from_array($_REQUEST); } @@ -639,8 +641,8 @@ class Item extends Controller { if($public_policy || $acl->is_private()) { $private = (($private) ? $private : 1); - } - + } + $location = $orig_post['location']; $coord = $orig_post['coord']; $verb = $orig_post['verb']; @@ -649,7 +651,7 @@ class Item extends Controller { $summary = trim($_REQUEST['summary']); $body = trim($_REQUEST['body']); $item_flags = $orig_post['item_flags']; - + $item_origin = $orig_post['item_origin']; $item_unseen = $orig_post['item_unseen']; $item_starred = $orig_post['item_starred']; @@ -673,16 +675,16 @@ class Item extends Controller { $item_delayed = $orig_post['item_delayed']; $item_pending_remove = $orig_post['item_pending_remove']; $item_blocked = $orig_post['item_blocked']; - - - + + + $postopts = $orig_post['postopts']; $created = $orig_post['created']; $expires = $orig_post['expires']; $mid = $orig_post['mid']; $parent_mid = $orig_post['parent_mid']; $plink = $orig_post['plink']; - + } else { if(! $walltowall) { @@ -693,18 +695,18 @@ class Item extends Controller { $acl->set_from_array($_REQUEST); } elseif(! $api_source) { - + // if no ACL has been defined and we aren't using the API, the form // didn't send us any parameters. This means there's no ACL or it has // been reset to the default audience. // If $api_source is set and there are no ACL parameters, we default // to the channel permissions which were set in the ACL contructor. - + $acl->set(array('allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); } } - - + + $location = notags(trim($_REQUEST['location'])); $coord = notags(trim($_REQUEST['coord'])); $verb = notags(trim($_REQUEST['verb'])); @@ -714,12 +716,12 @@ class Item extends Controller { $body .= trim($_REQUEST['attachment']); $postopts = ''; - $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); + $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); $private = (($private) ? $private : intval($acl->is_private() || ($public_policy))); - + // If this is a comment, set the permissions from the parent. - + if($parent_item) { $acl->set($parent_item); $private = intval($acl->is_private() || $parent_item['item_private']); @@ -727,21 +729,21 @@ class Item extends Controller { $owner_hash = $parent_item['owner_xchan']; $webpage = $parent_item['item_type']; } - + if((! $allow_empty) && (! strlen($body))) { if($preview) killme(); info( t('Empty post discarded.') . EOL ); if($api_source) - return ( [ 'success' => false, 'message' => 'no content' ] ); - if(x($_REQUEST,'return')) + return ( [ 'success' => false, 'message' => 'no content' ] ); + if(x($_REQUEST,'return')) goaway(z_root() . "/" . $return_path ); killme(); } } - - - + + + if(feature_enabled($profile_uid,'content_expire')) { if(x($_REQUEST,'expire')) { $expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']); @@ -754,16 +756,16 @@ class Item extends Controller { $mimetype = notags(trim($_REQUEST['mimetype'])); if(! $mimetype) $mimetype = 'text/bbcode'; - - $execflag = ((intval($uid) == intval($profile_uid) + + $execflag = ((intval($uid) == intval($profile_uid) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); if($preview) { $summary = z_input_filter($summary,$mimetype,$execflag); $body = z_input_filter($body,$mimetype,$execflag); } - + $arr = [ 'profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype ]; call_hooks('post_content',$arr); @@ -771,7 +773,7 @@ class Item extends Controller { $body = $arr['content']; $mimetype = $arr['mimetype']; - + $gacl = $acl->get(); $str_contact_allow = $gacl['allow_cid']; $str_group_allow = $gacl['allow_gid']; @@ -782,7 +784,7 @@ class Item extends Controller { $groupww = false; // if this is a wall-to-wall post to a group, turn it into a direct message - + $role = get_pconfig($profile_uid,'system','permissions_role'); $rolesettings = PermissionRoles::role_perms($role); @@ -791,19 +793,19 @@ class Item extends Controller { $is_group = (($channel_type === 'group') ? true : false); - if (($is_group) && ($walltowall) && (! $walltowall_comment)) { + if (($is_group) && ($walltowall) && (! $walltowall_comment)) { $groupww = true; $str_contact_allow = $owner_xchan['xchan_hash']; $str_group_allow = ''; } $post_tags = []; - + if($mimetype === 'text/bbcode') { - - require_once('include/text.php'); - - + + require_once('include/text.php'); + + // BBCODE alert: the following functions assume bbcode input // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) // we may need virtual or template classes to implement the possible alternatives @@ -817,31 +819,31 @@ class Item extends Controller { $body_content = preg_replace("/\[summary\](.*?)\[\/summary\]/ism", '',$body); $body = trim($body_content); } - + $summary = cleanup_bbcode($summary); $body = cleanup_bbcode($body); - + // Look for tags and linkify them $results = linkify_tags($summary, ($uid) ? $uid : $profile_uid); $results = linkify_tags($body, ($uid) ? $uid : $profile_uid); if($results) { - + // Set permissions based on tag replacements set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private); - + foreach($results as $result) { $success = $result['success']; if($success['replaced']) { $post_tags[] = array( - 'uid' => $profile_uid, + 'uid' => $profile_uid, 'ttype' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url'] - ); + ); } } @@ -852,10 +854,10 @@ class Item extends Controller { $private = 2; } - + /** * - * When a photo was uploaded into the message using the (profile wall) ajax + * When a photo was uploaded into the message using the (profile wall) ajax * uploader, The permissions are initially set to disallow anybody but the * owner from seeing it. This is because the permissions may not yet have been * set for the post. If it's private, the photo permissions should be set @@ -865,27 +867,27 @@ class Item extends Controller { * * If the post was end-to-end encrypted we can't find images and attachments in the body, * use our media_str input instead which only contains these elements - but only do this - * when encrypted content exists because the photo/attachment may have been removed from + * when encrypted content exists because the photo/attachment may have been removed from * the post and we should keep it private. If it's encrypted we have no way of knowing - * so we'll set the permissions regardless and realise that the media may not be - * referenced in the post. + * so we'll set the permissions regardless and realise that the media may not be + * referenced in the post. * */ - + if(! $preview) { fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - + fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($summary,'[/crypt]')) ? $_POST['media_str'] : $summary),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - + } - - + + $attachments = ''; $match = false; - + if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { $attachments = array(); $i = 0; @@ -908,10 +910,9 @@ class Item extends Controller { } } - if(preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/',$body,$match)) { - // process share by id + // process share by id $i = 0; foreach($match[2] as $mtch) { @@ -920,11 +921,11 @@ class Item extends Controller { $i++; } } - + } - + // BBCODE end alert - + if(strlen($categories)) { $cats = explode(',',$categories); @@ -941,15 +942,15 @@ class Item extends Controller { } $post_tags[] = array( - 'uid' => $profile_uid, + 'uid' => $profile_uid, 'ttype' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), 'url' => $catlink - ); + ); } } - + if($orig_post) { // preserve original tags $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )", @@ -963,26 +964,26 @@ class Item extends Controller { if($t) { foreach($t as $t1) { $post_tags[] = array( - 'uid' => $profile_uid, + 'uid' => $profile_uid, 'ttype' => $t1['ttype'], 'otype' => TERM_OBJ_POST, 'term' => $t1['term'], 'url' => $t1['url'], - ); + ); } } - } - - + } + + $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); - $item_wall = (($post_type === 'wall' || $post_type === 'wall-comment') ? 1 : 0); + $item_wall = (($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment') ? 1 : 0); $item_origin = (($origin) ? 1 : 0); $item_consensus = (($consensus) ? 1 : 0); $item_nocomment = (($nocomment) ? 1 : 0); - - + + // determine if this is a wall post - + if($parent) { $item_wall = $parent_item['item_wall']; } @@ -991,20 +992,20 @@ class Item extends Controller { $item_wall = 1; } } - - + + if($moderated) $item_blocked = ITEM_MODERATED; - - + + if(! strlen($verb)) $verb = ACTIVITY_POST ; - + $notify_type = (($parent) ? 'comment-new' : 'wall-new' ); - + if(! $mid) { $uuid = (($message_id) ? $message_id : item_message_id()); - $mid = z_root() . '/item/' . $uuid; + $mid = z_root() . '/item/' . $uuid; } @@ -1032,23 +1033,23 @@ class Item extends Controller { if(! $parent_mid) { $parent_mid = $mid; } - + if($parent_item) $parent_mid = $parent_item['mid']; // Fallback so that we alway have a thr_parent - + if(!$thr_parent) $thr_parent = $mid; - + $item_thread_top = ((! $parent) ? 1 : 0); - + // fix permalinks for cards - + if($webpage == ITEM_TYPE_CARD) { $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); } @@ -1136,27 +1137,27 @@ class Item extends Controller { $datarray['item_unpublished'] = intval($item_unpublished); $datarray['item_delayed'] = intval($item_delayed); $datarray['item_pending_remove'] = intval($item_pending_remove); - $datarray['item_blocked'] = intval($item_blocked); + $datarray['item_blocked'] = intval($item_blocked); $datarray['layout_mid'] = $layout_mid; $datarray['public_policy'] = $public_policy; - $datarray['comment_policy'] = map_scope($comment_policy); + $datarray['comment_policy'] = map_scope($comment_policy); $datarray['term'] = array_unique($post_tags, SORT_REGULAR); $datarray['plink'] = $plink; $datarray['route'] = $route; // A specific ACL over-rides public_policy completely - + if(! empty_acl($datarray)) $datarray['public_policy'] = ''; if($iconfig) $datarray['iconfig'] = $iconfig; - + // preview mode - prepare the body for display and send it via json - + if($preview) { require_once('include/conversation.php'); - + $datarray['owner'] = $owner_xchan; $datarray['author'] = $observer; $datarray['attach'] = json_encode($datarray['attach']); @@ -1167,45 +1168,45 @@ class Item extends Controller { } if($orig_post) $datarray['edit'] = true; - + // suppress duplicates, *unless* you're editing an existing post. This could get picked up // as a duplicate if you're editing it very soon after posting it initially and you edited - // some attribute besides the content, such as title or categories. + // some attribute besides the content, such as title or categories. if(feature_enabled($profile_uid,'suppress_duplicates') && (! $orig_post)) { - + $z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1", intval($profile_uid), db_utcnow(), db_quoteinterval('2 MINUTE'), dbesc($body) ); - + if($z) { $datarray['cancel'] = 1; notice( t('Duplicate post suppressed.') . EOL); logger('Duplicate post. Faking plugin cancel.'); } } - + call_hooks('post_local',$datarray); - + if(x($datarray,'cancel')) { logger('mod_item: post cancelled by plugin or duplicate suppressed.'); if($return_path) goaway(z_root() . "/" . $return_path); if($api_source) - return ( [ 'success' => false, 'message' => 'operation cancelled' ] ); + return ( [ 'success' => false, 'message' => 'operation cancelled' ] ); $json = array('cancel' => 1); $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; echo json_encode($json); killme(); } - - + + if(mb_strlen($datarray['title']) > 191) $datarray['title'] = mb_substr($datarray['title'],0,191); - + if($webpage) { IConfig::Set($datarray,'system', webpage_to_namespace($webpage), (($pagetitle) ? $pagetitle : basename($datarray['mid'])), true); @@ -1218,20 +1219,20 @@ class Item extends Controller { if($orig_post) { $datarray['id'] = $post_id; - + $x = item_store_update($datarray,$execflag); - + // We only need edit activities for other federated protocols - // which do not support edits natively. While this does federate + // which do not support edits natively. While this does federate // edits, it presents a number of issues locally - such as #757 and #758. // The SQL check for an edit activity would not perform that well so to fix these issues - // requires an additional item flag (perhaps 'item_edit_activity') that we can add to the + // requires an additional item flag (perhaps 'item_edit_activity') that we can add to the // query for searches and notifications. - // For now we'll just forget about trying to make edits work on network protocols that - // don't support them. + // For now we'll just forget about trying to make edits work on network protocols that + // don't support them. - // item_create_edit_activity($x); + // item_create_edit_activity($x); if(! $parent) { $r = q("select * from item where id = %d", @@ -1245,7 +1246,7 @@ class Item extends Controller { } if(! $nopush) Master::Summon([ 'Notifier', 'edit_post', $post_id ]); - + if($api_source) return($x); @@ -1258,18 +1259,18 @@ class Item extends Controller { } else $post_id = 0; - + $post = item_store($datarray,$execflag); - + $post_id = $post['item_id']; $datarray = $post['item']; if($post_id) { logger('mod_item: saved item ' . $post_id); - + if($parent) { - + // prevent conversations which you are involved from being expired if(local_channel()) @@ -1277,7 +1278,7 @@ class Item extends Controller { // only send comment notification if this is a wall-to-wall comment, // otherwise it will happen during delivery - + if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) { Enotify::submit(array( 'type' => NOTIFY_COMMENT, @@ -1290,12 +1291,12 @@ class Item extends Controller { 'parent' => $parent, 'parent_mid' => $parent_item['mid'] )); - + } } else { $parent = $post_id; - + if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) { Enotify::submit(array( 'type' => NOTIFY_WALL, @@ -1307,7 +1308,7 @@ class Item extends Controller { 'otype' => 'item' )); } - + if($uid && $uid == $profile_uid && (is_item_normal($datarray))) { q("update channel set channel_lastpost = '%s' where channel_id = %d", dbesc(datetime_convert()), @@ -1315,11 +1316,11 @@ class Item extends Controller { ); } } - + // photo comments turn the corresponding item visible to the profile wall // This way we don't see every picture in your new photo album posted to your wall at once. // They will show up as people comment on them. - + if(intval($parent_item['item_hidden'])) { $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", intval($parent_item['id']) @@ -1335,8 +1336,8 @@ class Item extends Controller { return ( [ 'success' => false, 'message' => 'system error' ] ); killme(); } - - if(($parent == $post_id) || ($datarray['item_private'] == 1)) { + + if($parent || $datarray['item_private'] == 1) { $r = q("select * from item where id = %d", intval($post_id) ); @@ -1346,10 +1347,10 @@ class Item extends Controller { Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true)))); } } - + $datarray['id'] = $post_id; $datarray['llink'] = z_root() . '/display/' . gen_link_id($datarray['mid']); - + call_hooks('post_local_end', $datarray); if ($groupww) { @@ -1358,48 +1359,61 @@ class Item extends Controller { if(! $nopush) Master::Summon([ 'Notifier', $notify_type, $post_id ]); - + logger('post_complete'); if($moderated) { info(t('Your comment is awaiting approval.') . EOL); } - + // figure out how to return, depending on from whence we came - + if($api_source) return $post; - + if($return_path) { goaway(z_root() . "/" . $return_path); } - - $json = array('success' => 1); + + if($mode === 'channel') + profile_load($channel['channel_address']); + + $item[] = $datarray; + $item[0]['owner'] = $owner_xchan; + $item[0]['author'] = $observer; + $item[0]['attach'] = $datarray['attach']; + + $json = [ + 'success' => 1, + 'id' => $post_id, + 'html' => conversation($item,$mode,true,'r_preview'), + ]; + if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload'])) $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; - + logger('post_json: ' . print_r($json,true), LOGGER_DEBUG); - + echo json_encode($json); killme(); // NOTREACHED } - - + + function get() { - + if((! local_channel()) && (! remote_channel())) return; - + if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { - + require_once('include/items.php'); $i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1", intval(argv(2)) ); - + if($i) { $can_delete = false; $local_delete = false; @@ -1407,14 +1421,14 @@ class Item extends Controller { if(local_channel() && local_channel() == $i[0]['uid']) { $local_delete = true; } - + $ob_hash = get_observer_hash(); if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { $can_delete = true; } // The site admin can delete any post/item on the site. - // If the item originated on this site+channel the deletion will propagate downstream. + // If the item originated on this site+channel the deletion will propagate downstream. // Otherwise just the local copy is removed. if(is_site_admin()) { @@ -1428,11 +1442,11 @@ class Item extends Controller { notice( t('Permission denied.') . EOL); return; } - + // if this is a different page type or it's just a local delete // but not by the item author or owner, do a simple deletion - $complex = false; + $complex = false; if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { drop_item($i[0]['id']); @@ -1458,15 +1472,15 @@ class Item extends Controller { } } } - - - + + + function item_check_service_class($channel_id,$iswebpage) { $ret = array('success' => false, 'message' => ''); - + if ($iswebpage) { - $r = q("select count(i.id) as total from item i - right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) + $r = q("select count(i.id) as total from item i + right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) and i.parent=i.id and i.item_type = %d and i.item_deleted = 0 and i.uid= %d ", intval(ITEM_TYPE_WEBPAGE), intval($channel_id) @@ -1477,11 +1491,11 @@ class Item extends Controller { intval($channel_id) ); } - + if(! $r) { $ret['message'] = t('Unable to obtain post information from database.'); return $ret; - } + } if (!$iswebpage) { $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_items')); @@ -1495,13 +1509,13 @@ class Item extends Controller { if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) { $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f webpages.'),$max); return $result; - } + } } - + $ret['success'] = true; return $ret; } - + function extract_bb_poll_data(&$body,$item) { $multiple = false; @@ -1535,7 +1549,7 @@ class Item extends Controller { } $matches = null; - + if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) { $obj['content'] = bbcode($matches[1]); $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); @@ -1543,7 +1557,7 @@ class Item extends Controller { } $matches = null; - + if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) { $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index 8ffa7f66c..358611b1b 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -7,13 +7,10 @@ use Zotlabs\Lib\Libsync; require_once('include/security.php'); require_once('include/bbcode.php'); require_once('include/items.php'); - - +require_once('include/conversation.php'); class Like extends \Zotlabs\Web\Controller { - - private function reaction_to_activity($reaction) { $acts = [ @@ -24,7 +21,7 @@ class Like extends \Zotlabs\Web\Controller { 'abstain' => ACTIVITY_ABSTAIN , 'attendyes' => ACTIVITY_ATTEND , 'attendno' => ACTIVITY_ATTENDNO , - 'attendmaybe' => ACTIVITY_ATTENDMAYBE + 'attendmaybe' => ACTIVITY_ATTENDMAYBE ]; // unlike (etc.) reactions are an undo of positive reactions, rather than a negative action. @@ -42,10 +39,49 @@ class Like extends \Zotlabs\Web\Controller { } + private function like_response($arr) { + + if($arr['conv_mode'] === 'channel') { + $parts = explode('@', $arr['owner_xchan']['xchan_addr']); + profile_load($parts[0]); + } + + + $item_normal = item_normal(); + + $activities = q("SELECT item.*, item.id AS item_id FROM item + WHERE uid = %d $item_normal + AND thr_parent = '%s' + AND verb IN ('%s', '%s', '%s', '%s', '%s')", + intval($arr['item']['uid']), + dbesc($arr['item']['mid']), + dbesc(ACTIVITY_LIKE), + dbesc(ACTIVITY_DISLIKE), + dbesc(ACTIVITY_ATTEND), + dbesc(ACTIVITY_ATTENDNO), + dbesc(ACTIVITY_ATTENDMAYBE) + ); + + xchan_query($activities,true); + + $convitems[] = $arr['item']; + $convitems = array_merge($convitems, $activities); + + $convitems = fetch_post_tags($convitems,true); + + $ret = [ + 'success' => 1, + 'orig_id' => $arr['orig_item_id'], //this is required for pubstream items where $item_id != $item['id'] + 'id' => $arr['item']['id'], + 'html' => conversation($convitems, $arr['conv_mode'], true, 'r_preview'), + ]; + + return $ret; + } public function get() { - + $o = EMPTY_STR; $sys_channel = get_sys_channel(); @@ -56,7 +92,7 @@ class Like extends \Zotlabs\Web\Controller { if((! $observer) || ($interactive)) { $o .= '<h1>' . t('Like/Dislike') . '</h1>'; $o .= EOL . EOL; - + if(! $observer) { $_SESSION['return_url'] = \App::$query_string; $o .= t('This action is restricted to members.') . EOL; @@ -64,16 +100,17 @@ class Like extends \Zotlabs\Web\Controller { return $o; } } - + $verb = notags(trim($_GET['verb'])); - + $mode = (($_GET['conv_mode'] === 'channel') ? 'channel' : 'network'); + if(! $verb) $verb = 'like'; - + $activity = $this->reaction_to_activity($verb); if(! $activity) { - return EMPTY_STR; + return EMPTY_STR; } $is_rsvp = false; @@ -86,23 +123,23 @@ class Like extends \Zotlabs\Web\Controller { $object = $target = null; $post_type = EMPTY_STR; $objtype = EMPTY_STR; - + if(argc() == 3) { - + if(! $observer) killme(); - + $extended_like = true; $obj_type = argv(1); $obj_id = argv(2); $public = true; - + if($obj_type == 'profile') { $r = q("select * from profile where profile_guid = '%s' limit 1", dbesc(argv(2)) ); if(! $r) - killme(); + killme(); $owner_uid = $r[0]['uid']; if($r[0]['is_default']) $public = true; @@ -128,54 +165,54 @@ class Like extends \Zotlabs\Web\Controller { } $post_type = t('channel'); $objtype = ACTIVITY_OBJ_PROFILE; - + $profile = $r[0]; } elseif($obj_type == 'thing') { - + $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", intval(TERM_OBJ_THING), dbesc(argv(2)) ); - + if(! $r) { if($interactive) { notice( t('Invalid request.') . EOL); return $o; } - killme(); + killme(); } - + $owner_uid = $r[0]['obj_channel']; - + $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $deny_cid = $r[0]['deny_cid']; $deny_gid = $r[0]['deny_gid']; - if($allow_cid || $allow_gid || $deny_cid || $deny_gid) + if($allow_cid || $allow_gid || $deny_cid || $deny_gid) $public = false; - + $post_type = t('thing'); $objtype = ACTIVITY_OBJ_PROFILE; $tgttype = ACTIVITY_OBJ_THING; - + $links = array(); $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/thing/' . $r[0]['obj_obj']); - if($r[0]['imgurl']) + if($r[0]['imgurl']) $links[] = array('rel' => 'photo', 'href' => $r[0]['obj_imgurl']); - + $target = json_encode(array( 'type' => $tgttype, 'title' => $r[0]['obj_term'], 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], 'link' => $links )); - + $plink = '[zrl=' . z_root() . '/thing/' . $r[0]['obj_obj'] . ']' . $r[0]['obj_term'] . '[/zrl]'; - + } - + if(! ($owner_uid && $r)) { if($interactive) { notice( t('Invalid request.') . EOL); @@ -183,11 +220,11 @@ class Like extends \Zotlabs\Web\Controller { } killme(); } - + // The resultant activity is going to be a wall-to-wall post, so make sure this is allowed - + $perms = get_all_perms($owner_uid,$observer['xchan_hash']); - + if(! ($perms['post_like'] && $perms['view_profile'])) { if($interactive) { notice( t('Permission denied.') . EOL); @@ -195,7 +232,7 @@ class Like extends \Zotlabs\Web\Controller { } killme(); } - + $ch = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($owner_uid) ); @@ -206,14 +243,14 @@ class Like extends \Zotlabs\Web\Controller { } killme(); } - + if(! $plink) $plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]'; - + $object = json_encode(Activity::fetch_profile([ 'id' => channel_url($ch[0]) ])); // second like of the same thing is "undo" for the first like - + $z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1", intval($ch[0]['channel_id']), dbesc($observer['xchan_hash']), @@ -221,11 +258,11 @@ class Like extends \Zotlabs\Web\Controller { dbesc(($tgttype)?$tgttype:$objtype), dbesc($obj_id) ); - + if($z) { $z[0]['deleted'] = 1; Libsync::build_sync_packet($ch[0]['channel_id'],array('likes' => $z)); - + q("delete from likes where id = %d", intval($z[0]['id']) ); @@ -248,17 +285,17 @@ class Like extends \Zotlabs\Web\Controller { if(! $observer) killme(); - + // this is used to like an item or comment - + $item_id = ((argc() == 2) ? notags(trim(argv(1))) : 0); - + logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG); - + // get the item. Allow linked photos (which are normally hidden) to be liked - $r = q("SELECT * FROM item WHERE id = %d - and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0 + $r = q("SELECT * FROM item WHERE id = %d + and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0 and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1", intval($item_id) ); @@ -304,7 +341,7 @@ class Like extends \Zotlabs\Web\Controller { $thread_owner = $r[0]; else killme(); - + $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['author_xchan']) ); @@ -312,15 +349,14 @@ class Like extends \Zotlabs\Web\Controller { $item_author = $r[0]; else killme(); - - + $verbs = " '".dbesc($activity)."' "; - - $multi_undo = false; - + + $multi_undo = false; + // event participation and consensus items are essentially radio toggles. If you make a subsequent choice, - // we need to eradicate your first choice. - + // we need to eradicate your first choice. + if($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) { $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' "; $multi_undo = 1; @@ -329,16 +365,16 @@ class Like extends \Zotlabs\Web\Controller { $verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' "; $multi_undo = true; } - + $item_normal = item_normal(); - + $r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( $verbs ) $item_normal AND author_xchan = '%s' AND thr_parent = '%s' and uid = %d ", dbesc($observer['xchan_hash']), dbesc($item['mid']), intval($owner_uid) ); - + if($r) { // already liked it. Drop that item. require_once('include/items.php'); @@ -350,30 +386,41 @@ class Like extends \Zotlabs\Web\Controller { intval($rr['parent']), intval($rr['uid']) ); - // Prior activity was a duplicate of the one we're submitting, just undo it; + // Prior activity was a duplicate of the one we're submitting, just undo it; // don't fall through and create another if(activity_match($rr['verb'],$activity)) $multi_undo = false; - + // drop_item was not done interactively, so we need to invoke the notifier // in order to push the changes to connections - + \Zotlabs\Daemon\Master::Summon(array('Notifier','drop',$rr['id'])); - + + + } - + if($interactive) return; - - if(! $multi_undo) - killme(); + + if(! $multi_undo) { + $ret = self::like_response([ + 'item' => $item, + 'orig_item_id' => $item_id, + 'owner_xchan' => $thread_owner, + 'conv_mode' => $mode + ]); + json_return_and_die($ret); + } + + } } - + $uuid = item_message_id(); - + $arr = array(); - + $arr['uuid'] = $uuid; $arr['mid'] = z_root() . (($is_rsvp) ? '/activity/' : '/item/') . $uuid; @@ -386,38 +433,38 @@ class Like extends \Zotlabs\Web\Controller { $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); if($item['obj_type'] === ACTIVITY_OBJ_EVENT) $post_type = t('event'); - + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); - $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); if($objtype === ACTIVITY_OBJ_NOTE && (! intval($item['item_thread_top']))) $objtype = ACTIVITY_OBJ_COMMENT; - + $body = $item['body']; - + $object = json_encode(Activity::fetch_item( [ 'id' => $item['mid'] ])); if(! intval($item['item_thread_top'])) - $post_type = 'comment'; - + $post_type = 'comment'; + $arr['item_origin'] = 1; $arr['item_notshown'] = 1; $arr['item_type'] = $item['item_type']; - + if(intval($item['item_wall'])) $arr['item_wall'] = 1; - + // if this was a linked photo and was hidden, unhide it. - + if(intval($item['item_hidden'])) { $r = q("update item set item_hidden = 0 where id = %d", intval($item['id']) ); - } - + } + } - + if($verb === 'like') $bodyverb = t('%1$s likes %2$s\'s %3$s'); if($verb === 'dislike') @@ -434,12 +481,12 @@ class Like extends \Zotlabs\Web\Controller { $bodyverb = t('%1$s is not attending %2$s\'s %3$s'); if($verb === 'attendmaybe') $bodyverb = t('%1$s may attend %2$s\'s %3$s'); - + if(! isset($bodyverb)) - killme(); - - - + killme(); + + + if($extended_like) { $ulink = '[zrl=' . $ch[0]['xchan_url'] . '][bdi]' . $ch[0]['xchan_name'] . '[/bdi][/zrl]'; $alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]'; @@ -456,65 +503,64 @@ class Like extends \Zotlabs\Web\Controller { $deny_cid = $item['deny_cid']; $deny_gid = $item['deny_gid']; $private = $item['private']; - + } - - + + $arr['aid'] = (($extended_like) ? $ch[0]['channel_account_id'] : $owner_aid); $arr['uid'] = $owner_uid; - $arr['item_flags'] = $item_flags; - $arr['item_wall'] = $item_wall; + $arr['item_flags'] = $item['item_flags']; + $arr['item_wall'] = $item['item_wall']; $arr['parent_mid'] = (($extended_like) ? $arr['mid'] : $item['mid']); $arr['owner_xchan'] = (($extended_like) ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash']); $arr['author_xchan'] = $observer['xchan_hash']; - - + + $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); if($obj_type === 'thing' && $r[0]['imgurl']) { $arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]'; - } + } if($obj_type === 'profile') { if($public) { - $arr['body'] .= "\n\n" . '[embed]' . z_root() . '/profile/' . $ch[0]['channel_address'] . '[/embed]'; + $arr['body'] .= "\n\n" . '[embed]' . z_root() . '/profile/' . $ch[0]['channel_address'] . '[/embed]'; } else $arr['body'] .= "\n\n[zmg=80x80]" . $profile['thumb'] . '[/zmg]'; - } - - + } + + $arr['verb'] = $activity; $arr['obj_type'] = $objtype; $arr['obj'] = $object; - + if($target) { $arr['tgt_type'] = $tgttype; $arr['target'] = $target; } - + $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; $arr['deny_cid'] = $deny_cid; $arr['deny_gid'] = $deny_gid; $arr['item_private'] = $private; - + call_hooks('post_local',$arr); - - $post = item_store($arr); + $post = item_store($arr); $post_id = $post['item_id']; // save the conversation from expiration if(local_channel() && array_key_exists('item',$post) && (intval($post['item']['id']) != intval($post['item']['parent']))) - retain_item($post['item']['parent']); - + retain_item($post['item']['parent']); + $arr['id'] = $post_id; - + call_hooks('post_local_end', $arr); - - + + if($extended_like) { $r = q("insert into likes (channel_id,liker,likee,iid,i_mid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s','%s')", intval($ch[0]['channel_id']), @@ -536,22 +582,26 @@ class Like extends \Zotlabs\Web\Controller { dbesc($obj_id) ); if($r) - Libsync::build_sync_packet($ch[0]['channel_id'],array('likes' => $r)); - + Libsync::build_sync_packet($ch[0]['channel_id'],array('likes' => $r)); + } - - + \Zotlabs\Daemon\Master::Summon(array('Notifier','like',$post_id)); - + if($interactive) { notice( t('Action completed.') . EOL); $o .= t('Thank you.'); return $o; } - - killme(); + + $ret = self::like_response([ + 'item' => $item, + 'orig_item_id' => $item_id, + 'owner_xchan' => $thread_owner, + 'conv_mode' => $mode + ]); + json_return_and_die($ret); + } - - - + } diff --git a/Zotlabs/Module/Lockview.php b/Zotlabs/Module/Lockview.php index 8c8519c57..11c781df0 100644 --- a/Zotlabs/Module/Lockview.php +++ b/Zotlabs/Module/Lockview.php @@ -19,22 +19,22 @@ class Lockview extends \Zotlabs\Web\Controller { } } } - + $type = ((argc() > 1) ? argv(1) : 0); if (is_numeric($type)) { $item_id = intval($type); $type='item'; - } + } else { $item_id = ((argc() > 2) ? intval(argv(2)) : 0); } - + if(! $item_id) killme(); - + if (! in_array($type, array('item', 'photo', 'attach', 'event', 'menu_item', 'chatroom'))) killme(); - + // we have different naming in in menu_item table and chatroom table switch($type) { case 'menu_item': @@ -47,17 +47,17 @@ class Lockview extends \Zotlabs\Web\Controller { $id = 'id'; break; } - + $r = q("SELECT * FROM %s WHERE $id = %d LIMIT 1", dbesc($type), intval($item_id) ); - + if(! $r) killme(); - + $item = $r[0]; - + //we have different naming in in menu_item table and chatroom table switch($type) { case 'menu_item': @@ -70,37 +70,37 @@ class Lockview extends \Zotlabs\Web\Controller { $uid = $item['uid']; break; } - + if($uid != local_channel()) { echo '<div class="dropdown-item">' . t('Remote privacy information not available.') . '</div>'; killme(); } - - if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) + + if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { - + // if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any // specific recipients, we're the recipient of a post with "bcc" or targeted recipients; so we'll just show it // as unknown specific recipients. The sender will have the visibility list and will fall through to the // next section. - + echo '<div class="dropdown-item">' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>'; killme(); } - + $allowed_users = expand_acl($item['allow_cid']); $allowed_groups = expand_acl($item['allow_gid']); $deny_users = expand_acl($item['deny_cid']); $deny_groups = expand_acl($item['deny_gid']); - + $o = '<div class="dropdown-item">' . t('Visible to:') . '</div>'; $l = array(); - + stringify_array_elms($allowed_groups,true); stringify_array_elms($allowed_users,true); stringify_array_elms($deny_groups,true); stringify_array_elms($deny_users,true); - + $profile_groups = []; if($allowed_groups) { @@ -113,24 +113,24 @@ class Lockview extends \Zotlabs\Web\Controller { if(count($profile_groups)) { $r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item"><b>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</b></div>'; } if(count($allowed_groups)) { $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item"><b>' . $rr['gname'] . '</b></div>'; } if(count($allowed_users)) { $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item">' . $rr['xchan_name'] . '</div>'; if($atokens) { foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) { + if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) { $l[] = '<div class="dropdown-item">' . $at['xchan_name'] . '</div>'; } } @@ -149,7 +149,7 @@ class Lockview extends \Zotlabs\Web\Controller { if(count($profile_groups)) { $r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item"><b><strike>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</strike></b></div>'; } @@ -158,18 +158,18 @@ class Lockview extends \Zotlabs\Web\Controller { if(count($deny_groups)) { $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item"><b><strike>' . $rr['gname'] . '</strike></b></div>'; } if(count($deny_users)) { $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); if($r) - foreach($r as $rr) + foreach($r as $rr) $l[] = '<div class="dropdown-item"><strike>' . $rr['xchan_name'] . '</strike></div>'; if($atokens) { foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) { + if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) { $l[] = '<div class="dropdown-item"><strike>' . $at['xchan_name'] . '</strike></div>'; } } @@ -177,11 +177,11 @@ class Lockview extends \Zotlabs\Web\Controller { } - + echo $o . implode($l); killme(); - - + + } - + } diff --git a/Zotlabs/Module/Locs.php b/Zotlabs/Module/Locs.php index 4c935a6a2..2dd359c95 100644 --- a/Zotlabs/Module/Locs.php +++ b/Zotlabs/Module/Locs.php @@ -8,55 +8,65 @@ use Zotlabs\Daemon\Master; class Locs extends Controller { function post() { - + if(! local_channel()) return; - + $channel = App::get_channel(); - + if($_REQUEST['primary']) { $hubloc_id = intval($_REQUEST['primary']); if($hubloc_id) { - + $r = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", intval($hubloc_id), dbesc($channel['channel_hash']) ); - + if(! $r) { notice( t('Location not found.') . EOL); return; } - + q("UPDATE hubloc SET hubloc_primary = 0 WHERE hubloc_primary = 1 AND (hubloc_hash = '%s' OR hubloc_hash = '%s')", dbesc($channel['channel_hash']), dbesc($channel['channel_portable_id']) ); + q("UPDATE hubloc SET hubloc_primary = 1 WHERE hubloc_id = %d AND hubloc_hash = '%s'", intval($hubloc_id), dbesc($channel['channel_hash']) ); + $x = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' ", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + + if ($x) { + hubloc_change_primary($x[0]); + } + Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); return; - } + } } - - + if($_REQUEST['drop']) { $hubloc_id = intval($_REQUEST['drop']); - + if($hubloc_id) { $r = q("select * from hubloc where hubloc_id = %d and hubloc_url != '%s' and hubloc_hash = '%s' limit 1", intval($hubloc_id), dbesc(z_root()), dbesc($channel['channel_hash']) ); - + if(! $r) { notice( t('Location not found.') . EOL); return; } + if(intval($r[0]['hubloc_primary'])) { $x = q("select hubloc_id from hubloc where hubloc_primary = 1 and hubloc_hash = '%s'", dbesc($channel['channel_hash']) @@ -70,7 +80,7 @@ class Locs extends Controller { return; } } - + q("UPDATE hubloc SET hubloc_deleted = 1 WHERE hubloc_id_url = '%s' AND (hubloc_hash = '%s' OR hubloc_hash = '%s')", dbesc($r[0]['hubloc_id_url']), dbesc($channel['channel_hash']), @@ -78,44 +88,41 @@ class Locs extends Controller { ); Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); return; - } + } } } - - - + + + function get() { - - + if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } - + $channel = App::get_channel(); - + if($_REQUEST['sync']) { Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); info( t('Syncing locations') . EOL); goaway(z_root() . '/locs'); } - - + $r = q("select * from hubloc where hubloc_hash = '%s'", dbesc($channel['channel_hash']) ); - + if(! $r) { notice( t('No locations found.') . EOL); return; } - - + for($x = 0; $x < count($r); $x ++) { $r[$x]['primary'] = (intval($r[$x]['hubloc_primary']) ? true : false); $r[$x]['deleted'] = (intval($r[$x]['hubloc_deleted']) ? true : false); } - + $o = replace_macros(get_markup_template('locmanage.tpl'), array( '$header' => t('Manage Channel Locations'), '$loc' => t('Location'), @@ -129,8 +136,8 @@ class Locs extends Controller { '$last_resort' => t('Use this form to drop the location if the hub is no longer operating.'), '$hubs' => $r )); - + return $o; } - + } diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index bbacbb21e..4a1692d64 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -44,10 +44,6 @@ class Network extends \Zotlabs\Web\Controller { $o = ''; - if($load) { - $_SESSION['loadtime'] = datetime_convert(); - } - $arr = array('query' => App::$query_string); call_hooks('network_content_init', $arr); @@ -64,7 +60,6 @@ class Network extends \Zotlabs\Web\Controller { $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); - $static = ((x($_GET,'static')) ? intval($_GET['static']) : 0); $gid = ((x($_GET,'gid')) ? intval($_GET['gid']) : 0); $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); @@ -213,8 +208,6 @@ class Network extends \Zotlabs\Web\Controller { $status_editor = status_editor($a,$x,false,'Network'); $o .= $status_editor; - $static = channel_manual_conv_update(local_channel()); - } @@ -370,7 +363,6 @@ class Network extends \Zotlabs\Web\Controller { '$dm' => (($dm) ? $dm : '0'), '$nouveau' => (($nouveau) ? $nouveau : '0'), '$wall' => '0', - '$static' => $static, '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), '$search' => (($search) ? urlencode($search) : ''), @@ -494,8 +486,6 @@ class Network extends \Zotlabs\Web\Controller { $parents_str = ''; - $simple_update = (($update) ? " and item_unseen = 1 " : ''); - // This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day // or three and look at your matrix page - after opening up your browser. The first page loads just as it // should. All of a sudden a few seconds later, page 2 will get inserted at the beginning of the page @@ -507,16 +497,11 @@ class Network extends \Zotlabs\Web\Controller { // which "arrived as you were reading page 1". We're going to do this // by storing in your session the current UTC time whenever you LOAD a network page, and only UPDATE items // which are both ITEM_UNSEEN and have "changed" since that time. Cross fingers... - + + $simple_update = ''; if($update && $_SESSION['loadtime']) $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; - if($load) - $simple_update = ''; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - if($nouveau && $load) { // "New Item View" - show all items unthreaded in reverse created date order $items = q("SELECT item.*, item.id AS item_id, created FROM item @@ -524,7 +509,6 @@ class Network extends \Zotlabs\Web\Controller { $net_query WHERE true $uids $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) - $simple_update $sql_extra $sql_options $sql_nets $net_query2 ORDER BY item.created DESC $pager_sql " @@ -570,7 +554,6 @@ class Network extends \Zotlabs\Web\Controller { and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_options $sql_nets $net_query2" ); - $_SESSION['loadtime'] = datetime_convert(); } // Then fetch all the children of the parents that are on this page @@ -605,6 +588,8 @@ class Network extends \Zotlabs\Web\Controller { if(($items) && (! $update)) $o .= alt_pager(count($items)); + + $_SESSION['loadtime'] = datetime_convert(); return $o; } diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/OAuth2TestVehicle.php index 5ae278e8c..5ae278e8c 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/OAuth2TestVehicle.php diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php index 561e35754..9a3513f34 100644 --- a/Zotlabs/Module/Owa.php +++ b/Zotlabs/Module/Owa.php @@ -11,9 +11,9 @@ use Zotlabs\Web\Controller; * See spec/OpenWebAuth/Home.md * Requests to this endpoint should be signed using HTTP Signatures * using the 'Authorization: Signature' authentication method - * If the signature verifies a token is returned. + * If the signature verifies a token is returned. * - * This token may be exchanged for an authenticated cookie. + * This token may be exchanged for an authenticated cookie. */ class Owa extends Controller { @@ -31,36 +31,34 @@ class Owa extends Controller { if ($sigblock) { $keyId = $sigblock['keyId']; if ($keyId) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ", - dbesc(str_replace('acct:','',$keyId)), + $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash + WHERE hubloc_id_url = '%s'", dbesc($keyId) ); if (! $r) { $found = discover_by_webbie(str_replace('acct:','',$keyId)); if ($found) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ", - dbesc(str_replace('acct:','',$keyId)), + $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash + WHERE hubloc_id_url = '%s'", dbesc($keyId) ); } } if ($r) { foreach ($r as $hubloc) { - $verified = HTTPSig::verify(file_get_contents('php://input')); + $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']); if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) { logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); - logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); + logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA); $ret['success'] = true; $token = random_string(32); - Verify::create('owt',0,$token,$hubloc['hubloc_addr']); + Verify::create('owt',0,$token,$hubloc['hubloc_id_url']); $result = ''; openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); $ret['encrypted_token'] = base64url_encode($result); break; } else { - logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); + logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']); } } } diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index c88696578..814705a85 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -35,7 +35,7 @@ class Photo extends \Zotlabs\Web\Controller { call_hooks('cache_mode_hook', $cache_mode); $observer_xchan = get_observer_hash(); - $cachecontrol = ''; + $cachecontrol = ', no-cache'; if(isset($type)) { @@ -81,18 +81,18 @@ class Photo extends \Zotlabs\Web\Controller { else $data = dbunescbin($r[0]['content']); } - } - if(! $data) { - $d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ]; - call_hooks('get_profile_photo',$d); - - $resolution = $d['imgscale']; - $uid = $d['channel_id']; - $default = $d['default']; - $data = $d['data']; - $mimetype = $d['mimetype']; - $modified = 0; + if(! $data) { + $d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ]; + call_hooks('get_profile_photo',$d); + + $resolution = $d['imgscale']; + $uid = $d['channel_id']; + $default = $d['default']; + $data = $d['data']; + $mimetype = $d['mimetype']; + $modified = 0; + } } if(! $data) { @@ -102,7 +102,7 @@ class Photo extends \Zotlabs\Web\Controller { $modified = filemtime($default); } - $cachecontrol = ', must-revalidate'; + $cachecontrol .= ', must-revalidate'; } else { @@ -169,6 +169,7 @@ class Photo extends \Zotlabs\Web\Controller { $url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url); goaway($url); } + $cachecontrol = ''; } } } @@ -271,7 +272,7 @@ class Photo extends \Zotlabs\Web\Controller { // in the event that infrastructure caching is present. $smaxage = intval($maxage/12); - header("Cache-Control: no-cache, s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol); + header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol); } diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index fa9216c97..099289c03 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -16,66 +16,66 @@ require_once('include/text.php'); class Photos extends \Zotlabs\Web\Controller { function init() { - + if(observer_prohibited()) { return; } - + if(argc() > 1) { $nick = argv(1); - + profile_load($nick); - + $channelx = channelx_by_nick($nick); - + if(! $channelx) return; - + \App::$data['channel'] = $channelx; - + $observer = \App::get_observer(); \App::$data['observer'] = $observer; - + $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); - + head_set_icon(\App::$data['channel']['xchan_photo_s']); - + \App::$page['htmlhead'] .= "<script> var profile_uid = " . ((\App::$data['channel']) ? \App::$data['channel']['channel_id'] : 0) . "; </script>" ; - + } - + return; } - - - + + + function post() { - + logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); - + logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA); logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA); - + $ph = photo_factory(''); - + $phototypes = $ph->supportedTypes(); - + $can_post = false; - + $page_owner_uid = \App::$data['channel']['channel_id']; - + if(perm_is_allowed($page_owner_uid,get_observer_hash(),'write_storage')) $can_post = true; - + if(! $can_post) { notice( t('Permission denied.') . EOL ); if(is_ajax()) killme(); return; } - + $s = abook_self($page_owner_uid); - + if(! $s) { notice( t('Page owner information could not be retrieved.') . EOL); logger('mod_photos: post: unable to locate contact record for page owner. uid=' . $page_owner_uid); @@ -83,30 +83,30 @@ class Photos extends \Zotlabs\Web\Controller { killme(); return; } - - $owner_record = $s[0]; - + + $owner_record = $s[0]; + $acl = new \Zotlabs\Access\AccessList(\App::$data['channel']); - + if((argc() > 3) && (argv(2) === 'album')) { - + $album = argv(3); if(! photos_album_exists($page_owner_uid, get_observer_hash(), $album)) { notice( t('Album not found.') . EOL); goaway(z_root() . '/' . $_SESSION['photo_return']); } - - + + /* * DELETE photo album and all its photos */ - + if($_REQUEST['dropalbum'] == t('Delete Album')) { - - + + $folder_hash = ''; - + $r = q("select * from attach where is_dir = 1 and uid = %d and hash = '%s'", intval($page_owner_uid), dbesc($album) @@ -116,13 +116,13 @@ class Photos extends \Zotlabs\Web\Controller { return; } $folder_hash = $r[0]['hash']; - - + + $res = array(); $admin_delete = false; // get the list of photos we are about to delete - + if(remote_channel() && (! local_channel())) { $str = photos_album_get_db_idstr($page_owner_uid,$album,remote_channel()); } @@ -139,7 +139,7 @@ class Photos extends \Zotlabs\Web\Controller { if(! $str) { goaway(z_root() . '/' . $_SESSION['photo_return']); } - + $r = q("select id from item where resource_id in ( $str ) and resource_type = 'photo' and uid = %d " . item_normal(), intval($page_owner_uid) ); @@ -148,34 +148,34 @@ class Photos extends \Zotlabs\Web\Controller { attach_delete($page_owner_uid, $i['resource_id'], true ); } } - + // remove the associated photos in case they weren't attached to an item - + q("delete from photo where resource_id in ( $str ) and uid = %d", intval($page_owner_uid) ); - + // @FIXME do the same for the linked attach - + if($folder_hash) { attach_delete($page_owner_uid, $folder_hash, true ); - if(! $admin_delete) { + if(! $admin_delete) { $sync = attach_export_data(\App::$data['channel'],$folder_hash, true); - - if($sync) + + if($sync) Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync))); } } - + } - + goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']); } - + if((argc() > 2) && (x($_REQUEST,'delete')) && ($_REQUEST['delete'] === t('Delete Photo'))) { // same as above but remove single photo - + $ob_hash = get_observer_hash(); if(! $ob_hash) goaway(z_root() . '/' . $_SESSION['photo_return']); @@ -185,18 +185,18 @@ class Photos extends \Zotlabs\Web\Controller { intval(local_channel()), dbesc(argv(2)) ); - + if($r) { attach_delete($page_owner_uid, $r[0]['resource_id'], true ); $sync = attach_export_data(\App::$data['channel'],$r[0]['resource_id'], true); - - if($sync) + + if($sync) Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync))); } elseif(is_site_admin()) { // If the admin deletes a photo, don't sync attach_delete($page_owner_uid, argv(2), true); - } + } goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); @@ -208,10 +208,10 @@ class Photos extends \Zotlabs\Web\Controller { intval($page_owner_uid) ); if(($m) && ($m[0]['folder'] != $_POST['move_to_album'])) { - attach_move($page_owner_uid,argv(2),$_POST['move_to_album']); + attach_move($page_owner_uid,argv(2),$_POST['move_to_album']); $sync = attach_export_data(\App::$data['channel'], argv(2), false); - if($sync) + if($sync) Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync))); if(! ($_POST['desc'] && $_POST['newtag'])) @@ -220,28 +220,28 @@ class Photos extends \Zotlabs\Web\Controller { } if((argc() > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false))) { - + $desc = ((x($_POST,'desc')) ? notags(trim($_POST['desc'])) : ''); $rawtags = ((x($_POST,'newtag')) ? notags(trim($_POST['newtag'])) : ''); $item_id = ((x($_POST,'item_id')) ? intval($_POST['item_id']) : 0); $is_nsfw = ((x($_POST,'adult')) ? intval($_POST['adult']) : 0); - + $acl->set_from_array($_POST); $perm = $acl->get(); - + $resource_id = argv(2); - - if((x($_POST,'rotate') !== false) && + + if((x($_POST,'rotate') !== false) && ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) { logger('rotate'); - + $r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0 limit 1", dbesc($resource_id), intval($page_owner_uid) ); if(count($r)) { - + $ph = photo_factory(@file_get_contents(dbunescbin($r[0]['content'])), $r[0]['mimetype']); if($ph->is_valid()) { $rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 ); @@ -255,12 +255,12 @@ class Photos extends \Zotlabs\Web\Controller { dbesc($resource_id), intval($page_owner_uid) ); - + $ph->saveImage(dbunescbin($r[0]['content'])); - - $arr = [ + + $arr = [ 'aid' => get_account_id(), - 'uid' => intval($page_owner_uid), + 'uid' => intval($page_owner_uid), 'resource_id' => dbesc($resource_id), 'filename' => $r[0]['filename'], 'imgscale' => 0, @@ -277,28 +277,31 @@ class Photos extends \Zotlabs\Web\Controller { unset($arr['os_syspath']); - if($width > 1024 || $height > 1024) + $width = $r[0]['width']; + $height = $r[0]['height']; + + if($width > 1024 || $height > 1024) $ph->scaleImage(1024); $ph->storeThumbnail($arr, PHOTO_RES_1024); - if($width > 640 || $height > 640) + if($width > 640 || $height > 640) $ph->scaleImage(640); $ph->storeThumbnail($arr, PHOTO_RES_640); - if($width > 320 || $height > 320) + if($width > 320 || $height > 320) $ph->scaleImage(320); $ph->storeThumbnail($arr, PHOTO_RES_320); } } } - + $p = q("SELECT mimetype, is_nsfw, description, resource_id, imgscale, allow_cid, allow_gid, deny_cid, deny_gid FROM photo WHERE resource_id = '%s' AND uid = %d ORDER BY imgscale DESC", dbesc($resource_id), intval($page_owner_uid) ); if($p) { $ext = $phototypes[$p[0]['mimetype']]; - + $r = q("UPDATE photo SET description = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' WHERE resource_id = '%s' AND uid = %d", dbesc($desc), dbesc($perm['allow_cid']), @@ -309,9 +312,7 @@ class Photos extends \Zotlabs\Web\Controller { intval($page_owner_uid) ); } - - $item_private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); - + $old_is_nsfw = $p[0]['is_nsfw']; if($old_is_nsfw != $is_nsfw) { $r = q("update photo set is_nsfw = %d where resource_id = '%s' and uid = %d", @@ -320,31 +321,31 @@ class Photos extends \Zotlabs\Web\Controller { intval($page_owner_uid) ); } - + /* Don't make the item visible if the only change was the album name */ - + $visibility = 0; if($p[0]['description'] !== $desc || strlen($rawtags)) $visibility = 1; - + if(! $item_id) { $item_id = photos_create_item(\App::$data['channel'],get_observer_hash(),$p[0],$visibility); - + } - + if($item_id) { $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", intval($item_id), intval($page_owner_uid) ); - + if($r) { $old_tag = $r[0]['tag']; $old_inform = $r[0]['inform']; } } - - + + // make sure the linked item has the same permissions as the photo regardless of any other changes $x = q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where id = %d", @@ -355,7 +356,7 @@ class Photos extends \Zotlabs\Web\Controller { intval($acl->is_private()), intval($item_id) ); - + // make sure the attach has the same permissions as the photo regardless of any other changes $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d and is_photo = 1", dbesc($perm['allow_cid']), @@ -365,46 +366,46 @@ class Photos extends \Zotlabs\Web\Controller { dbesc($resource_id), intval($page_owner_uid) ); - - - + + + if(strlen($rawtags)) { - + $str_tags = ''; $inform = ''; - + // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a mention - + $x = substr($rawtags,0,1); if($x !== '@' && $x !== '#') $rawtags = '@' . $rawtags; - + require_once('include/text.php'); $profile_uid = \App::$profile['profile_uid']; - + $results = linkify_tags($rawtags, (local_channel()) ? local_channel() : $profile_uid); - + $success = $results['success']; $post_tags = array(); - + foreach($results as $result) { $success = $result['success']; if($success['replaced']) { $post_tags[] = array( - 'uid' => $profile_uid, + 'uid' => $profile_uid, 'ttype' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url'] - ); + ); } } - + $r = q("select * from item where id = %d and uid = %d limit 1", intval($item_id), intval($page_owner_uid) ); - + if($r) { $r = fetch_post_tags($r,true); $datarray = $r[0]; @@ -412,42 +413,42 @@ class Photos extends \Zotlabs\Web\Controller { if((! array_key_exists('term',$datarray)) || (! is_array($datarray['term']))) $datarray['term'] = $post_tags; else - $datarray['term'] = array_merge($datarray['term'],$post_tags); + $datarray['term'] = array_merge($datarray['term'],$post_tags); } item_store_update($datarray,$execflag); } - + } $sync = attach_export_data(\App::$data['channel'],$resource_id); - - if($sync) + + if($sync) Libsync::build_sync_packet($page_owner_uid,array('file' => array($sync))); - + goaway(z_root() . '/' . $_SESSION['photo_return']); return; // NOTREACHED - - + + } - - + + /** * default post action - upload a photo */ - + $channel = \App::$data['channel']; $observer = \App::$data['observer']; - + $_REQUEST['source'] = 'photos'; require_once('include/attach.php'); - + if(! local_channel()) { $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']); $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']); $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']); $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']); } - + $matches = []; $partial = false; @@ -467,7 +468,7 @@ class Photos extends \Zotlabs\Web\Controller { if($x['partial']) { header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($result); + json_return_and_die($x); } else { header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); @@ -481,7 +482,7 @@ class Photos extends \Zotlabs\Web\Controller { ]; } } - else { + else { if(! array_key_exists('userfile',$_FILES)) { $_FILES['userfile'] = [ 'name' => $_FILES['files']['name'], @@ -494,53 +495,53 @@ class Photos extends \Zotlabs\Web\Controller { } $r = attach_store($channel,get_observer_hash(), '', $_REQUEST); - + if(! $r['success']) { notice($r['message'] . EOL); goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']); - } + } goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $r['data']['folder']); - + } - - - + + + function get() { - + // URLs: // photos/name // photos/name/album/xxxxx (xxxxx is album name) // photos/name/image/xxxxx - - + + if(observer_prohibited()) { notice( t('Public access denied.') . EOL); return; } - + $unsafe = ((array_key_exists('unsafe',$_REQUEST) && $_REQUEST['unsafe']) ? 1 : 0); - + require_once('include/bbcode.php'); require_once('include/security.php'); require_once('include/conversation.php'); - + if(! x(\App::$data,'channel')) { notice( t('No photos selected') . EOL ); return; } - + $ph = photo_factory(''); $phototypes = $ph->supportedTypes(); - + $_SESSION['photo_return'] = \App::$cmd; - + // - // Parse arguments + // Parse arguments // - + $can_comment = perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'post_comments'); - + if(argc() > 3) { $datatype = argv(2); $datum = argv(3); @@ -552,70 +553,70 @@ class Photos extends \Zotlabs\Web\Controller { else $datatype = 'summary'; } - + if(argc() > 4) $cmd = argv(4); else $cmd = 'view'; - + // // Setup permissions structures // - + $can_post = false; $visitor = 0; - - + + $owner_uid = \App::$data['channel']['channel_id']; $owner_aid = \App::$data['channel']['channel_account_id']; - + $observer = \App::get_observer(); - + $can_post = perm_is_allowed($owner_uid,$observer['xchan_hash'],'write_storage'); $can_view = perm_is_allowed($owner_uid,$observer['xchan_hash'],'view_storage'); - + if(! $can_view) { notice( t('Access to this item is restricted.') . EOL); return; } - + $sql_item = item_permissions_sql($owner_uid,get_observer_hash()); $sql_extra = permissions_sql($owner_uid,get_observer_hash(),'photo'); $sql_attach = permissions_sql($owner_uid,get_observer_hash(),'attach'); nav_set_selected('Photos'); - + $o = '<script src="vendor/blueimp/jquery-file-upload/js/vendor/jquery.ui.widget.js"></script> <script src="vendor/blueimp/jquery-file-upload/js/jquery.iframe-transport.js"></script> <script src="vendor/blueimp/jquery-file-upload/js/jquery.fileupload.js"></script>'; - $o .= "<script> var profile_uid = " . \App::$profile['profile_uid'] + $o .= "<script> var profile_uid = " . \App::$profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n"; - + $_is_owner = (local_channel() && (local_channel() == $owner_uid)); - + /** * Display upload form */ - + if( $can_post) { - + $uploader = ''; - + $ret = array('post_url' => z_root() . '/photos/' . \App::$data['channel']['channel_address'], 'addon_text' => $uploader, 'default_upload' => true); - + call_hooks('photo_upload_form',$ret); - + /* Show space usage */ - + $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ", intval(\App::$data['channel']['channel_account_id']) ); - - + + $limit = engr_units_to_bytes(service_class_fetch(\App::$data['channel']['channel_id'],'photo_upload_limit')); if($limit !== false) { $usage_message = sprintf( t("%1$.2f MB of %2$.2f MB photo storage used."), $r[0]['total'] / 1024000, $limit / 1024000 ); @@ -623,22 +624,22 @@ class Photos extends \Zotlabs\Web\Controller { else { $usage_message = sprintf( t('%1$.2f MB photo storage used.'), $r[0]['total'] / 1024000 ); } - + if($_is_owner) { $channel = \App::get_channel(); - + $acl = new \Zotlabs\Access\AccessList($channel); $channel_acl = $acl->get(); - + $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); } - + $aclselect = (($_is_owner) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : ''); - + // this is wrong but is to work around an issue with js_upload wherein it chokes if these variables - // don't exist. They really should be set to a parseable representation of the channel's default permissions - // which can be processed by getSelected() - + // don't exist. They really should be set to a parseable representation of the channel's default permissions + // which can be processed by getSelected() + if(! $aclselect) { $aclselect = '<input id="group_allow" type="hidden" name="allow_gid[]" value="" /><input id="contact_allow" type="hidden" name="allow_cid[]" value="" /><input id="group_deny" type="hidden" name="deny_gid[]" value="" /><input id="contact_deny" type="hidden" name="deny_cid[]" value="" />'; } @@ -648,11 +649,11 @@ class Photos extends \Zotlabs\Web\Controller { if($datum) { $h = attach_by_hash_nodata($datum,get_observer_hash()); $selname = $h['data']['display_path']; - } + } + - $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer'])); - + if(! $selname) { $def_album = get_pconfig(\App::$data['channel']['channel_id'],'system','photo_path'); if($def_album) { @@ -660,7 +661,7 @@ class Photos extends \Zotlabs\Web\Controller { $albums['album'][] = array('text' => $selname); } } - + $tpl = get_markup_template('photos_upload.tpl'); $upload_form = replace_macros($tpl,array( '$pagename' => t('Upload Photos'), @@ -685,22 +686,22 @@ class Photos extends \Zotlabs\Web\Controller { '$default' => (($ret['default_upload']) ? true : false), '$uploadurl' => $ret['post_url'], '$submit' => t('Upload') - + )); - + } - + // // dispatch request // - + /* * Display a single photo album */ - + if($datatype === 'album') { - head_add_link([ + head_add_link([ 'rel' => 'alternate', 'type' => 'application/json+oembed', 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string), @@ -710,7 +711,7 @@ class Photos extends \Zotlabs\Web\Controller { if($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) { \App::set_pager_itemspage(30); $album = $x['display_path']; - } + } else { goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']); } @@ -721,7 +722,7 @@ class Photos extends \Zotlabs\Web\Controller { $order = 'DESC'; $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN - (SELECT resource_id, max(imgscale) imgscale FROM photo left join attach on folder = '%s' and photo.resource_id = attach.hash WHERE attach.uid = %d AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph + (SELECT resource_id, max(imgscale) imgscale FROM photo left join attach on folder = '%s' and photo.resource_id = attach.hash WHERE attach.uid = %d AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale) ORDER BY created $order LIMIT %d OFFSET %d", dbesc($x['hash']), @@ -739,9 +740,9 @@ class Photos extends \Zotlabs\Web\Controller { if($can_post) { $album_e = $album; $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer'])); - + // @fixme - syncronise actions with DAV - + // $edit_tpl = get_markup_template('album_edit.tpl'); // $album_edit = replace_macros($edit_tpl,array( // '$nametext' => t('Enter a new album name'), @@ -753,32 +754,32 @@ class Photos extends \Zotlabs\Web\Controller { // '$submit' => t('Submit'), // '$dropsubmit' => t('Delete Album') // )); - + } - + if($_GET['order'] === 'posted') $order = array(t('Show Newest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $datum); else $order = array(t('Show Oldest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=posted'); - + $photos = array(); if(count($r)) { $twist = 'rotright'; foreach($r as $rr) { - + if($twist == 'rotright') $twist = 'rotleft'; else $twist = 'rotright'; - + $ext = $phototypes[$rr['mimetype']]; - + $imgalt_e = $rr['filename']; $desc_e = $rr['description']; - + $imagelink = (z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); - + $photos[] = array( 'id' => $rr['id'], 'twist' => ' ' . $twist . rand(2,4), @@ -793,7 +794,7 @@ class Photos extends \Zotlabs\Web\Controller { ); } } - + if($_REQUEST['aj']) { if($photos) { $o = replace_macros(get_markup_template('photosajax.tpl'),array( @@ -821,71 +822,71 @@ class Photos extends \Zotlabs\Web\Controller { '$upload_form' => $upload_form, '$usage' => $usage_message )); - + } - + if((! $photos) && ($_REQUEST['aj'])) { $o .= '<div id="content-complete"></div>'; echo $o; killme(); } - + return $o; - - } - - /** + + } + + /** * Display one photo */ - + if($datatype === 'image') { - + \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n"; - + $x = q("select folder from attach where hash = '%s' and uid = %d $sql_attach limit 1", dbesc($datum), intval($owner_uid) ); // fetch image, item containing image, then comments - - $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM photo WHERE uid = %d AND resource_id = '%s' + + $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM photo WHERE uid = %d AND resource_id = '%s' $sql_extra ORDER BY imgscale ASC ", intval($owner_uid), dbesc($datum) ); - + if(! ($ph && $x)) { - + /* Check again - this time without specifying permissions */ - + $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' LIMIT 1", intval($owner_uid), dbesc($datum) ); - if($ph) + if($ph) notice( t('Permission denied. Access to this item may be restricted.') . EOL); else notice( t('Photo not available') . EOL ); return; } - - - + + + $prevlink = ''; $nextlink = ''; - + if($_GET['order'] === 'posted') $order = 'ASC'; else $order = 'DESC'; - + $prvnxt = q("SELECT hash FROM attach WHERE folder = '%s' AND uid = %d AND is_photo = 1 $sql_attach ORDER BY created $order ", dbesc($x[0]['folder']), intval($owner_uid) - ); + ); if(count($prvnxt)) { for($z = 0; $z < count($prvnxt); $z++) { @@ -899,12 +900,12 @@ class Photos extends \Zotlabs\Web\Controller { break; } } - + $prevlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['hash'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); $nextlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['hash'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); } - - + + if(count($ph) == 1) $hires = $lores = $ph[0]; if(count($ph) > 1) { @@ -917,74 +918,74 @@ class Photos extends \Zotlabs\Web\Controller { $lores = $ph[1]; } } - + $album_link = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $x[0]['folder']; $tools = Null; $lock = Null; - + if($can_post && ($ph[0]['uid'] == $owner_uid)) { $tools = array( 'profile'=>array(z_root() . '/profile_photo/use/'.$ph[0]['resource_id'], t('Use as profile photo')), 'cover'=>array(z_root() . '/cover_photo/use/'.$ph[0]['resource_id'], t('Use as cover photo')), ); } - + // lockstate $lockstate = ( ( (strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid'])) ) ? array('lock', t('Private Photo')) : array('unlock', Null)); - + \App::$page['htmlhead'] .= '<script>$(document).keydown(function(event) {' . "\n"; if($prevlink) \App::$page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 37) { event.preventDefault(); window.location.href = \'' . $prevlink . '\'; }' . "\n"; if($nextlink) \App::$page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 39) { event.preventDefault(); window.location.href = \'' . $nextlink . '\'; }' . "\n"; \App::$page['htmlhead'] .= '});</script>'; - + if($prevlink) $prevlink = array($prevlink, t('Previous')); - + $photo = array( 'href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['imgscale'] . '.' . $phototypes[$hires['mimetype']], 'title'=> t('View Full Size'), 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['imgscale'] . '.' . $phototypes[$lores['mimetype']] ); - + if($nextlink) $nextlink = array($nextlink, t('Next')); - - + + // Do we have an item for this photo? - - $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' + + $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' $sql_item LIMIT 1", dbesc($datum) ); - + $map = null; - + if($linked_items) { - + xchan_query($linked_items); $linked_items = fetch_post_tags($linked_items,true); - + $link_item = $linked_items[0]; $item_normal = item_normal(); - - $r = q("select * from item where parent_mid = '%s' + + $r = q("select * from item where parent_mid = '%s' $item_normal and uid = %d $sql_item ", dbesc($link_item['mid']), intval($link_item['uid']) - + ); - + if($r) { xchan_query($r); $r = fetch_post_tags($r,true); $r = conv_sort($r,'commented'); } - + $tags = array(); if($link_item['term']) { $cnt = 0; @@ -997,23 +998,23 @@ class Photos extends \Zotlabs\Web\Controller { $cnt ++; } } - + if((local_channel()) && (local_channel() == $link_item['uid'])) { q("UPDATE item SET item_unseen = 0 WHERE parent = %d and uid = %d and item_unseen = 1", intval($link_item['parent']), intval(local_channel()) ); } - + if($link_item['coord']) { $map = generate_map($link_item['coord']); } } - + // logger('mod_photo: link_item' . print_r($link_item,true)); - - // FIXME - remove this when we move to conversation module - + + // FIXME - remove this when we move to conversation module + $r = $r[0]['children']; $edit = null; @@ -1023,11 +1024,11 @@ class Photos extends \Zotlabs\Web\Controller { $caption_e = $ph[0]['description']; $aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : ''); $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer'])); - + $_SESSION['album_return'] = bin2hex($ph[0]['album']); $folder_list = attach_folder_select_list($ph[0]['uid']); - + $edit = [ 'edit' => t('Edit photo'), 'id' => $link_item['id'], @@ -1058,17 +1059,17 @@ class Photos extends \Zotlabs\Web\Controller { 'delete' => t('Delete Photo') ]; } - + if(count($linked_items)) { - + $cmnt_tpl = get_markup_template('comment_item.tpl'); $tpl = get_markup_template('photo_item.tpl'); $return_url = \App::$cmd; - + $like_tpl = get_markup_template('like_noshare.tpl'); - + $likebuttons = ''; - + if($observer && ($can_post || $can_comment)) { $likebuttons = [ 'id' => $link_item['id'], @@ -1078,12 +1079,12 @@ class Photos extends \Zotlabs\Web\Controller { 'wait' => t('Please wait') ]; } - + $comments = ''; if(! $r) { if($observer && ($can_post || $can_comment)) { $commentbox = replace_macros($cmnt_tpl,array( - '$return_path' => '', + '$return_path' => '', '$mode' => 'photos', '$jsreload' => $return_url, '$type' => 'wall-comment', @@ -1101,28 +1102,28 @@ class Photos extends \Zotlabs\Web\Controller { )); } } - + $alike = array(); $dlike = array(); - + $like = ''; $dislike = ''; - + $conv_responses = array( 'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')), - 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')), + 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')), 'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title')) ); - - - - + + + + if($r) { - + foreach($r as $item) { builtin_activity_puller($item, $conv_responses); } - + $like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : ''); $like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : ''); @@ -1133,7 +1134,7 @@ class Photos extends \Zotlabs\Web\Controller { $like_list_part = ''; } $like_button_label = tt('Like','Likes',$like_count,'noun'); - + //if (feature_enabled($conv->get_profile_owner(),'dislike')) { $dislike_count = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid']] : ''); $dislike_list = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid'] . '-l'] : ''); @@ -1145,44 +1146,44 @@ class Photos extends \Zotlabs\Web\Controller { $dislike_list_part = ''; } //} - - + + $like = ((isset($alike[$link_item['mid']])) ? format_like($alike[$link_item['mid']],$alike[$link_item['mid'] . '-l'],'like',$link_item['mid']) : ''); $dislike = ((isset($dlike[$link_item['mid']])) ? format_like($dlike[$link_item['mid']],$dlike[$link_item['mid'] . '-l'],'dislike',$link_item['mid']) : ''); - + // display comments - + foreach($r as $item) { $comment = ''; $template = $tpl; $sparkle = ''; - + if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) && ($item['id'] != $item['parent'])) continue; - + $redirect_url = z_root() . '/redir/' . $item['cid'] ; - - + + $profile_url = zid($item['author']['xchan_url']); $sparkle = ''; - - + + $profile_name = $item['author']['xchan_name']; $profile_avatar = $item['author']['xchan_photo_m']; - + $profile_link = $profile_url; - + $drop = ''; - + if($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete'))); - - + + $name_e = $profile_name; $title_e = $item['title']; unobscure($item); $body_e = prepare_text($item['body'],$item['mimetype']); - + $comments .= replace_macros($template,array( '$id' => $item['id'], '$mode' => 'photos', @@ -1197,9 +1198,9 @@ class Photos extends \Zotlabs\Web\Controller { '$drop' => $drop, '$comment' => $comment )); - + } - + if($observer && ($can_post || $can_comment)) { $commentbox = replace_macros($cmnt_tpl,array( '$return_path' => '', @@ -1216,20 +1217,20 @@ class Photos extends \Zotlabs\Web\Controller { '$ww' => '' )); } - + } $paginate = paginate($a); } - + $album_e = array($album_link,$ph[0]['album']); $like_e = $like; $dislike_e = $dislike; - - + + $response_verbs = array('like'); if(feature_enabled($owner_uid,'dislike')) $response_verbs[] = 'dislike'; - + $responses = get_responses($conv_responses,$response_verbs,'',$link_item); $hookdata = [ @@ -1238,7 +1239,7 @@ class Photos extends \Zotlabs\Web\Controller { 'nickname' => \App::$data['channel']['channel_address'] ]; call_hooks('photo_view_filter', $hookdata); - + $photo_tpl = get_markup_template('photo_view.tpl'); $o .= replace_macros($photo_tpl, array( '$id' => $ph[0]['id'], @@ -1255,7 +1256,7 @@ class Photos extends \Zotlabs\Web\Controller { '$tag_hdr' => t('In This Photo:'), '$tags' => $tags, 'responses' => $responses, - '$edit' => $edit, + '$edit' => $edit, '$map' => $map, '$map_text' => t('Map'), '$likebuttons' => $likebuttons, @@ -1277,26 +1278,26 @@ class Photos extends \Zotlabs\Web\Controller { '$paginate' => $paginate, '$onclick' => $hookdata['onclick'] )); - + \App::$data['photo_html'] = $o; - + return $o; } - + // Default - show recent photos with upload link (if applicable) //$o = ''; - + \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n"; - + \App::set_pager_itemspage(30); - - $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path - FROM photo p - INNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo - WHERE photo.uid = %d AND photo_usage IN ( %d, %d ) - AND is_nsfw = %d $sql_extra group by resource_id ) ph - ON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale) + + $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path + FROM photo p + INNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo + WHERE photo.uid = %d AND photo_usage IN ( %d, %d ) + AND is_nsfw = %d $sql_extra group by resource_id ) ph + ON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale) ORDER by p.created DESC LIMIT %d OFFSET %d", intval(\App::$data['channel']['channel_id']), intval(PHOTO_NORMAL), @@ -1305,9 +1306,9 @@ class Photos extends \Zotlabs\Web\Controller { intval(\App::$pager['itemspage']), intval(\App::$pager['start']) ); - - - + + + $photos = array(); if($r) { $twist = 'rotright'; @@ -1321,7 +1322,7 @@ class Photos extends \Zotlabs\Web\Controller { else $twist = 'rotright'; $ext = $phototypes[$rr['mimetype']]; - + $alt_e = $rr['filename']; $name_e = dirname($rr['display_path']); @@ -1335,11 +1336,11 @@ class Photos extends \Zotlabs\Web\Controller { 'album' => array( 'name' => $name_e, ), - + ); } } - + if($_REQUEST['aj']) { if($photos) { $o = replace_macros(get_markup_template('photosajax.tpl'),array( @@ -1355,7 +1356,7 @@ class Photos extends \Zotlabs\Web\Controller { } else { $o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; </script>"; - $tpl = get_markup_template('photos_recent.tpl'); + $tpl = get_markup_template('photos_recent.tpl'); $o .= replace_macros($tpl, array( '$title' => t('Recent Photos'), '$album_id' => bin2hex(t('Recent Photos')), @@ -1365,18 +1366,18 @@ class Photos extends \Zotlabs\Web\Controller { '$upload_form' => $upload_form, '$usage' => $usage_message )); - + } - + if((! $photos) && ($_REQUEST['aj'])) { $o .= '<div id="content-complete"></div>'; echo $o; killme(); } - + // paginate($a); return $o; } - - + + } diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 9ac0e725e..ca6ab435f 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -12,11 +12,11 @@ class Profiles extends \Zotlabs\Web\Controller { function init() { nav_set_selected('Profiles', 'settings/profiles'); - + if(! local_channel()) { return; } - + if((argc() > 2) && (argv(1) === "drop") && intval(argv(2))) { $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1", intval(argv(2)), @@ -28,11 +28,11 @@ class Profiles extends \Zotlabs\Web\Controller { return; // NOTREACHED } $profile_guid = $r['profile_guid']; - + check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); - + // move every contact using this profile as their default to the user default - + $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", intval(local_channel()), dbesc($profile_guid), @@ -44,34 +44,34 @@ class Profiles extends \Zotlabs\Web\Controller { ); if($r) info( t('Profile deleted.') . EOL); - - // @fixme this is a much more complicated sync - add any changed abook entries and + + // @fixme this is a much more complicated sync - add any changed abook entries and // also add deleted flag to profile structure // profiles_build_sync is just here as a placeholder - it doesn't work at all here - + // profiles_build_sync(local_channel()); - + goaway(z_root() . '/profiles'); return; // NOTREACHED } - - - - - + + + + + if((argc() > 1) && (argv(1) === 'new')) { - + // check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); - + $r0 = q("SELECT id FROM profile WHERE uid = %d", intval(local_channel())); $num_profiles = count($r0); - + $name = t('Profile-') . ($num_profiles + 1); - + $r1 = q("SELECT fullname, photo, thumb FROM profile WHERE uid = %d AND is_default = 1 LIMIT 1", intval(local_channel())); - + $r2 = profile_store_lowlevel( [ 'aid' => intval(get_account_id()), @@ -83,27 +83,27 @@ class Profiles extends \Zotlabs\Web\Controller { 'thumb' => $r1[0]['thumb'] ] ); - + $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", intval(local_channel()), dbesc($name) ); - + info( t('New profile created.') . EOL); if(count($r3) == 1) goaway(z_root() . '/profiles/' . $r3[0]['id']); - + goaway(z_root() . '/profiles'); - } - + } + if((argc() > 2) && (argv(1) === 'clone')) { - + check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); - + $r0 = q("SELECT id FROM profile WHERE uid = %d", intval(local_channel())); $num_profiles = count($r0); - + $name = t('Profile-') . ($num_profiles + 1); $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", intval(local_channel()), @@ -116,30 +116,30 @@ class Profiles extends \Zotlabs\Web\Controller { } unset($r1[0]['id']); $r1[0]['is_default'] = 0; - $r1[0]['publish'] = 0; + $r1[0]['publish'] = 0; $r1[0]['profile_name'] = dbesc($name); $r1[0]['profile_guid'] = dbesc(random_string()); - + create_table_from_array('profile', $r1[0]); - + $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", intval(local_channel()), dbesc($name) ); info( t('New profile created.') . EOL); - + profiles_build_sync(local_channel()); - + if(($r3) && (count($r3) == 1)) goaway(z_root() . '/profiles/' . $r3[0]['id']); - + goaway(z_root() . '/profiles'); - + return; // NOTREACHED } - + if((argc() > 2) && (argv(1) === 'export')) { - + $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", intval(local_channel()), intval(argv(2)) @@ -151,7 +151,7 @@ class Profiles extends \Zotlabs\Web\Controller { } header('content-type: application/octet_stream'); header('content-disposition: attachment; filename="' . $r1[0]['profile_name'] . '.json"' ); - + unset($r1[0]['id']); unset($r1[0]['aid']); unset($r1[0]['uid']); @@ -162,10 +162,10 @@ class Profiles extends \Zotlabs\Web\Controller { echo json_encode($r1[0]); killme(); } - - - - + + + + // Run profile_load() here to make sure the theme is set before // we start loading content if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { @@ -187,28 +187,28 @@ class Profiles extends \Zotlabs\Web\Controller { \App::$error = 404; return; } - + $chan = \App::get_channel(); - + profile_load($chan['channel_address'],$r[0]['id']); } } - + function post() { - + if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } - + require_once('include/activities.php'); - + $namechanged = false; - - + + // import from json export file. // Only import fields that are allowed on this hub - + if(x($_FILES,'userfile')) { $src = $_FILES['userfile']['tmp_name']; $filesize = intval($_FILES['userfile']['size']); @@ -230,10 +230,10 @@ class Profiles extends \Zotlabs\Web\Controller { } } } - + call_hooks('profile_post', $_POST); - - + + if((argc() > 1) && (argv(1) !== "new") && intval(argv(1))) { $orig = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", intval(\App::$argv[1]), @@ -243,26 +243,26 @@ class Profiles extends \Zotlabs\Web\Controller { notice( t('Profile not found.') . EOL); return; } - + check_form_security_token_redirectOnErr('/profiles', 'profile_edit'); - + $is_default = (($orig[0]['is_default']) ? 1 : 0); - + $profile_name = notags(trim($_POST['profile_name'])); if(! strlen($profile_name)) { notice( t('Profile Name is required.') . EOL); return; } - + $dob = $_POST['dob'] ? escape_tags(trim($_POST['dob'])) : '0000-00-00'; // FIXME: Needs to be validated? - + $y = substr($dob,0,4); if((! ctype_digit($y)) || ($y < 1900)) $ignore_year = true; else $ignore_year = false; - + if($dob != '0000-00-00') { if(strpos($dob,'0000-') === 0) { $ignore_year = true; @@ -272,12 +272,12 @@ class Profiles extends \Zotlabs\Web\Controller { if($ignore_year) $dob = '0000-' . $dob; } - + $name = escape_tags(trim($_POST['name'])); - + if($orig[0]['fullname'] != $name) { $namechanged = true; - + $v = validate_channelname($name); if($v) { notice($v); @@ -285,7 +285,7 @@ class Profiles extends \Zotlabs\Web\Controller { $name = $orig[0]['fullname']; } } - + $pdesc = escape_tags(trim($_POST['pdesc'])); $gender = escape_tags(trim($_POST['gender'])); $address = escape_tags(trim($_POST['address'])); @@ -301,10 +301,10 @@ class Profiles extends \Zotlabs\Web\Controller { $hometown = escape_tags(trim($_POST['hometown'])); $politic = escape_tags(trim($_POST['politic'])); $religion = escape_tags(trim($_POST['religion'])); - + $likes = fix_mce_lf(escape_tags(trim($_POST['likes']))); $dislikes = fix_mce_lf(escape_tags(trim($_POST['dislikes']))); - + $about = fix_mce_lf(escape_tags(trim($_POST['about']))); $interest = fix_mce_lf(escape_tags(trim($_POST['interest']))); $contact = fix_mce_lf(escape_tags(trim($_POST['contact']))); @@ -316,11 +316,11 @@ class Profiles extends \Zotlabs\Web\Controller { $romance = fix_mce_lf(escape_tags(trim($_POST['romance']))); $work = fix_mce_lf(escape_tags(trim($_POST['work']))); $education = fix_mce_lf(escape_tags(trim($_POST['education']))); - + $hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0); - + // start fresh and create a new vcard. TODO: preserve the original guid or whatever else needs saving -// $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null); +// $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null); $orig_vcard = null; @@ -347,7 +347,7 @@ class Profiles extends \Zotlabs\Web\Controller { 5 => $postal_code, 6 => $country_name ]; - + $profile_vcard = update_vcard($defcard,$orig_vcard); $orig_vcard = \Sabre\VObject\Reader::read($profile_vcard); @@ -370,19 +370,19 @@ class Profiles extends \Zotlabs\Web\Controller { linkify_tags($romance, local_channel()); linkify_tags($work, local_channel()); linkify_tags($education, local_channel()); - - + + $with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : ''); - + if(! strlen($howlong)) $howlong = NULL_DATE; else $howlong = datetime_convert(date_default_timezone_get(),'UTC',$howlong); - + // linkify the relationship target if applicable - + $withchanged = false; - + if(strlen($with)) { if($with != strip_tags($orig[0]['partner'])) { $withchanged = true; @@ -392,7 +392,7 @@ class Profiles extends \Zotlabs\Web\Controller { $lookup = substr($lookup,1); $lookup = str_replace('_',' ', $lookup); $newname = $lookup; - + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", dbesc($newname), intval(local_channel()) @@ -407,8 +407,8 @@ class Profiles extends \Zotlabs\Web\Controller { $prf = $r[0]['xchan_url']; $newname = $r[0]['xchan_name']; } - - + + if($prf) { $with = str_replace($lookup,'<a href="' . $prf . '">' . $newname . '</a>', $with); if(strpos($with,'@') === 0) @@ -418,7 +418,7 @@ class Profiles extends \Zotlabs\Web\Controller { else $with = $orig[0]['partner']; } - + $profile_fields_basic = get_profile_fields_basic(); $profile_fields_advanced = get_profile_fields_advanced(); $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); @@ -426,7 +426,7 @@ class Profiles extends \Zotlabs\Web\Controller { $fields = $profile_fields_advanced; else $fields = $profile_fields_basic; - + $z = q("select * from profdef where true"); if($z) { foreach($z as $zz) { @@ -453,7 +453,7 @@ class Profiles extends \Zotlabs\Web\Controller { } } } - + $changes = array(); $value = ''; if($is_default) { @@ -513,12 +513,12 @@ class Profiles extends \Zotlabs\Web\Controller { $comma2 = (($region && $country_name) ? ', ' : ''); $value = $locality . $comma1 . $region . $comma2 . $country_name; } - + profile_activity($changes,$value); - - } - - $r = q("UPDATE profile + + } + + $r = q("UPDATE profile SET profile_name = '%s', fullname = '%s', pdesc = '%s', @@ -591,10 +591,10 @@ class Profiles extends \Zotlabs\Web\Controller { intval(argv(1)), intval(local_channel()) ); - + if($r) info( t('Profile updated.') . EOL); - + $r = q("select * from profile where id = %d and uid = %d limit 1", intval(argv(1)), intval(local_channel()) @@ -603,9 +603,9 @@ class Profiles extends \Zotlabs\Web\Controller { require_once('include/zot.php'); Libsync::build_sync_packet(local_channel(),array('profile' => $r)); } - + $channel = \App::get_channel(); - + if($namechanged && $is_default) { $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_url = '%s'", dbesc($name), @@ -617,7 +617,7 @@ class Profiles extends \Zotlabs\Web\Controller { dbesc($channel['xchan_hash']) ); } - + if($is_default) { // reload the info for the sidebar widget - why does this not work? profile_load($channel['channel_address']); @@ -625,24 +625,24 @@ class Profiles extends \Zotlabs\Web\Controller { } } } - - + + function get() { - + $o = ''; - + $channel = \App::get_channel(); - + if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } - + require_once('include/channel.php'); - + $profile_fields_basic = get_profile_fields_basic(); $profile_fields_advanced = get_profile_fields_advanced(); - + if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { if(feature_enabled(local_channel(),'multi_profiles')) $id = \App::$argv[1]; @@ -652,7 +652,7 @@ class Profiles extends \Zotlabs\Web\Controller { ); if($x) $id = $x[0]['id']; - } + } $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", intval($id), intval(local_channel()) @@ -661,20 +661,20 @@ class Profiles extends \Zotlabs\Web\Controller { notice( t('Profile not found.') . EOL); return; } - + $editselect = 'none'; - + \App::$page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array( '$baseurl' => z_root(), '$editselect' => $editselect, )); - + $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); if($advanced) $fields = $profile_fields_advanced; else $fields = $profile_fields_basic; - + $hide_friends = array( 'hide_friends', t('Hide your connections list from viewers of this profile'), @@ -682,36 +682,36 @@ class Profiles extends \Zotlabs\Web\Controller { '', array(t('No'),t('Yes')) ); - + $q = q("select * from profdef where true"); if($q) { $extra_fields = array(); - + foreach($q as $qq) { $mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1", - dbesc($qq['field_name']), + dbesc($qq['field_name']), dbesc($r[0]['profile_guid']), intval(local_channel()) ); - + if(array_key_exists($qq['field_name'],$fields)) { $extra_fields[] = array($qq['field_name'],$qq['field_desc'],(($mine) ? $mine[0]['v'] : ''), $qq['field_help']); } } } - + //logger('extra_fields: ' . print_r($extra_fields,true)); $vc = $r[0]['profile_vcard']; - $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); + $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null); $vcard = (($vctmp) ? get_vcard_array($vctmp,$r[0]['id']) : [] ); - + $f = get_config('system','birthday_input_format'); if(! $f) $f = 'ymd'; - + $is_default = (($r[0]['is_default']) ? 1 : 0); - + $tpl = get_markup_template("profile_edit.tpl"); $o .= replace_macros($tpl,array( '$multi_profiles' => ((feature_enabled(local_channel(),'multi_profiles')) ? true : false), @@ -749,7 +749,7 @@ class Profiles extends \Zotlabs\Web\Controller { '$default' => t('This is your default profile.') . EOL . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))), '$advanced' => $advanced, '$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'), - '$pdesc' => array('pdesc', t('Title/Description'), $r[0]['pdesc']), + '$pdesc' => array('pdesc', t('Short title/tescription'), $r[0]['pdesc'], t('Maximal 190 characters'), '', 'maxlength="190"'), '$dob' => dob($r[0]['dob']), '$hide_friends' => $hide_friends, '$address' => array('address', t('Street address'), $r[0]['address']), @@ -802,18 +802,18 @@ class Profiles extends \Zotlabs\Web\Controller { '$delete' => t('Delete'), '$cancel' => t('Cancel'), )); - + $arr = array('profile' => $r[0], 'entry' => $o); call_hooks('profile_edit', $arr); - + return $o; } else { - + $r = q("SELECT * FROM profile WHERE uid = %d", local_channel()); if($r) { - + $tpl = get_markup_template('profile_entry.tpl'); foreach($r as $rr) { $profiles .= replace_macros($tpl, array( @@ -821,24 +821,24 @@ class Profiles extends \Zotlabs\Web\Controller { '$id' => $rr['id'], '$alt' => t('Profile Image'), '$profile_name' => $rr['profile_name'], - '$visible' => (($rr['is_default']) - ? '<strong>' . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))) . '</strong>' + '$visible' => (($rr['is_default']) + ? '<strong>' . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))) . '</strong>' : '<a href="' . z_root() . '/profperm/' . $rr['id'] . '" />' . t('Edit visibility') . '</a>') )); } - + $tpl_header = get_markup_template('profile_listing_header.tpl'); $o .= replace_macros($tpl_header,array( '$header' => t('Edit Profiles'), '$cr_new' => t('Create New'), '$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new"), '$profiles' => $profiles - )); - + )); + } return $o; } - + } - + } diff --git a/Zotlabs/Module/Pubsites.php b/Zotlabs/Module/Pubsites.php index daec5dde3..4b64d9af6 100644 --- a/Zotlabs/Module/Pubsites.php +++ b/Zotlabs/Module/Pubsites.php @@ -1,18 +1,19 @@ <?php namespace Zotlabs\Module; +use Zotlabs\Lib\Libzotdir; class Pubsites extends \Zotlabs\Web\Controller { function get() { - require_once('include/dir_fns.php'); + require_once('include/dir_fns.php'); $dirmode = intval(get_config('system','directory_mode')); - + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { $url = z_root() . '/dirsearch'; } if(! $url) { - $directory = find_upstream_directory($dirmode); + $directory = Libzotdir::find_upstream_directory($dirmode); $url = $directory['url'] . '/dirsearch'; } $url .= '/sites'; @@ -20,12 +21,12 @@ class Pubsites extends \Zotlabs\Web\Controller { $rating_enabled = get_config('system','rating_enabled'); $o .= '<div class="generic-content-wrapper">'; - + $o .= '<div class="section-title-wrapper"><h2>' . t('Public Hubs') . '</h2></div>'; - - $o .= '<div class="section-content-tools-wrapper"><div class="descriptive-text">' . + + $o .= '<div class="section-content-tools-wrapper"><div class="descriptive-text">' . t('The listed hubs allow public registration for the $Projectname network. All hubs in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some hubs may require subscription or provide tiered service plans. The hub itself <strong>may</strong> provide additional details.') . '</div>' . EOL; - + $ret = z_fetch_url($url); if($ret['success']) { $j = json_decode($ret['body'],true); @@ -48,8 +49,8 @@ class Pubsites extends \Zotlabs\Web\Controller { $host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3)); $rate_links = ((local_channel()) ? '<td><a href="rate?f=&target=' . $host . '" class="btn-btn-default"><i class="fa fa-check-square-o"></i> ' . t('Rate') . '</a></td>' : ''); $location = ''; - if(!empty($jj['location'])) { - $location = '<p title="' . t('Location') . '" style="margin: 5px 5px 0 0; text-align: right"><i class="fa fa-globe"></i> ' . $jj['location'] . '</p>'; + if(!empty($jj['location'])) { + $location = '<p title="' . t('Location') . '" style="margin: 5px 5px 0 0; text-align: right"><i class="fa fa-globe"></i> ' . $jj['location'] . '</p>'; } else { $location = '<br /> '; @@ -61,14 +62,14 @@ class Pubsites extends \Zotlabs\Web\Controller { $o .= '</tr>'; } } - + $o .= '</table>'; - + $o .= '</div></div>'; - + } } return $o; } - + } diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 55c96b23d..113f0a196 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -23,9 +23,6 @@ class Pubstream extends \Zotlabs\Web\Controller { } } - if($load) - $_SESSION['loadtime'] = datetime_convert(); - if((observer_prohibited(true))) { return login(); } @@ -59,7 +56,6 @@ class Pubstream extends \Zotlabs\Web\Controller { $item_normal = item_normal(); $item_normal_update = item_normal_update(); - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); $net = ((array_key_exists('net',$_REQUEST)) ? escape_tags($_REQUEST['net']) : ''); $title = replace_macros(get_markup_template("section_title.tpl"),array( @@ -103,11 +99,6 @@ class Pubstream extends \Zotlabs\Web\Controller { $o .= status_editor($a,$x,false,'Pubstream'); $o .= '</div>'; } - - - - - if(! $update && !$load) { @@ -116,8 +107,6 @@ class Pubstream extends \Zotlabs\Web\Controller { if(!$mid) $_SESSION['static_loadtime'] = datetime_convert(); - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - $maxheight = get_config('system','home_divmore_height'); if(! $maxheight) $maxheight = 400; @@ -148,7 +137,6 @@ class Pubstream extends \Zotlabs\Web\Controller { '$nouveau' => '0', '$wall' => '0', '$list' => '0', - '$static' => $static, '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1), '$search' => '', '$xchan' => '', @@ -200,14 +188,10 @@ class Pubstream extends \Zotlabs\Web\Controller { $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); $abook_uids = " and abook.abook_channel = " . intval(\App::$profile['profile_uid']) . " "; - - $simple_update = (($_SESSION['loadtime']) ? " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' " : ''); - - if($load) - $simple_update = ''; - if($static && $simple_update) - $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + $simple_update = ''; + if($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; //logger('update: ' . $update . ' load: ' . $load); @@ -220,10 +204,10 @@ class Pubstream extends \Zotlabs\Web\Controller { $r = q("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query - WHERE mid like '%s' $uids $item_normal + WHERE mid = '%s' $uids $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) - $sql_extra3 $sql_extra $sql_nets $net_query2 LIMIT 1", - dbesc($mid . '%') + $sql_extra3 $sql_extra $sql_nets $net_query2", + dbesc($mid) ); } else { @@ -243,10 +227,10 @@ class Pubstream extends \Zotlabs\Web\Controller { $r = q("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query - WHERE mid like '%s' $uids $item_normal_update $simple_update + WHERE mid = '%s' $uids $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) - $sql_extra3 $sql_extra $sql_nets $net_query2 LIMIT 1", - dbesc($mid . '%') + $sql_extra3 $sql_extra $sql_nets $net_query2", + dbesc($mid) ); } else { @@ -259,7 +243,6 @@ class Pubstream extends \Zotlabs\Web\Controller { $sql_extra3 $sql_extra $sql_nets $net_query2" ); } - $_SESSION['loadtime'] = datetime_convert(); } // Then fetch all the children of the parents that are on this page @@ -291,7 +274,7 @@ class Pubstream extends \Zotlabs\Web\Controller { // fake it $mode = (($hashtags) ? 'search' : 'pubstream'); - + $o .= conversation($items,$mode,$update,$page_mode); if($mid) @@ -300,6 +283,8 @@ class Pubstream extends \Zotlabs\Web\Controller { if(($items) && (! $update)) $o .= alt_pager(count($items)); + $_SESSION['loadtime'] = datetime_convert(); + return $o; } diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php index f03dae2bf..031270845 100644 --- a/Zotlabs/Module/Rpost.php +++ b/Zotlabs/Module/Rpost.php @@ -10,7 +10,7 @@ require_once('include/zot.php'); /** * remote post - * + * * https://yoursite/rpost?f=&title=&body=&remote_return= * * This can be called via either GET or POST, use POST for long body content as suhosin often limits GET parameter length @@ -20,7 +20,7 @@ require_once('include/zot.php'); * body= Body of post * url= URL which will be parsed and the results appended to the body * source= Source application - * post_id= post_id of post to 'share' (local use only) + * post_id= post_id of post to 'share' (local use only) * remote_return= absolute URL to return after posting is finished * type= choices are 'html' or 'bbcode', default is 'bbcode' * @@ -32,16 +32,16 @@ require_once('include/zot.php'); class Rpost extends \Zotlabs\Web\Controller { function get() { - + $o = ''; - + if(! local_channel()) { if(remote_channel()) { // redirect to your own site. // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin // blocks them. - + $url = get_rpost_path(\App::get_observer()); // make sure we're not looping to our own hub if(($url) && (! stristr($url, \App::get_hostname()))) { @@ -53,10 +53,10 @@ class Rpost extends \Zotlabs\Web\Controller { goaway($url); } } - + // The login procedure is going to bugger our $_REQUEST variables // so save them in the session. - + if(array_key_exists('body',$_REQUEST)) { $_SESSION['rpost'] = $_REQUEST; } @@ -64,14 +64,14 @@ class Rpost extends \Zotlabs\Web\Controller { } nav_set_selected('Post'); - + // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables - + if((! array_key_exists('body',$_REQUEST)) && (array_key_exists('rpost',$_SESSION))) { $_REQUEST = $_SESSION['rpost']; unset($_SESSION['rpost']); } - + if(array_key_exists('channel',$_REQUEST)) { $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", intval(get_account_id()), @@ -82,7 +82,7 @@ class Rpost extends \Zotlabs\Web\Controller { $change = change_channel($r[0]['channel_id']); } } - + if($_REQUEST['remote_return']) { $_SESSION['remote_return'] = $_REQUEST['remote_return']; } @@ -91,21 +91,27 @@ class Rpost extends \Zotlabs\Web\Controller { goaway($_SESSION['remote_return']); goaway(z_root() . '/network'); } - + $plaintext = true; - + if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') { require_once('include/html2bbcode.php'); - $_REQUEST['body'] = html2bbcode($_REQUEST['body']); + $_REQUEST['body'] = html2bbcode($_REQUEST['body']); } - + $channel = \App::get_channel(); - - - $acl = new \Zotlabs\Access\AccessList($channel); - - $channel_acl = $acl->get(); - + + if($_REQUEST['acl']) { + $acl = new \Zotlabs\Access\AccessList([]); + $acl->set($_REQUEST['acl']); + $channel_acl = $acl->get(); + } + else { + $acl = new \Zotlabs\Access\AccessList($channel); + $channel_acl = $acl->get(); + } + + if($_REQUEST['url']) { $x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url'])); if($x['success']) @@ -115,7 +121,7 @@ class Rpost extends \Zotlabs\Web\Controller { if($_REQUEST['post_id']) { $_REQUEST['body'] .= '[share=' . intval($_REQUEST['post_id']) . '][/share]'; } - + $x = array( 'is_owner' => true, 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), @@ -137,19 +143,19 @@ class Rpost extends \Zotlabs\Web\Controller { 'bbcode' => true, 'jotnets' => true ); - + $editor = status_editor($a,$x,false,'Rpost'); - + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( '$title' => t('Edit post'), '$cancel' => '', '$editor' => $editor )); - + return $o; - + } - - - + + + } diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index d586ae12f..c22bf2836 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -19,9 +19,6 @@ class Search extends \Zotlabs\Web\Controller { } } - if($load) - $_SESSION['loadtime'] = datetime_convert(); - nav_set_selected('Search'); require_once("include/bbcode.php"); @@ -54,8 +51,6 @@ class Search extends \Zotlabs\Web\Controller { $search = ((x($_GET,'tag')) ? trim(escape_tags(rawurldecode($_GET['tag']))) : ''); } - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - $o .= search($search,'search-box','/search',((local_channel()) ? true : false)); if(strpos($search,'#') === 0) { @@ -105,9 +100,6 @@ class Search extends \Zotlabs\Web\Controller { if((! $update) && (! $load)) { - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0); - - // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, // because browser prefetching might change it on us. We have to deliver it with the page. @@ -131,7 +123,6 @@ class Search extends \Zotlabs\Web\Controller { '$dm' => '0', '$nouveau' => '0', '$wall' => '0', - '$static' => $static, '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1), '$search' => (($tag) ? urlencode('#') : '') . $search, diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php index 01ae8652a..cade0a529 100644 --- a/Zotlabs/Module/Settings/Display.php +++ b/Zotlabs/Module/Settings/Display.php @@ -28,7 +28,6 @@ class Display { $user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0); $nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0); $title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0); - $manual_update = ((array_key_exists('manual_update',$_POST)) ? intval($_POST['manual_update']) : 0); $start_menu = ((x($_POST,'start_menu')) ? intval($_POST['start_menu']) : 0); $browser_update = ((x($_POST,'browser_update')) ? intval($_POST['browser_update']) : 0); @@ -47,7 +46,6 @@ class Display { set_pconfig(local_channel(),'system','itemspage', $itemspage); set_pconfig(local_channel(),'system','no_smilies',1-intval($nosmile)); set_pconfig(local_channel(),'system','title_tosource',$title_tosource); - set_pconfig(local_channel(),'system','manual_conversation_update', $manual_update); set_pconfig(local_channel(),'system','channel_menu', $channel_menu); set_pconfig(local_channel(),'system','start_menu', $start_menu); @@ -200,7 +198,6 @@ class Display { '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 30 items')), '$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1-intval($nosmile), '', $yes_no), '$channel_menu' => [ 'channel_menu', t('Provide channel menu in navigation bar'), get_pconfig(local_channel(),'system','channel_menu',get_config('system','channel_menu',0)), t('Default: channel menu located in app menu'),$yes_no ], - '$manual_update' => array('manual_update', t('Manual conversation updates'), channel_manual_conv_update(local_channel()), t('Default is on, turning this off may increase screen jumping'), $yes_no), '$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no), '$theme_config' => $theme_config, '$start_menu' => ['start_menu', t('New Member Links'), $start_menu, t('Display new member quick links menu'), $yes_no] diff --git a/Zotlabs/Module/Sse.php b/Zotlabs/Module/Sse.php index b68fe6705..46b4a8d87 100644 --- a/Zotlabs/Module/Sse.php +++ b/Zotlabs/Module/Sse.php @@ -14,6 +14,7 @@ class Sse extends Controller { public static $ob_hash; public static $sse_id; public static $vnotify; + public static $sse_enabled; function init() { @@ -49,18 +50,86 @@ class Sse extends Controller { $sys = get_sys_channel(); $sleep_seconds = 3; - header("Content-Type: text/event-stream"); - header("Cache-Control: no-cache"); - header("Connection: keep-alive"); - header("X-Accel-Buffering: no"); + self::$sse_enabled = get_config('system', 'sse_enabled', 0); - while(true) { + if(self::$sse_enabled) { - /** - * Update chat presence indication (if applicable) - */ + // Server Sent Events + + header("Content-Type: text/event-stream"); + header("Cache-Control: no-cache"); + header("Connection: keep-alive"); + header("X-Accel-Buffering: no"); + + while(true) { + + if(! self::$sse_id) { + + // Update chat presence indication + + $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", + dbesc(self::$ob_hash), + dbesc($_SERVER['REMOTE_ADDR']) + ); + $basic_presence = false; + if($r) { + $basic_presence = true; + q("update chatpresence set cp_last = '%s' where cp_id = %d", + dbesc(datetime_convert()), + intval($r[0]['cp_id']) + ); + } + if(! $basic_presence) { + q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) + values( '%s', '%s', '%s', '%s' ) ", + dbesc(self::$ob_hash), + dbesc(datetime_convert()), + dbesc('online'), + dbesc($_SERVER['REMOTE_ADDR']) + ); + } + } + + XConfig::Load(self::$ob_hash); + + $result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []); + $lock = XConfig::Get(self::$ob_hash, 'sse', 'lock'); + + if($result && !$lock) { + echo "event: notifications\n"; + echo 'data: ' . json_encode($result); + echo "\n\n"; + + XConfig::Set(self::$ob_hash, 'sse', 'notifications', []); + unset($result); + } + + // always send heartbeat to detect disconnected clients + echo "event: heartbeat\n"; + echo 'data: {}'; + echo "\n\n"; + + ob_end_flush(); + flush(); + + if(connection_status() != CONNECTION_NORMAL || connection_aborted()) { + //TODO: this does not seem to be triggered + XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE); + break; + } + + sleep($sleep_seconds); + + } + + } + else { + // Fallback to traditional polling if(! self::$sse_id) { + + // Update chat presence indication + $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", dbesc(self::$ob_hash), dbesc($_SERVER['REMOTE_ADDR']) @@ -90,29 +159,11 @@ class Sse extends Controller { $lock = XConfig::Get(self::$ob_hash, 'sse', 'lock'); if($result && !$lock) { - echo "event: notifications\n"; - echo 'data: ' . json_encode($result); - echo "\n\n"; - XConfig::Set(self::$ob_hash, 'sse', 'notifications', []); - unset($result); - } - - // always send heartbeat to detect disconnected clients - echo "event: heartbeat\n"; - echo 'data: {}'; - echo "\n\n"; - - ob_end_flush(); - flush(); - - if(connection_status() != CONNECTION_NORMAL || connection_aborted()) { - //TODO: this does not seem to be triggered - XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE); - break; + json_return_and_die($result); } - sleep($sleep_seconds); + killme(); } diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php index 287c24829..396e07001 100644 --- a/Zotlabs/Module/Sse_bs.php +++ b/Zotlabs/Module/Sse_bs.php @@ -123,7 +123,7 @@ class Sse_bs extends Controller { $mids[] = '\'' . dbesc(@base64url_decode(substr($a,4))) . '\''; } - $str = implode($mids, ','); + $str = implode(',', $mids); $x = [ 'channel_id' => self::$uid, 'update' => 'unset' ]; call_hooks('update_unseen',$x); @@ -162,7 +162,7 @@ class Sse_bs extends Controller { $item_normal = item_normal(); if ($notifications) { - $items = q("SELECT * FROM item + $items = q("SELECT * FROM item WHERE uid = %d AND created <= '%s' AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1) @@ -190,7 +190,7 @@ class Sse_bs extends Controller { } - $r = q("SELECT count(id) as total FROM item + $r = q("SELECT count(id) as total FROM item WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1) AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' @@ -231,10 +231,10 @@ class Sse_bs extends Controller { $item_normal = item_normal(); if ($notifications) { - $items = q("SELECT * FROM item + $items = q("SELECT * FROM item WHERE uid = %d AND created <= '%s' - AND item_unseen = 1 AND item_wall = 0 AND item_private = 2 + AND item_unseen = 1 AND item_private = 2 AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal @@ -259,8 +259,8 @@ class Sse_bs extends Controller { } - $r = q("SELECT count(id) as total FROM item - WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private = 2 + $r = q("SELECT count(id) as total FROM item + WHERE uid = %d and item_unseen = 1 AND item_private = 2 $item_normal $sql_extra AND author_xchan != '%s'", @@ -300,10 +300,10 @@ class Sse_bs extends Controller { $item_normal = item_normal(); if ($notifications) { - $items = q("SELECT * FROM item + $items = q("SELECT * FROM item WHERE uid = %d AND created <= '%s' - AND item_unseen = 1 AND item_wall = 1 + AND item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1) AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal @@ -328,8 +328,8 @@ class Sse_bs extends Controller { } - $r = q("SELECT count(id) as total FROM item - WHERE uid = %d and item_unseen = 1 AND item_wall = 1 + $r = q("SELECT count(id) as total FROM item + WHERE uid = %d and item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1) $item_normal $sql_extra AND author_xchan != '%s'", @@ -379,7 +379,7 @@ class Sse_bs extends Controller { $item_normal = item_normal(); if ($notifications) { - $items = q("SELECT * FROM item + $items = q("SELECT * FROM item WHERE uid = %d AND created <= '%s' AND item_unseen = 1 @@ -410,7 +410,7 @@ class Sse_bs extends Controller { } - $r = q("SELECT count(id) as total FROM item + $r = q("SELECT count(id) as total FROM item WHERE uid = %d AND item_unseen = 1 AND created > '%s' $item_normal @@ -516,7 +516,7 @@ class Sse_bs extends Controller { $p_str = ids_to_querystr($p, 'parent'); $p_sql = (($p_str) ? "OR parent IN ( $p_str )" : ''); - $r = q("select mid from item + $r = q("select mid from item where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $sql_extra $item_normal", intval(self::$uid), dbesc($forums[$x]['xchan_hash']), @@ -577,7 +577,7 @@ class Sse_bs extends Controller { $item_normal = item_normal(); - $r = q("SELECT * FROM item + $r = q("SELECT * FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d diff --git a/Zotlabs/Module/Zfinger.php b/Zotlabs/Module/Zfinger.php index 533f0a5db..ce7117ad8 100644 --- a/Zotlabs/Module/Zfinger.php +++ b/Zotlabs/Module/Zfinger.php @@ -7,7 +7,7 @@ use Zotlabs\Lib\Libzot; class Zfinger extends \Zotlabs\Web\Controller { function init() { - + require_once('include/zot.php'); require_once('include/crypto.php'); @@ -26,7 +26,7 @@ class Zfinger extends \Zotlabs\Web\Controller { if($chan) { $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],'acct:' . channel_reddress($chan)); + $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'], channel_url($chan)); HTTPSig::set_headers($h); } else { @@ -37,7 +37,7 @@ class Zfinger extends \Zotlabs\Web\Controller { echo $ret; killme(); - + } - + } diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index fde66efcd..fdef35210 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -3,6 +3,7 @@ namespace Zotlabs\Storage; use Sabre\DAV; +use App; /** * @brief Provides a DAV frontend for the webbrowser. @@ -76,49 +77,82 @@ class Browser extends DAV\Browser\Plugin { * @param string $path which should be displayed */ public function generateDirectoryIndex($path) { - // (owner_id = channel_id) is visitor owner of this directory? - $is_owner = ((local_channel() && $this->auth->owner_id == local_channel()) ? true : false); - - if ($this->auth->getTimezone()) - date_default_timezone_set($this->auth->getTimezone()); require_once('include/conversation.php'); require_once('include/text.php'); - if ($this->auth->owner_nick) { - $html = ''; - } - $files = $this->server->getPropertiesForPath($path, array( - '{DAV:}displayname', - '{DAV:}resourcetype', - '{DAV:}getcontenttype', - '{DAV:}getcontentlength', - '{DAV:}getlastmodified', - ), 1); + $nick = $this->auth->owner_nick; + $channel_id = $this->auth->owner_id; + + // Is visitor owner of this directory? + $is_owner = ((local_channel() && $channel_id == local_channel()) ? true : false); + $cat = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); + + if ($this->auth->getTimezone()) { + date_default_timezone_set($this->auth->getTimezone()); + } + $files = $this->server->getPropertiesForPath($path, [], 1); $parent = $this->server->tree->getNodeForPath($path); - $parentpath = array(); - // only show parent if not leaving /cloud/; TODO how to improve this? - if ($path && $path != "cloud") { - list($parentUri) = \Sabre\Uri\split($path); - $fullPath = \Sabre\HTTP\encodePath($this->server->getBaseUri() . $parentUri); + $arr = explode('/', $parent->os_path); + end($arr); + $folder_parent = ((isset($arr[1])) ? prev($arr) : ''); + + $folder_list = attach_folder_select_list($channel_id); + + $siteroot_disabled = get_config('system', 'cloud_disable_siteroot'); + $is_root_folder = (($path === 'cloud/' . $nick) ? true : false); - $parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : ''; - $parentpath['path'] = $fullPath; + $parent_path = ''; + + if ($channel_id && ! $cat && !($siteroot_disabled && $is_root_folder)) { + list($parent_uri) = \Sabre\Uri\split($path); + $parent_path = \Sabre\HTTP\encodePath($this->server->getBaseUri() . $parent_uri); } - $f = array(); + $embedable_video_types = [ + 'video/mp4', + 'video/ogg', + 'video/webm' + ]; + + $embedable_audio_types = [ + 'audio/mpeg', + 'audio/wav', + 'audio/ogg', + 'audio/webm' + ]; + + $f = []; + foreach ($files as $file) { - $ft = array(); + + $ft = []; $type = null; - // This is the current directory, we can skip it - if (rtrim($file['href'], '/') == $path) continue; + $href = rtrim($file['href'], '/'); + + // This is the current directory - skip it + if ($href === $path) + continue; - list(, $name) = \Sabre\Uri\split($file['href']); + $node = $this->server->tree->getNodeForPath($href); + $data = $node->data; + $attach_hash = $data['hash']; + $folder_hash = $node->folder_hash; + + list(, $filename) = \Sabre\Uri\split($href); + + $name = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $filename; + $name = $this->escapeHTML($name); + + $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : ''; + + $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''); if (isset($file[200]['{DAV:}resourcetype'])) { + $type = $file[200]['{DAV:}resourcetype']->getValue(); // resourcetype can have multiple values @@ -128,22 +162,22 @@ class Browser extends DAV\Browser\Plugin { // Some name mapping is preferred switch ($v) { case '{DAV:}collection' : - $type[$k] = t('Collection'); + $type[$k] = 'Collection'; break; case '{DAV:}principal' : - $type[$k] = t('Principal'); + $type[$k] = 'Principal'; break; case '{urn:ietf:params:xml:ns:carddav}addressbook' : - $type[$k] = t('Addressbook'); + $type[$k] = 'Addressbook'; break; case '{urn:ietf:params:xml:ns:caldav}calendar' : - $type[$k] = t('Calendar'); + $type[$k] = 'Calendar'; break; case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' : - $type[$k] = t('Schedule Inbox'); + $type[$k] = 'Schedule Inbox'; break; case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' : - $type[$k] = t('Schedule Outbox'); + $type[$k] = 'Schedule Outbox'; break; case '{http://calendarserver.org/ns/}calendar-proxy-read' : $type[$k] = 'Proxy-Read'; @@ -158,124 +192,173 @@ class Browser extends DAV\Browser\Plugin { // If no resourcetype was found, we attempt to use // the contenttype property - if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { + if (! $type && isset($file[200]['{DAV:}getcontenttype'])) { $type = $file[200]['{DAV:}getcontenttype']; } - if (!$type) $type = t('Unknown'); - $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : ''; - $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''); - - $fullPath = \Sabre\HTTP\encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); - - $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name; - - $displayName = $this->escapeHTML($displayName); - $type = $this->escapeHTML($type); - - - $icon = ''; - - if ($this->enableAssets) { - $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name); - foreach (array_reverse($this->iconMap) as $class=>$iconName) { - if ($node instanceof $class) { - $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>'; - break; - } - } - } - - $parentHash = ''; - $owner = $this->auth->owner_id; - $splitPath = explode('/', $fullPath); - if (count($splitPath) > 3) { - for ($i = 3; $i < count($splitPath); $i++) { - $attachName = urldecode($splitPath[$i]); - $attachHash = $this->findAttachHash($owner, $parentHash, $attachName); - $parentHash = $attachHash; - } + if (! $type) { + $type = $data['filetype']; } + $type = $this->escapeHTML($type); - // generate preview icons for tile view. + // generate preview icons for tile view. // Currently we only handle images, but this could potentially be extended with plugins - // to provide document and video thumbnails. SVG, PDF and office documents have some + // to provide document and video thumbnails. SVG, PDF and office documents have some // security concerns and should only be allowed on single-user sites with tightly controlled - // upload access. system.thumbnail_security should be set to 1 if you want to include these - // types + // upload access. system.thumbnail_security should be set to 1 if you want to include these + // types $is_creator = false; $photo_icon = ''; $preview_style = intval(get_config('system','thumbnail_security',0)); - $r = q("select content, creator from attach where hash = '%s' and uid = %d limit 1", - dbesc($attachHash), - intval($owner) - ); - - if($r) { - $is_creator = (($r[0]['creator'] === get_observer_hash()) ? true : false); - if(file_exists(dbunescbin($r[0]['content']) . '.thumb')) { - $photo_icon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents(dbunescbin($r[0]['content']) . '.thumb')); -// logger('found thumb: ' . $photo_icon); - } - } + $is_creator = (($data['creator'] === get_observer_hash()) ? true : false); - if(strpos($type,'image/') === 0 && $attachHash) { - $r = q("select resource_id, imgscale from photo where resource_id = '%s' and imgscale in ( %d, %d ) order by imgscale asc limit 1", - dbesc($attachHash), + if(strpos($type,'image/') === 0 && $attach_hash) { + $p = q("select resource_id, imgscale from photo where resource_id = '%s' and imgscale in ( %d, %d ) order by imgscale asc limit 1", + dbesc($attach_hash), intval(PHOTO_RES_320), intval(PHOTO_RES_PROFILE_80) ); - if($r) { - $photo_icon = 'photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale']; + if($p) { + $photo_icon = 'photo/' . $p[0]['resource_id'] . '-' . $p[0]['imgscale']; } if($type === 'image/svg+xml' && $preview_style > 0) { - $photo_icon = $fullPath; + $photo_icon = $href; } } - $g = [ 'resource_id' => $attachHash, 'thumbnail' => $photo_icon, 'security' => $preview_style ]; + $g = [ 'resource_id' => $attach_hash, 'thumbnail' => $photo_icon, 'security' => $preview_style ]; call_hooks('file_thumbnail', $g); $photo_icon = $g['thumbnail']; + $lockstate = (($data['allow_cid'] || $data['allow_gid'] || $data['deny_cid'] || $data['deny_gid']) ? 'lock' : 'unlock'); + $id = $data['id']; - $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"fa fa-arrow-circle-o-down\"></i></a>"; + if($id) { + $terms = q("select * from term where oid = %d AND otype = %d", + intval($id), + intval(TERM_OBJ_FILE) + ); + + $categories = []; + $terms_str = ''; + if($terms) { + foreach($terms as $t) { + $term = htmlspecialchars($t['term'],ENT_COMPAT,'UTF-8',false) ; + if(! trim($term)) + continue; + $categories[] = array('term' => $term, 'url' => $t['url']); + if ($terms_str) + $terms_str .= ','; + $terms_str .= $term; + } + $ft['terms'] = replace_macros(get_markup_template('item_categories.tpl'),array( + '$categories' => $categories + )); + } + } // put the array for this file together - $ft['attachId'] = $this->findAttachIdByHash($attachHash); - $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->owner_nick; + $ft['attach_id'] = $id; $ft['icon'] = $icon; $ft['photo_icon'] = $photo_icon; - $ft['attachIcon'] = (($size) ? $attachIcon : ''); - // @todo Should this be an item value, not a global one? - $ft['is_owner'] = $is_owner; $ft['is_creator'] = $is_creator; - $ft['fullPath'] = $fullPath; - $ft['displayName'] = $displayName; + $ft['rel_path'] = (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href); + $ft['full_path'] = z_root() . (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href); + $ft['name'] = $name; $ft['type'] = $type; $ft['size'] = $size; - $ft['sizeFormatted'] = userReadableSize($size); - $ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : ''); - $ft['iconFromType'] = getIconFromType($type); + $ft['collection'] = (($type === 'Collection') ? true : false); + $ft['size_formatted'] = userReadableSize($size); + $ft['last_modified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : ''); + $ft['icon_from_type'] = getIconFromType($type); + + $ft['allow_cid'] = acl2json($data['allow_cid']); + $ft['allow_gid'] = acl2json($data['allow_gid']); + $ft['deny_cid'] = acl2json($data['deny_cid']); + $ft['deny_gid'] = acl2json($data['deny_gid']); + + $ft['raw_allow_cid'] = $data['allow_cid']; + $ft['raw_allow_gid'] = $data['allow_gid']; + $ft['raw_deny_cid'] = $data['deny_cid']; + $ft['raw_deny_gid'] = $data['deny_gid']; + + $ft['lockstate'] = $lockstate; + $ft['resource'] = $data['hash']; + $ft['folder'] = $data['folder']; + $ft['revision'] = $data['revision']; + $ft['newfilename'] = ['newfilename_' . $id, t('Change filename to'), $name]; + $ft['categories'] = ['categories_' . $id, t('Categories'), $terms_str]; + + // create a copy of the list which we can alter for the current resource + $folders = $folder_list; + + if($data['is_dir']) { + + $rm_path = $folders[$folder_hash]; + // can not copy a folder into itself or own child folders + foreach($folders as $k => $v) { + if(strpos($v, $rm_path) === 0) + unset($folders[$k]); + } + + } + + $ft['newfolder'] = ['newfolder_' . $id, t('Select a target location'), $data['folder'], '', $folders]; + $ft['copy'] = ['copy_' . $id, t('Copy to target location'), 0, '', [t('No'), t('Yes')]]; + $ft['recurse'] = ['recurse_' . $id, t('Set permissions for all files and sub folders'), 0, '', [t('No'), t('Yes')]]; + $ft['notify'] = ['notify_edit_' . $id, t('Notify your contacts about this file'), 0, '', [t('No'), t('Yes')]]; + + $embed_bbcode = ''; + $link_bbcode = ''; + $attach_bbcode = ''; + + if($data['is_photo']) { + $embed_bbcode = '[zmg]' . $ft['full_path'] . '[/zmg]'; + } + elseif(strpos($type, 'video') === 0 && in_array($type, $embedable_video_types)) { + $embed_bbcode = '[zvideo]' . $ft['full_path'] . '[/zvideo]'; + } + elseif(strpos($type, 'audio') === 0 && in_array($type, $embedable_audio_types)) { + $embed_bbcode = '[zaudio]' . $ft['full_path'] . '[/zaudio]'; + } + $ft['embed_bbcode'] = $embed_bbcode; + + if(! $data['is_dir']) { + $attach_bbcode = '[attachment]' . $data['hash'] . ',' . $data['revision'] . '[/attachment]'; + } + $ft['attach_bbcode'] = $attach_bbcode; + + $link_bbcode = '[zrl=' . $ft['full_path'] . ']' . $ft['name'] . '[/zrl]'; + $ft['link_bbcode'] = $link_bbcode; $f[] = $ft; } - $output = ''; if ($this->enablePost) { - $this->server->emit('onHTMLActionsPanel', array($parent, &$output, $path)); + $this->server->emit('onHTMLActionsPanel', [$parent, &$output, $path]); } $deftiles = (($is_owner) ? 0 : 1); + $tiles = ((array_key_exists('cloud_tiles',$_SESSION)) ? intval($_SESSION['cloud_tiles']) : $deftiles); $_SESSION['cloud_tiles'] = $tiles; - - $html .= replace_macros(get_markup_template('cloud.tpl'), array( - '$header' => t('Files') . ": " . $this->escapeHTML($path) . "/", + + $header = (($cat) ? t('File category') . ": " . $this->escapeHTML($cat) : t('Files')); + + $channel = channelx_by_n($channel_id); + if($channel) { + $acl = new \Zotlabs\Access\AccessList($channel); + $channel_acl = $acl->get(); + $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); + } + + $html = replace_macros(get_markup_template('cloud.tpl'), array( + '$header' => $header, '$total' => t('Total'), '$actionspanel' => $output, '$shared' => t('Shared'), @@ -283,9 +366,12 @@ class Browser extends DAV\Browser\Plugin { '$upload' => t('Add Files'), '$is_owner' => $is_owner, '$is_admin' => is_site_admin(), - '$admin_delete' => t('Admin Delete'), - '$parentpath' => $parentpath, - '$cpath' => bin2hex(\App::$query_string), + '$admin_delete_label' => t('Admin Delete'), + '$parentpath' => $parent_path, + '$folder_parent' => $folder_parent, + '$folder' => $parent->folder_hash, + '$is_root_folder' => $is_root_folder, + '$cpath' => bin2hex(App::$query_string), '$tiles' => intval($_SESSION['cloud_tiles']), '$entries' => $f, '$name' => t('Name'), @@ -293,17 +379,43 @@ class Browser extends DAV\Browser\Plugin { '$size' => t('Size'), '$lastmod' => t('Last Modified'), '$parent' => t('parent'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$nick' => $this->auth->getCurrentUser() + '$submit_label' => t('Submit'), + '$cancel_label' => t('Cancel'), + '$delete_label' => t('Delete'), + '$channel_id' => $channel_id, + '$cpdesc' => t('Copy/paste this code to attach file to a post'), + '$cpldesc' => t('Copy/paste this URL to link file from a web page'), + '$categories' => ['categories', t('Categories')], + '$recurse' => ['recurse', t('Set permissions for all files and sub folders'), 0, '', [t('No'), t('Yes')]], + '$newfolder' => ['newfolder', t('Select a target location'), $parent->folder_hash, '', $folder_list], + '$copy' => ['copy', t('Copy to target location'), 0, '', [t('No'), t('Yes')]], + '$return_path' => $path, + '$lockstate' => $lockstate, + '$allow_cid' => acl2json($channel_acl['allow_cid']), + '$allow_gid' => acl2json($channel_acl['allow_gid']), + '$deny_cid' => acl2json($channel_acl['deny_cid']), + '$deny_gid' => acl2json($channel_acl['deny_gid']), + '$is_owner' => $is_owner, + '$select_all_label' => t('Select All'), + '$bulk_actions_label' => t('Bulk Actions'), + '$adjust_permissions_label' => t('Adjust Permissions'), + '$move_copy_label' => t('Move or Copy'), + '$categories_label' => t('Categories'), + '$download_label' => t('Download'), + '$info_label' => t('Info'), + '$rename_label' => t('Rename'), + '$post_label' => t('Post'), + '$attach_bbcode_label' => t('Attachment BBcode'), + '$embed_bbcode_label' => t('Embed BBcode'), + '$link_bbcode_label' => t('Link BBcode'), + '$close_label' => t('Close') )); - $a = false; nav_set_selected('Files'); - \App::$page['content'] = $html; + App::$page['content'] = $html; load_pdl(); $current_theme = \Zotlabs\Render\Theme::current(); @@ -335,6 +447,7 @@ class Browser extends DAV\Browser\Plugin { // SimpleCollection, we won't need to show the panel either. if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') return; + require_once('include/acl_selectors.php'); $aclselect = null; @@ -387,9 +500,38 @@ class Browser extends DAV\Browser\Plugin { $special = 'cloud/' . $this->auth->owner_nick; $count = strlen($special); + + if(strpos($path,$special) === 0) - $path = trim(substr($path,$count),'/'); + $display_path = trim(substr($path,$count),'/'); + + $breadcrumbs_html = ''; + + if($display_path && ! $_REQUEST['cat'] && ! $_SESSION['cloud_tiles']){ + $breadcrumbs = []; + $folders = explode('/', $display_path); + $folder_hashes = explode('/', $node->os_path); + $breadcrumb_path = z_root() . '/cloud/' . $this->auth->owner_nick; + + $breadcrumbs[] = [ + 'name' => $this->auth->owner_nick, + 'hash' => '', + 'path' => $breadcrumb_path + ]; + + foreach($folders as $i => $name) { + $breadcrumb_path .= '/' . $name; + $breadcrumbs[] = [ + 'name' => $name, + 'hash' => $folder_hashes[$i], + 'path' => $breadcrumb_path + ]; + } + $breadcrumbs_html = replace_macros(get_markup_template('breadcrumb.tpl'), array( + '$breadcrumbs' => $breadcrumbs + )); + } $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( '$folder_header' => t('Create new folder'), @@ -404,11 +546,12 @@ class Browser extends DAV\Browser\Plugin { '$deny_cid' => acl2json($channel_acl['deny_cid']), '$deny_gid' => acl2json($channel_acl['deny_gid']), '$lockstate' => $lockstate, - '$return_url' => \App::$cmd, - '$path' => $path, - '$folder' => find_folder_hash_by_path($this->auth->owner_id, $path), + '$return_url' => $path, + '$folder' => $node->folder_hash, '$dragdroptext' => t('Drop files here to immediately upload'), - '$notify' => ['notify', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]] + '$notify' => ['notify', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]], + '$breadcrumbs_html' => $breadcrumbs_html, + '$drop_area_label' => t('You can select files via the upload button or drop them right here or into an existing folder.') )); } @@ -453,6 +596,21 @@ class Browser extends DAV\Browser\Plugin { return $hash; } + protected function findAttachHashFlat($owner, $attachName) { + $r = q("SELECT hash FROM attach WHERE uid = %d AND filename = '%s' ORDER BY edited DESC LIMIT 1", + intval($owner), + dbesc($attachName) + ); + $hash = ''; + if ($r) { + foreach ($r as $rr) { + $hash = $rr['hash']; + } + } + + return $hash; + } + /** * @brief Returns an attachment's id for a given hash. * diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index 1231dfa25..c56ffcbbb 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -25,7 +25,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo * @var string $red_path */ private $red_path; - private $folder_hash; + public $folder_hash; + public $data; + + /** * @brief The full path as seen in the browser. * /cloud + $red_path @@ -41,7 +44,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo * * @var string $os_path */ - private $os_path = ''; + public $os_path = ''; /** * @brief Sets up the directory node, expects a full path. @@ -49,7 +52,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo * @param string $ext_path a full path * @param BasicAuth &$auth_plugin */ - public function __construct($ext_path, &$auth_plugin) { + public function __construct($ext_path, $data, &$auth_plugin) { // $ext_path = urldecode($ext_path); logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; @@ -61,6 +64,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo } $this->auth = $auth_plugin; $this->folder_hash = ''; + $this->data = $data; + $this->getDir(); if($this->auth->browser) { @@ -116,7 +121,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $modulename = \App::$module; if ($this->red_path === '/' && $name === $modulename) { - return new Directory('/' . $modulename, $this->auth); + return new Directory('/' . $modulename, [], $this->auth); } $x = $this->FileData($this->ext_path . '/' . $name, $this->auth); @@ -269,8 +274,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo dbesc($f), dbesc(datetime_convert()), dbesc(datetime_convert()), - '', - '', + '', + '', dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), @@ -293,7 +298,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo else { $size = file_put_contents($f, $data); } - + // delete attach entry if file_put_contents() failed if ($size === false) { logger('file_put_contents() failed to ' . $f); @@ -374,7 +379,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $args = array( 'resource_id' => $hash, 'album' => $album, 'os_syspath' => $f, 'os_path' => $xpath['os_path'], 'display_path' => $xpath['path'], 'filename' => $name, 'getimagesize' => $gis, 'directory' => $direct); $p = photo_upload($c[0], \App::get_observer(), $args); } - + \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $hash ]); $sync = attach_export_data($c[0], $hash); @@ -402,13 +407,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo if ($r) { - // When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the - // folder already exists. + // When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the + // folder already exists. require_once('include/attach.php'); $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); if($result['success']) { + $sync = attach_export_data($r[0],$result['data']['hash']); logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); @@ -476,15 +482,16 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) { - if(! $this->auth->owner_id) { - return false; - } + $channel_id = $this->auth->owner_id; + // Files have $sourceNode->data['hash'] set. For directories rely on $sourceNode->folder_hash. + $resource_id = ((isset($sourceNode->data['hash'])) ? $sourceNode->data['hash'] : $sourceNode->folder_hash); + $new_folder_hash = $this->folder_hash; - if(! ($sourceNode->data && $sourceNode->data->hash)) { + if(!$channel_id && !$resource_id) return false; - } - return attach_move($this->auth->owner_id, $sourceNode->data->hash, $this->folder_hash); + $ret = attach_move($channel_id, $resource_id, $new_folder_hash); + return $ret['success']; } @@ -515,6 +522,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $file = trim($file, '/'); $path_arr = explode('/', $file); + if (! $path_arr) return; @@ -609,6 +617,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $file = trim($file, '/'); $path_arr = explode('/', $file); + $cat = $_REQUEST['cat']; + + if (! $path_arr) return null; @@ -679,7 +690,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $_SESSION['cloud_sort'] = 'name'; switch($_SESSION['cloud_sort']) { - case 'size': + case 'size': $suffix = ' order by is_dir desc, filesize asc '; break; // The following provides inconsistent results for directories because we re-calculate the date for directories based on the most recent change @@ -692,17 +703,34 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo break; } - $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", - dbesc($folder), - intval($channel_id) - ); + if ($cat) { + $r = q("select $prefix attach.id, attach.uid, attach.hash, attach.filename, attach.is_photo, + attach.filetype, attach.filesize, attach.revision, attach.folder, attach.creator, + attach.flags, attach.is_dir, attach.created, attach.edited, attach.display_path, + attach.allow_cid, attach.allow_gid, attach.deny_cid, attach.deny_gid from attach + left join term on attach.id = term.oid + where term.term = '%s' and attach.uid = %d $perms $suffix", + dbesc($cat), + intval($channel_id) + ); + } + else { + $r = q("select $prefix attach.id, attach.uid, attach.hash, attach.filename, attach.is_photo, + attach.filetype, attach.filesize, attach.revision, attach.folder, attach.creator, + attach.flags, attach.is_dir, attach.created, attach.edited, attach.display_path, + attach.allow_cid, attach.allow_gid, attach.deny_cid, attach.deny_gid from attach + where folder = '%s' and uid = %d $perms $suffix", + dbesc($folder), + intval($channel_id) + ); + } foreach ($r as $rr) { if(\App::$module === 'cloud' && (strpos($rr['filename'],'.') === 0) && (! get_pconfig($channel_id,'system','show_dot_files')) ) continue; // @FIXME I don't think we use revisions currently in attach structures. - // In case we see any in the wild provide a unique filename. This + // In case we see any in the wild provide a unique filename. This // name may or may not be accessible if($rr['revision']) @@ -710,13 +738,12 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); if (intval($rr['is_dir'])) { - $ret[] = new Directory($path . '/' . $rr['filename'], $auth); + $ret[] = new Directory($path . '/' . $rr['filename'], $rr, $auth); } else { $ret[] = new File($path . '/' . $rr['filename'], $rr, $auth); } } - return $ret; } @@ -738,15 +765,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo return $ret; } - $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0", + $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0 and profile.is_default = 1", intval(PAGE_HIDDEN) ); - if ($r) { foreach ($r as $rr) { - if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) { + if ((perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish'])|| $rr['channel_id'] == $this->auth->channel_id) { logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); - $ret[] = new Directory($rr['channel_address'], $auth); + $ret[] = new Directory($rr['channel_address'], [], $auth); } } } @@ -778,7 +804,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo } if ((! $file) || ($file === '/')) { - return new Directory('/', $auth); + return new Directory('/', [], $auth); } $file = trim($file, '/'); @@ -848,7 +874,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo if ($test) return true; // final component was a directory. - return new Directory($file, $auth); + return new Directory($file, [], $auth); } if ($errors) { @@ -867,7 +893,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo return true; if (intval($r[0]['is_dir'])) { - return new Directory($path . '/' . $r[0]['filename'], $auth); + return new Directory($path . '/' . $r[0]['filename'], [], $auth); } else { return new File($path . '/' . $r[0]['filename'], $r[0], $auth); @@ -888,7 +914,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $used = 0; $limit = 0; $free = 0; - + if ($this->auth->owner_id) { $channel = channelx_by_n($this->auth->owner_id); if($channel) { @@ -919,5 +945,4 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo return [ (int) $used, (int) $free ]; } - } diff --git a/Zotlabs/Update/_1239.php b/Zotlabs/Update/_1239.php new file mode 100644 index 000000000..ed8de30bb --- /dev/null +++ b/Zotlabs/Update/_1239.php @@ -0,0 +1,27 @@ +<?php + +namespace Zotlabs\Update; + +class _1239 { + + function run() { + + dbq("START TRANSACTION"); + + // remove broken activitypub hubloc entries + $r = dbq("DELETE FROM hubloc WHERE hubloc_network = 'activitypub' and hubloc_callback = ''"); + + // remove broken hubloc entries from friendica + $r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''"); + + if($r && $r1) { + dbq("COMMIT"); + return UPDATE_SUCCESS; + } + + dbq("ROLLBACK"); + return UPDATE_FAILED; + + } + +} diff --git a/Zotlabs/Update/_1240.php b/Zotlabs/Update/_1240.php new file mode 100644 index 000000000..d007c9fa9 --- /dev/null +++ b/Zotlabs/Update/_1240.php @@ -0,0 +1,34 @@ +<?php + +namespace Zotlabs\Update; + +class _1240 { + + function run() { + + q("START TRANSACTION"); + + // remove broken xchan entries + $r0 = dbq("DELETE FROM xchan WHERE xchan_hash = ''"); + + // remove broken hubloc entries + $r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''"); + + // fix legacy zot hubloc_id_url + $r2 = dbq("UPDATE hubloc + SET hubloc_id_url = CONCAT(hubloc_url, '/channel/', SUBSTRING(hubloc_addr FROM 1 FOR POSITION('@' IN hubloc_addr) -1)) + WHERE hubloc_network = 'zot' + AND hubloc_id_url = ''" + ); + + if($r0 && $r1 && $r2) { + q("COMMIT"); + return UPDATE_SUCCESS; + } + + q("ROLLBACK"); + return UPDATE_FAILED; + + } + +} diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index 42426afb1..1f6979191 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -151,13 +151,13 @@ class HTTPSig { $result['signer'] = $sig_block['keyId']; - $key = self::get_key($key,$keytype,$result['signer']); + $cached_key = self::get_key($key,$keytype,$result['signer']); - if(! ($key && $key['public_key'])) { + if(! ($cached_key && $cached_key['public_key'])) { return $result; } - $x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm); + $x = rsa_verify($signed_data,$sig_block['signature'],$cached_key['public_key'],$algorithm); logger('verified: ' . $x, LOGGER_DEBUG); @@ -166,15 +166,15 @@ class HTTPSig { // try again, ignoring the local actor (xchan) cache and refetching the key // from its source - $fkey = self::get_key($key,$keytype,$result['signer'],true); + $fetched_key = self::get_key($key,$keytype,$result['signer'],true); - if ($fkey && $fkey['public_key']) { - $y = rsa_verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm); + if ($fetched_key && $fetched_key['public_key']) { + $y = rsa_verify($signed_data,$sig_block['signature'],$fetched_key['public_key'],$algorithm); logger('verified: (cache reload) ' . $x, LOGGER_DEBUG); } if (! $y) { - logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key')); + logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fetched_key['public_key']) ? '' : ' no key')); $sig_block['signature'] = base64_encode($sig_block['signature']); logger('affected sigblock: ' . print_r($sig_block,true)); logger('headers: ' . print_r($headers,true)); @@ -184,6 +184,8 @@ class HTTPSig { } + $key = (($fetched_key) ? $fetched_key : $cached_key); + $result['portable_id'] = $key['portable_id']; $result['header_valid'] = true; @@ -212,6 +214,9 @@ class HTTPSig { static function get_key($key,$keytype,$id) { + if(is_array($key)) + btlogger('key is array: ' . print_r($key,true)); + if($key) { if(function_exists($key)) { return $key($id); @@ -241,7 +246,7 @@ class HTTPSig { function convertKey($key) { - if(strstr($key,'RSA ')) { + if(strstr($key,'RSA ')) { return rsatopem($key); } elseif(substr($key,0,5) === 'data:') { @@ -450,7 +455,7 @@ class HTTPSig { foreach($headers as $h) { header($h); } - } + } } diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index 82c37cd0c..94ad469da 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -21,7 +21,9 @@ class Categories { if(($articles) && (! Apps::system_app_installed(App::$profile['profile_uid'],'Articles'))) return ''; - if((! App::$profile['profile_uid']) + $files = ((array_key_exists('files',$arr) && $arr['files']) ? true : false); + + if((! App::$profile['profile_uid']) || (! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),(($cards || $articles) ? 'view_pages' : 'view_stream')))) { return ''; } @@ -29,12 +31,14 @@ class Categories { $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : ''); $srchurl = (($cards) ? App::$argv[0] . '/' . App::$argv[1] : App::$query_string); $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); - $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); + $srchurl = str_replace(array('?f=','&f=', '/?'),array('', '', ''),$srchurl); if($cards) return cardcategories_widget($srchurl, $cat); elseif($articles) return articlecategories_widget($srchurl, $cat); + elseif($files) + return filecategories_widget($srchurl, $cat); else return categories_widget($srchurl, $cat); diff --git a/Zotlabs/Widget/Dirsort.php b/Zotlabs/Widget/Dirsort.php index e75a00e50..2fb38b7df 100644 --- a/Zotlabs/Widget/Dirsort.php +++ b/Zotlabs/Widget/Dirsort.php @@ -2,10 +2,10 @@ namespace Zotlabs\Widget; -require_once('include/dir_fns.php'); +use Zotlabs\Lib\Libzotdir; class Dirsort { function widget($arr) { - return dir_sort_links(); + return Libzotdir::dir_sort_links(); } } diff --git a/Zotlabs/Zot6/Finger.php b/Zotlabs/Zot6/Finger.php index 22ce4685d..cec3f98ab 100644 --- a/Zotlabs/Zot6/Finger.php +++ b/Zotlabs/Zot6/Finger.php @@ -88,7 +88,7 @@ class Finger { $headers = []; $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname(); $headers['X-Zot-Nonce'] = random_string(); - $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel)); + $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel)); $retries = 0; @@ -100,7 +100,7 @@ class Finger { $result = z_post_url('http://' . $host . $rhs,$postvars, $retries, [ 'headers' => $xhead ]); } } - } + } else { $rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token; diff --git a/Zotlabs/Zot6/Zot6Handler.php b/Zotlabs/Zot6/Zot6Handler.php index d717b147b..bd321c4b1 100644 --- a/Zotlabs/Zot6/Zot6Handler.php +++ b/Zotlabs/Zot6/Zot6Handler.php @@ -226,18 +226,18 @@ class Zot6Handler implements IHandler { if ($recipients) { // basically this means "unfriend" foreach ($recipients as $recip) { - $r = q("select channel.*,xchan.* from channel + $channel = q("select channel.*,xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", dbesc($recip) ); - if ($r) { - $r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1", - intval($r[0]['channel_id']), + if ($channel) { + $abook = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval($channel[0]['channel_id']), dbesc($sender) ); - if ($r) { - contact_remove($r[0]['channel_id'],$r[0]['abook_id']); + if ($abook) { + contact_remove($channel[0]['channel_id'],$abook[0]['abook_id']); } } } |