diff options
67 files changed, 1147 insertions, 350 deletions
@@ -1,3 +1,8 @@ +Hubzilla 7.8.7 (2022-12-03) + - Fix regression when adding feed contacts + - Fix regression new channel calendar event not created + + Hubzilla 7.8.6 (2022-11-14) - Fix typo in boot.php diff --git a/Zotlabs/Daemon/Addon.php b/Zotlabs/Daemon/Addon.php index c6778750d..126e11cf6 100644 --- a/Zotlabs/Daemon/Addon.php +++ b/Zotlabs/Daemon/Addon.php @@ -7,6 +7,7 @@ class Addon { static public function run($argc, $argv) { call_hooks('daemon_addon', $argv); + return; } diff --git a/Zotlabs/Daemon/Cache_embeds.php b/Zotlabs/Daemon/Cache_embeds.php index 9e5b8d2bb..d5adfcc59 100644 --- a/Zotlabs/Daemon/Cache_embeds.php +++ b/Zotlabs/Daemon/Cache_embeds.php @@ -19,8 +19,10 @@ class Cache_embeds { $item = $c[0]; // bbcode conversion by default processes embeds that aren't already cached. - // Ignore the returned html output. + // Ignore the returned html output. bbcode($item['body']); + + return; } } diff --git a/Zotlabs/Daemon/Cache_query.php b/Zotlabs/Daemon/Cache_query.php index 5f92ae6d0..cd9597e9a 100644 --- a/Zotlabs/Daemon/Cache_query.php +++ b/Zotlabs/Daemon/Cache_query.php @@ -24,7 +24,7 @@ class Cache_query { array_shift($argv); array_shift($argv); - + $arr = json_decode(base64_decode($argv[0]), true); $r = call_user_func_array('q', $arr); @@ -32,5 +32,7 @@ class Cache_query { Cache::set($key, serialize($r)); del_config('procid', $key); + + return; } } diff --git a/Zotlabs/Daemon/Cli_suggest.php b/Zotlabs/Daemon/Cli_suggest.php index 5dced462d..028228cb0 100644 --- a/Zotlabs/Daemon/Cli_suggest.php +++ b/Zotlabs/Daemon/Cli_suggest.php @@ -9,6 +9,7 @@ class Cli_suggest { static public function run($argc,$argv) { update_suggestions(); + return; } } diff --git a/Zotlabs/Daemon/Convo.php b/Zotlabs/Daemon/Convo.php index 940216b2c..d1a7e4f4d 100644 --- a/Zotlabs/Daemon/Convo.php +++ b/Zotlabs/Daemon/Convo.php @@ -30,6 +30,7 @@ class Convo { intval($channel_id), dbesc($contact_hash) ); + if (!$r) { return; } @@ -40,19 +41,25 @@ class Convo { $messages = $obj->get(); - if ($messages) { - foreach ($messages as $message) { - if (is_string($message)) { - $message = Activity::fetch($message, $channel); - } - // set client flag because comments will probably just be objects and not full blown activities - // and that lets us use implied_create - $AS = new ActivityStreams($message); - if ($AS->is_valid() && is_array($AS->obj)) { - $item = Activity::decode_note($AS); - Activity::store($channel, $contact['abook_xchan'], $AS, $item); - } + if (!$messages) { + return; + } + + foreach ($messages as $message) { + if (is_string($message)) { + $message = Activity::fetch($message, $channel); + } + + // set client flag because comments will probably just be objects and not full blown activities + // and that lets us use implied_create + $AS = new ActivityStreams($message); + if ($AS->is_valid() && is_array($AS->obj)) { + $item = Activity::decode_note($AS); + Activity::store($channel, $contact['abook_xchan'], $AS, $item); } } + + return; + } } diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php index 6629491de..640f06102 100644 --- a/Zotlabs/Daemon/Cron.php +++ b/Zotlabs/Daemon/Cron.php @@ -19,6 +19,7 @@ class Cron { } } +/* // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. $lockfile = 'store/[data]/cron'; if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600)) @@ -30,6 +31,7 @@ class Cron { // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. $x = ''; file_put_contents($lockfile, $x); +*/ logger('cron: start'); @@ -50,7 +52,7 @@ class Cron { require_once('include/account.php'); remove_expired_registrations(); - $interval = get_config('system', 'delivery_interval', 3); + $interval = get_config('queueworker', 'queue_interval', 500000); // expire any expired items @@ -65,8 +67,10 @@ class Cron { if ($rr['item_wall']) { // The notifier isn't normally invoked unless item_drop is interactive. Master::Summon(['Notifier', 'drop', $rr['id']]); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + + if ($interval) { + usleep($interval); + } } } } @@ -96,8 +100,10 @@ class Cron { if ($r) { foreach ($r as $rr) { Master::Summon(array('Directory', $rr['channel_id'], 'force')); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + + if ($interval) { + usleep($interval); + } } } @@ -151,8 +157,10 @@ class Cron { ); } Master::Summon(array('Notifier', 'wall-new', $rr['id'])); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + + if ($interval) { + usleep($interval); + } } } } @@ -203,10 +211,10 @@ class Cron { } - // pull in some public posts + // pull in some public posts if allowed - $disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false; - if (!$disable_discover_tab) + $disable_externals = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false || get_config('system', 'site_firehose'); + if (!$disable_externals) Master::Summon(['Externals']); $restart = false; @@ -228,7 +236,7 @@ class Cron { set_config('system', 'lastcron', datetime_convert()); //All done - clear the lockfile - @unlink($lockfile); + //@unlink($lockfile); return; } diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index 71d3bc9ef..6d62836c7 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -119,5 +119,7 @@ class Cron_daily { /** * End Cron Daily */ + + return; } } diff --git a/Zotlabs/Daemon/Cron_weekly.php b/Zotlabs/Daemon/Cron_weekly.php index 407aa40ef..75fb94700 100644 --- a/Zotlabs/Daemon/Cron_weekly.php +++ b/Zotlabs/Daemon/Cron_weekly.php @@ -22,12 +22,12 @@ class Cron_weekly { mark_orphan_hubsxchans(); - // Find channels that were removed in the last three weeks, but + // Find channels that were removed in the last three weeks, but // haven't been finally cleaned up. These should be older than 10 - // days to ensure that "purgeall" messages have gone out or bounced - // or timed out. + // days to ensure that "purgeall" messages have gone out or bounced + // or timed out. - $r = q("select channel_id from channel where channel_removed = 1 and + $r = q("select channel_id from channel where channel_removed = 1 and channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('21 DAY'), db_utcnow(), db_quoteinterval('10 DAY') @@ -59,5 +59,6 @@ class Cron_weekly { * End Cron Weekly */ + return; } -}
\ No newline at end of file +} diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php index 400ef697b..2d80dc093 100644 --- a/Zotlabs/Daemon/Deliver.php +++ b/Zotlabs/Daemon/Deliver.php @@ -28,6 +28,8 @@ class Deliver { } + return; + } } diff --git a/Zotlabs/Daemon/Deliver_hooks.php b/Zotlabs/Daemon/Deliver_hooks.php index 4d3ce4e1d..1e478db1e 100644 --- a/Zotlabs/Daemon/Deliver_hooks.php +++ b/Zotlabs/Daemon/Deliver_hooks.php @@ -12,8 +12,12 @@ class Deliver_hooks { $r = q("select * from item where id = '%d'", intval($argv[1]) ); - if ($r) + + if ($r) { call_hooks('notifier_normal', $r[0]); + } + + return; } } diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php index 3996b8079..19adf8273 100644 --- a/Zotlabs/Daemon/Directory.php +++ b/Zotlabs/Daemon/Directory.php @@ -97,5 +97,7 @@ class Directory { if ($pushall) { Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); } + + return; } } diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php index 99fe68b6f..5d9f14b28 100644 --- a/Zotlabs/Daemon/Expire.php +++ b/Zotlabs/Daemon/Expire.php @@ -103,5 +103,7 @@ class Expire { } del_config('procid', 'expire'); + + return; } } diff --git a/Zotlabs/Daemon/Externals.php b/Zotlabs/Daemon/Externals.php index 91fa09044..2c7c7c172 100644 --- a/Zotlabs/Daemon/Externals.php +++ b/Zotlabs/Daemon/Externals.php @@ -143,7 +143,7 @@ class Externals { $AS = new ActivityStreams($message); if ($AS->is_valid() && is_array($AS->obj)) { $item = Activity::decode_note($AS); - Activity::store($importer, $contact['abook_xchan'], $AS, $item); + Activity::store($importer, $contact['hubloc_hash'], $AS, $item); $total++; } } diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php index 9e818e2b3..c5a81e50c 100644 --- a/Zotlabs/Daemon/Importdoc.php +++ b/Zotlabs/Daemon/Importdoc.php @@ -11,6 +11,8 @@ class Importdoc { self::update_docs_dir('doc/*'); + return; + } static public function update_docs_dir($s) { diff --git a/Zotlabs/Daemon/Master.php b/Zotlabs/Daemon/Master.php index 6fa656be5..c9ed91aaa 100644 --- a/Zotlabs/Daemon/Master.php +++ b/Zotlabs/Daemon/Master.php @@ -2,6 +2,8 @@ namespace Zotlabs\Daemon; +use Zotlabs\Lib\QueueWorker; + if (array_search(__file__, get_included_files()) === 0) { require_once('include/cli_startup.php'); array_shift($argv); @@ -9,6 +11,7 @@ if (array_search(__file__, get_included_files()) === 0) { if ($argc) Master::Release($argc, $argv); + return; } @@ -16,6 +19,10 @@ if (array_search(__file__, get_included_files()) === 0) { class Master { static public function Summon($arr) { + + QueueWorker::Summon($arr); + return; +/* $hookinfo = [ 'argv' => $arr ]; @@ -32,11 +39,15 @@ class Master { $phpbin = get_config('system', 'phpbin', 'php'); proc_run($phpbin, 'Zotlabs/Daemon/Master.php', $arr); +*/ } static public function Release($argc, $argv) { cli_startup(); + QueueWorker::Release($argv); + return; +/* $hookinfo = [ 'argv' => $argv ]; @@ -54,5 +65,6 @@ class Master { logger('Master: release: ' . json_encode($argv), LOGGER_ALL, LOG_DEBUG); $cls = '\\Zotlabs\\Daemon\\' . $argv[0]; $cls::run($argc, $argv); +*/ } } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index bfccb4099..f51dfab28 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -509,6 +509,7 @@ class Notifier { // 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 + /* sys channel is now added in collect recipients if (!self::$private) { $found_localhost = false; if ($hubs) { @@ -529,6 +530,7 @@ class Notifier { } } } + */ if (!$hubs) { logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE); diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php index 63c498f17..0fdc3da16 100644 --- a/Zotlabs/Daemon/Poller.php +++ b/Zotlabs/Daemon/Poller.php @@ -17,9 +17,12 @@ class Poller { } } - $interval = intval(get_config('system', 'poll_interval')); - if (!$interval) + $interval = get_config('queueworker', 'queue_interval', 500000); + +/* + if (!$interval) { $interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval'))); + } // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. $lockfile = 'store/[data]/poller'; @@ -32,6 +35,7 @@ class Poller { // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. $x = ''; file_put_contents($lockfile, $x); +*/ logger('poller: start'); @@ -103,8 +107,10 @@ class Poller { if ($t < $x) { Master::Summon(['Onepoll', $contact['abook_id']]); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + + if ($interval) { + usleep($interval); + } } continue; @@ -167,9 +173,10 @@ class Poller { continue; Master::Summon(['Onepoll', $contact['abook_id']]); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + if ($interval) { + usleep($interval); + } } } @@ -190,9 +197,12 @@ class Poller { if ($rr['ud_last'] > NULL_DATE) if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day')) continue; + Master::Summon(['Onedirsync', $rr['ud_id']]); - if ($interval) - @time_sleep_until(microtime(true) + (float)$interval); + + if ($interval) { + usleep($interval); + } } } } @@ -200,9 +210,9 @@ class Poller { set_config('system', 'lastpoll', datetime_convert()); //All done - clear the lockfile - +/* @unlink($lockfile); - +*/ return; } } diff --git a/Zotlabs/Daemon/Queue.php b/Zotlabs/Daemon/Queue.php index 41aaf45ed..3eb7d9d23 100644 --- a/Zotlabs/Daemon/Queue.php +++ b/Zotlabs/Daemon/Queue.php @@ -79,5 +79,7 @@ class Queue { foreach ($r as $rv) { LibQueue::deliver($rv); } + + return; } } diff --git a/Zotlabs/Daemon/Thumbnail.php b/Zotlabs/Daemon/Thumbnail.php index 3688e8ae5..fa9570658 100644 --- a/Zotlabs/Daemon/Thumbnail.php +++ b/Zotlabs/Daemon/Thumbnail.php @@ -73,5 +73,7 @@ class Thumbnail { || (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) { $default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height); } + + return; } } diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 9dbb15c28..8f4e0444c 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -672,6 +672,7 @@ class Activity { } } } + return $ret; } @@ -2456,7 +2457,7 @@ class Activity { $s['attach'] = $a; } - $a = self::decode_iconfig($act->obj); + $a = self::decode_iconfig($act->data); if ($a) { $s['iconfig'] = $a; } @@ -2786,8 +2787,9 @@ class Activity { set_iconfig($s, 'diaspora', 'fields', $diaspora_rawmsg, 1); } - set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); - + if ($act->raw_recips) { + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); + } $hookinfo = [ 'act' => $act, diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index fd9886f71..f844c63b5 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -135,8 +135,7 @@ class Libsync { $info['collection_members'] = $r; } - $interval = ((get_config('system', 'delivery_interval') !== false) - ? intval(get_config('system', 'delivery_interval')) : 2); + $interval = get_config('queueworker', 'queue_interval', 500000); logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG); @@ -155,19 +154,26 @@ class Libsync { ]); + /* $x = q("select count(outq_hash) as total from outq where outq_delivered = 0"); + if (intval($x[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) { logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); Queue::update($hash); continue; } - + */ Master::Summon(['Deliver', $hash]); + + /* $total = $total - 1; + */ + + if ($interval) { + usleep($interval); + } - if ($interval && $total) - @time_sleep_until(microtime(true) + (float)$interval); } } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index b0d33e055..c635fdb17 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -291,6 +291,12 @@ class Libzot { } $m = parse_url($url); + + if (!$m) { + logger('zot_refresh: could not parse url'); + return false; + } + $site_url = unparse_url([ 'scheme' => $m['scheme'], 'host' => $m['host'] ]); $s = q("select site_dead from site where site_url = '%s' limit 1", diff --git a/Zotlabs/Lib/QueueWorker.php b/Zotlabs/Lib/QueueWorker.php new file mode 100644 index 000000000..fd2ebd7e1 --- /dev/null +++ b/Zotlabs/Lib/QueueWorker.php @@ -0,0 +1,357 @@ +<?php + +namespace Zotlabs\Lib; + +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\Exception\UnableToBuildUuidException; + +class QueueWorker { + + public static $queueworker = null; + public static $maxworkers = 0; + public static $workermaxage = 0; + public static $workersleep = 100; + public static $default_priorities = [ + 'Notifier' => 10, + 'Deliver' => 10, + 'Cache_query' => 10, + 'Content_importer' => 1, + 'File_importer' => 1, + 'Channel_purge' => 1, + 'Directory' => 1 + ]; + + // Exceptions for processtimeout ($workermaxage) value. + // Currently the value is overriden with 3600 seconds (1h). + public static $long_running_cmd = [ + 'Queue' + ]; + + private static function qstart() { + q('START TRANSACTION'); + } + + private static function qcommit() { + q("COMMIT"); + } + + private static function qrollback() { + q("ROLLBACK"); + } + + public static function Summon($argv) { + + if ($argv[0] !== 'Queueworker') { + + $priority = 0; // @TODO allow reprioritization + + if (isset(self::$default_priorities[$argv[0]])) { + $priority = self::$default_priorities[$argv[0]]; + } + + $workinfo = ['argc' => count($argv), 'argv' => $argv]; + $workinfo_json = json_encode($workinfo); + $uuid = self::getUuid($workinfo_json); + + $r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'", + dbesc($uuid) + ); + if ($r) { + logger("Summon: Ignoring duplicate workerq task", LOGGER_DEBUG); + logger(print_r($workinfo, true)); + return; + } + + self::qstart(); + $r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')", + intval($priority), + $workinfo_json, + dbesc($uuid), + dbesc($argv[0]) + ); + if (!$r) { + self::qrollback(); + logger("INSERT FAILED", LOGGER_DEBUG); + return; + } + self::qcommit(); + logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG); + } + + $workers = self::GetWorkerCount(); + if ($workers < self::$maxworkers) { + logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG); + $phpbin = get_config('system', 'phpbin', 'php'); + proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']); + } + } + + public static function Release($argv) { + + if ($argv[0] !== 'Queueworker') { + + $priority = 0; // @TODO allow reprioritization + if (isset(self::$default_priorities[$argv[0]])) { + $priority = self::$default_priorities[$argv[0]]; + } + + $workinfo = ['argc' => count($argv), 'argv' => $argv]; + $workinfo_json = json_encode($workinfo); + $uuid = self::getUuid($workinfo_json); + + $r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'", + dbesc($uuid) + ); + if ($r) { + logger("Release: Duplicate task - do not insert.", LOGGER_DEBUG); + logger(print_r($workinfo, true)); + return; + } + + self::qstart(); + $r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')", + intval($priority), + $workinfo_json, + dbesc($uuid), + dbesc($argv[0]) + ); + if (!$r) { + self::qrollback(); + logger("Insert failed: " . $workinfo_json, LOGGER_DEBUG); + return; + } + self::qcommit(); + logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG); + } + + self::Process(); + } + + public static function GetWorkerCount() { + if (self::$maxworkers == 0) { + self::$maxworkers = get_config('queueworker', 'max_queueworkers', 4); + self::$maxworkers = self::$maxworkers > 3 ? self::$maxworkers : 4; + } + if (self::$workermaxage == 0) { + self::$workermaxage = get_config('queueworker', 'max_queueworker_age'); + self::$workermaxage = self::$workermaxage > 120 ? self::$workermaxage : 300; + } + + q("update workerq set workerq_reservationid = null where workerq_reservationid is not null and workerq_processtimeout < %s", + db_utcnow() + ); + + //usleep(self::$workersleep); + + $workers = dbq("select count(distinct workerq_reservationid) as total from workerq where workerq_reservationid is not null"); + logger("WORKERCOUNT: " . $workers[0]['total'], LOGGER_DEBUG); + + return intval($workers[0]['total']); + } + + public static function GetWorkerID() { + if (self::$queueworker) { + return self::$queueworker; + } + + $wid = uniqid('', true); + + usleep(mt_rand(300000, 1000000)); //Sleep .3 - 1 seconds before creating a new worker. + + $workers = self::GetWorkerCount(); + + if ($workers >= self::$maxworkers) { + logger("Too many active workers ($workers) max = " . self::$maxworkers, LOGGER_DEBUG); + return false; + } + + self::$queueworker = $wid; + + return $wid; + } + + private static function getWorkId() { + self::GetWorkerCount(); + + self::qstart(); + + // This is probably the better solution but is not supported by mariadb < 10.6 which is still used a lot. + // $work = dbq("SELECT workerq_id FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE SKIP LOCKED;"); + + $work = dbq("SELECT workerq_id, workerq_cmd FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE;"); + + if (!$work) { + self::qcommit(); + return false; + } + + $id = $work[0]['workerq_id']; + $cmd = $work[0]['workerq_cmd']; + $age = self::$workermaxage; + + if (in_array($cmd, self::$long_running_cmd)) { + $age = 3600; // 1h TODO: make this configurable + } + + $work = q("UPDATE workerq SET workerq_reservationid = '%s', workerq_processtimeout = %s + INTERVAL %s WHERE workerq_id = %d", + self::$queueworker, + db_utcnow(), + db_quoteinterval($age . " SECOND"), + intval($id) + ); + + if (!$work) { + self::qrollback(); + logger("Could not update workerq.", LOGGER_DEBUG); + return false; + } + + logger("GOTWORK: " . json_encode($work), LOGGER_DEBUG); + self::qcommit(); + + return $id; + } + + public static function Process() { + $sleep = intval(get_config('queueworker', 'queue_worker_sleep', 100)); + $auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0); + + if (!self::GetWorkerID()) { + if ($auto_queue_worker_sleep) { + set_config('queueworker', 'queue_worker_sleep', $sleep + 100); + } + + logger('Unable to get worker ID. Exiting.', LOGGER_DEBUG); + killme(); + } + + if ($auto_queue_worker_sleep && $sleep > 100) { + $next_sleep = $sleep - 100; + set_config('queueworker', 'queue_worker_sleep', (($next_sleep < 100) ? 100 : $next_sleep)); + } + + $jobs = 0; + $workid = self::getWorkId(); + $load_average_sleep = false; + self::$workersleep = $sleep; + self::$workersleep = ((intval(self::$workersleep) > 100) ? intval(self::$workersleep) : 100); + + if (function_exists('sys_getloadavg') && get_config('queueworker', 'load_average_sleep')) { + // very experimental! + $load_average_sleep = true; + } + + while ($workid) { + + if ($load_average_sleep) { + $load_average = sys_getloadavg(); + self::$workersleep = intval($load_average[0]) * 10000; + + if (!self::$workersleep) { + self::$workersleep = 100; + } + } + + logger('queue_worker_sleep: ' . self::$workersleep, LOGGER_DEBUG); + + usleep(self::$workersleep); + + $workitem = dbq("SELECT * FROM workerq WHERE workerq_id = $workid"); + + if ($workitem) { + // At least SOME work to do.... in case there's more, let's ramp up workers. + $workers = self::GetWorkerCount(); + + if ($workers < self::$maxworkers) { + logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG); + $phpbin = get_config('system', 'phpbin', 'php'); + proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']); + } + + $jobs++; + + logger("Workinfo: " . $workitem[0]['workerq_data'], LOGGER_DEBUG); + + $workinfo = json_decode($workitem[0]['workerq_data'], true); + $argv = $workinfo['argv']; + + $cls = '\\Zotlabs\\Daemon\\' . $argv[0]; + $argv = flatten_array_recursive($argv); + $argc = count($argv); + $rnd = random_string(); + + logger('PROCESSING: ' . $rnd . ' ' . print_r($argv[0], true)); + + $cls::run($argc, $argv); + + logger('COMPLETED: ' . $rnd); + + // @FIXME: Right now we assume that if we get a return, everything is OK. + // At some point we may want to test whether the run returns true/false + // and requeue the work to be tried again if needed. But we probably want + // to implement some sort of "retry interval" first. + + dbq("delete from workerq where workerq_id = $workid"); + } + else { + logger("NO WORKITEM!", LOGGER_DEBUG); + } + $workid = self::getWorkId(); + } + logger('Master: Worker Thread: queue items processed:' . $jobs, LOGGER_DEBUG); + } + + public static function ClearQueue() { + $work = q("select * from workerq"); + while ($work) { + foreach ($work as $workitem) { + $workinfo = json_decode($workitem['v'], true); + $argc = $workinfo['argc']; + $argv = $workinfo['argv']; + + logger('Master: process: ' . print_r($argv, true), LOGGER_ALL, LOG_DEBUG); + + if (!isset($argv[0])) { + q("delete from workerq where workerq_id = %d", + $work[0]['workerq_id'] + ); + continue; + } + + $cls = '\\Zotlabs\\Daemon\\' . $argv[0]; + $cls::run($argc, $argv); + + q("delete from workerq where workerq_id = %d", + $work[0]['workerq_id'] + ); + + //Give the server .3 seconds to catch its breath between tasks. + //This will hopefully keep it from crashing to it's knees entirely + //if the last task ended up initiating other parallel processes + //(eg. polling remotes) + usleep(300000); + } + + //Make sure nothing new came in + $work = q("select * from workerq"); + } + } + + /** + * @brief Generate a name-based v5 UUID with custom namespace + * + * @param string $data + * @return string $uuid + */ + private static function getUuid(string $data) { + $namespace = '3a112e42-f147-4ccf-a78b-f6841339ea2a'; + try { + $uuid = Uuid::uuid5($namespace, $data)->toString(); + } catch (UnableToBuildUuidException $e) { + logger('UUID generation failed'); + return ''; + } + return $uuid; + } + +} diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index e86e2cac1..d1b386c42 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -137,13 +137,7 @@ class ThreadItem { $shareable = false; } - $privacy_warning = false; - if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) { - $recips = get_iconfig($item['parent'], 'activitypub', 'recips'); - - if(! is_array($recips['to']) || ! in_array($observer['xchan_url'], $recips['to'])) - $privacy_warning = true; - } + $privacy_warning = ($item['owner']['xchan_network'] === 'activitypub' && intval($item['item_private']) === 1); if ($lock) { if (($item['mid'] == $item['parent_mid']) && isset($item['term']) && count(get_terms_oftype($item['term'], TERM_FORUM))) { diff --git a/Zotlabs/Module/Admin/Queueworker.php b/Zotlabs/Module/Admin/Queueworker.php new file mode 100644 index 000000000..45a09bf04 --- /dev/null +++ b/Zotlabs/Module/Admin/Queueworker.php @@ -0,0 +1,121 @@ +<?php + +namespace Zotlabs\Module\Admin; + +use App; +use Zotlabs\Web\Controller; + +class Queueworker extends Controller { + + function init() { + + } + + function post() { + + check_form_security_token('form_security_token', 'queueworker'); + + $maxqueueworkers = intval($_POST['queueworker_maxworkers']); + $maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4; + set_config('queueworker', 'max_queueworkers', $maxqueueworkers); + + $maxworkerage = intval($_POST['queueworker_max_age']); + $maxworkerage = ($maxworkerage >= 120) ? $maxworkerage : 300; + set_config('queueworker', 'queueworker_max_age', $maxworkerage); + + $queueworkersleep = intval($_POST['queue_worker_sleep']); + $queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100; + set_config('queueworker', 'queue_worker_sleep', $queueworkersleep); + + $auto_queue_worker_sleep = intval($_POST['auto_queue_worker_sleep']); + set_config('queueworker', 'auto_queue_worker_sleep', $auto_queue_worker_sleep); + + goaway(z_root() . '/admin/queueworker'); + } + + function get() { + + $content = "<H1>Queue Status</H1>\n"; + + $r = q('select count(*) as total from workerq'); + + $content .= "<H4>There are " . $r[0]['total'] . " queue items to be processed.</H4>"; + + $r = dbq("select count(distinct workerq_reservationid) as qworkers from workerq where workerq_reservationid is not null"); + + $content .= "<H4>Active workers: " . $r[0]['qworkers'] . "</H4>"; + + $r = dbq("select workerq_cmd, count(*) as total from workerq where true group by workerq_cmd"); + + if ($r) { + $content .= "<H4>Work items</H4>"; + foreach($r as $rr) { + $content .= $rr['workerq_cmd'] . ': ' . $rr['total'] . '<br>'; + } + } + + $maxqueueworkers = get_config('queueworker', 'max_queueworkers', 4); + $maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4; + + $sc = ''; + + $sc .= replace_macros(get_markup_template('field_input.tpl'), [ + '$field' => [ + 'queueworker_maxworkers', + t('Max queueworker threads'), + $maxqueueworkers, + t('Minimum 4, default 4') + ] + ]); + + $workermaxage = get_config('queueworker', 'queueworker_max_age'); + $workermaxage = ($workermaxage >= 120) ? $workermaxage : 300; + + $sc .= replace_macros(get_markup_template('field_input.tpl'), [ + '$field' => [ + 'queueworker_max_age', + t('Assume workers dead after'), + $workermaxage, + t('Minimum 120, default 300 seconds') + ] + ]); + + $queueworkersleep = get_config('queueworker', 'queue_worker_sleep'); + $queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100; + + $auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), [ + '$field' => [ + 'queue_worker_sleep', + t('Pause before starting next task'), + $queueworkersleep, + t('Minimum 100, default 100 microseconds'), + '', + (($auto_queue_worker_sleep) ? 'disabled' : '') + ] + ]); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), [ + '$field' => [ + 'auto_queue_worker_sleep', + t('Automatically adjust pause before starting next task'), + $auto_queue_worker_sleep, + ] + ]); + + $tpl = get_markup_template('settings_addon.tpl'); + $content .= replace_macros($tpl, [ + '$action_url' => 'admin/queueworker', + '$form_security_token' => get_form_security_token('queueworker'), + '$title' => t('Queueworker Settings'), + '$content' => $sc, + '$baseurl' => z_root(), + '$submit' => t('Save') + ] + ); + + return $content; + + } +} diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index 85f81e344..42cf064c9 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -100,7 +100,7 @@ class Site { $reg_expire = (preg_match('/^[a-z]{1,1}$/', $regexpireu) ? $regexpiren . $regexpireu : ''); $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : ''); - $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); + //$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); $pub_incl = escape_tags(trim($_POST['pub_incl'])); $pub_excl = escape_tags(trim($_POST['pub_excl'])); @@ -205,7 +205,7 @@ class Site { set_config('system','disable_discover_tab', $disable_discover_tab); set_config('system','site_firehose', $site_firehose); set_config('system','open_pubstream', $open_pubstream); - set_config('system','force_queue_threshold', $force_queue); + //set_config('system','force_queue_threshold', $force_queue); if ($global_directory == '') { del_config('system', 'directory_submit_url'); } else { @@ -508,10 +508,10 @@ class Site { '$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'pubstream' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")), '$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')), '$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")), - '$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")), - '$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')), - '$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')), - '$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the Public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing. Warning: this content is unmoderated.')), + '$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory")), + '$disable_discover_tab' => array('disable_discover_tab', t('Enable public stream'), $discover_tab, t('Enable the public stream. Warning: this content is unmoderated')), + '$site_firehose' => array('site_firehose', t('Site only public stream'), get_config('system','site_firehose'), t('Restrict the public stream to content originating at this site')), + '$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing')), '$incl' => array('pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), '$excl' => array('pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), @@ -532,7 +532,7 @@ class Site { '$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).")), '$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")), '$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")), - '$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")), + //'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")), '$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")), '$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")), '$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")), diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 4cc7595a1..05109247a 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -100,7 +100,6 @@ class Cloud extends Controller { // over-ride the default XML output on thrown exceptions - $server->on('exception', [ $this, 'DAVException' ]); // All we need to do now, is to fire up the server @@ -117,21 +116,19 @@ class Cloud extends Controller { function DAVException($err) { if($err instanceof \Sabre\DAV\Exception\NotFound) { - notice( t('Not found') . EOL); + \App::$page['content'] = '<h2>404 Not found</h2>'; } elseif($err instanceof \Sabre\DAV\Exception\Forbidden) { - notice( t('Permission denied') . EOL); + \App::$page['content'] = '<h2>403 Forbidden</h2>'; } elseif($err instanceof \Sabre\DAV\Exception\NotImplemented) { - // notice( t('Please refresh page') . EOL); goaway(z_root() . '/' . \App::$query_string); } else { - notice( t('Unknown error') . EOL); + \App::$page['content'] = '<h2>Unknown error</h2>'; } construct_page(); - killme(); } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index ec47e370b..c8a9ac5ed 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -536,7 +536,7 @@ class Import extends Controller { $since = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), '0001-01-01 00:00'); $until = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), 'now + 1 day'); - $poll_interval = get_config('system', 'poll_interval', 3); + //$poll_interval = get_config('system', 'poll_interval', 3); $page = 0; Master::Summon(['Content_importer', sprintf('%d', $page), $since, $until, $channel['channel_address'], urlencode($hz_server)]); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 8e6106e79..27fc62ee6 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -1518,8 +1518,9 @@ class Item extends Controller { if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism', $body, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { - $ptr[] = ['name' => $match[1], 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; - $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body); + $answer = escape_tags(trim($match[1])); + $ptr[] = ['name' => $answer, 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + $body = str_replace('[answer]' . $answer . '[/answer]', EMPTY_STR, $body); } } @@ -1573,8 +1574,10 @@ class Item extends Controller { $obj['content'] = bbcode($question); foreach ($answers as $answer) { - if (trim($answer)) - $ptr[] = ['name' => escape_tags($answer), 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + $answer = escape_tags(trim($answer)); + if ($answer) { + $ptr[] = ['name' => $answer, 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + } } if ($multiple) { diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php index 3b94c9611..e0bbc31d0 100644 --- a/Zotlabs/Module/Pdledit.php +++ b/Zotlabs/Module/Pdledit.php @@ -78,6 +78,23 @@ class Pdledit extends Controller { } } + // addons + $o .= '<h2>Addons</h2>'; + + $addons = plugins_installed_list(); + + foreach ($addons as $addon) { + + $path = 'addon/' . $addon . '/Mod_' . ucfirst($addon) . '.php'; + + if (!file_exists($path)) + continue; + + $o .= '<a href="pdledit/' . $addon . '" >' . $addon . '</a>' . ((in_array($addon, $edited)) ? ' ' . t('(modified)') . ' <a href="pdledit/' . $addon . '/reset" >' . t('Reset') . '</a>': '' ) . '<br />'; + + } + + $o .= '</div>'; // list module pdl files @@ -85,11 +102,25 @@ class Pdledit extends Controller { } $t = get_pconfig(local_channel(),'system',$module); - $s = file_get_contents(theme_include($module)); - if(! $t) { + $s = ''; + + if(!$t) { + $sys_path = theme_include($module); + + if ($sys_path) { + $s = file_get_contents($sys_path); + } + else { + $addon_path = 'addon/' . argv(1) . '/' . $module; + if (file_exists($addon_path)) { + $s = file_get_contents($addon_path); + } + } + $t = $s; } - if(! $t) { + + if(!$t) { notice( t('Layout not found.') . EOL); return ''; } diff --git a/Zotlabs/Module/Pdledit_gui.php b/Zotlabs/Module/Pdledit_gui.php index b550b92d3..dadb3296e 100644 --- a/Zotlabs/Module/Pdledit_gui.php +++ b/Zotlabs/Module/Pdledit_gui.php @@ -220,6 +220,7 @@ class Pdledit_gui extends Controller { function get_modules() { $ret = ''; + $arr = []; $files = glob('Zotlabs/Module/*.php'); if($files) { @@ -232,23 +233,54 @@ class Pdledit_gui extends Controller { $x = theme_include('mod_' . $name . '.pdl'); if($x) { - $ret .= '<div class="mb-2"><a href="pdledit_gui/' . $name . '">' . $name . '</a></div>'; + $arr[] = $name; } } } + $addons = plugins_installed_list(); + if ($addons) { + foreach ($addons as $name) { + $path = 'addon/' . $name . '/mod_' . $name . '.pdl'; + if (file_exists($path)) { + $arr[] = $name; + } + } + } + + sort($arr); + + foreach ($arr as $name) { + $ret .= '<div class="mb-2"><a href="pdledit_gui/' . $name . '">' . $name . '</a></div>'; + } + return $ret; + } function get_widgets($module) { $ret = []; + $checkpaths = [ 'Zotlabs/Widget/*.php' ]; + $addons = plugins_installed_list(); + + if ($addons) { + foreach ($addons as $name) { + $path = 'addon/' . $name . '/Widget'; + + if (is_dir($path)) { + $checkpaths[] = $path . '/*.php'; + } + } + } + foreach ($checkpaths as $path) { $files = glob($path); + if($files) { foreach($files as $f) { $name = lcfirst(basename($f, '.php')); @@ -272,6 +304,8 @@ class Pdledit_gui extends Controller { } } + usort($ret, fn($a, $b) => $a['name'] <=> $b['name']); + return $ret; } @@ -536,12 +570,21 @@ class Pdledit_gui extends Controller { 'modified' => true ]; - $pdl_path = 'mod_' . $module . '.pdl'; + $pdl = 'mod_' . $module . '.pdl'; + $pdl_path = ''; - $ret['pdl'] = get_pconfig(local_channel(), 'system', $pdl_path); + $ret['pdl'] = get_pconfig(local_channel(), 'system', $pdl); if(!$ret['pdl']) { - $pdl_path = theme_include($pdl_path); + $pdl_path = theme_include($pdl); + + if (!$pdl_path) { + $addon_path = 'addon/' . $module . '/' . $pdl; + if (file_exists($addon_path)) { + $pdl_path = $addon_path; + } + } + if ($pdl_path) { $ret['pdl'] = file_get_contents($pdl_path); $ret['modified'] = false; diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 47da3c13a..7b8d75727 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -158,16 +158,15 @@ class Pubstream extends \Zotlabs\Web\Controller { require_once('include/security.php'); $sys = get_sys_channel(); + $uids = " and item.uid = " . intval($sys['channel_id']) . " "; $abook_uids = " and abook.abook_channel = " . intval($sys['channel_id']) . " "; - $sql_extra = ''; + $sql_extra = item_permissions_sql($sys['channel_id']); + $sql_extra_order = ''; + $site_firehose_sql = ''; + $thread_top = " and item.item_thread_top = 1 "; if($site_firehose) { - $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 "; - } - else { - $uids = " and item.uid = " . intval($sys['channel_id']) . " "; - $sql_extra .= item_permissions_sql($sys['channel_id']); - \App::$data['firehose'] = intval($sys['channel_id']); + $site_firehose_sql = " and owner_xchan in (select channel_hash from channel where channel_system = 0 and channel_removed = 0) "; } if(get_config('system','public_list_mode')) @@ -178,6 +177,8 @@ class Pubstream extends \Zotlabs\Web\Controller { if(x($hashtags)) { $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + $sql_extra_order = " ORDER BY item.created DESC "; + $thread_top = ''; } $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); @@ -199,7 +200,9 @@ 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 = '%s' $uids $item_normal + WHERE item.mid = '%s' and item.item_private = 0 + $uids $site_firehose_sql + $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2", dbesc($mid) @@ -207,10 +210,12 @@ class Pubstream extends \Zotlabs\Web\Controller { } else { // Fetch a page full of parent items for this page - $r = dbq("SELECT item.id AS item_id FROM item + $r = dbq("SELECT parent AS item_id FROM item left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids ) $net_query - WHERE true $uids and item.item_thread_top = 1 $item_normal + WHERE item.item_private = 0 $thread_top + $uids $site_firehose_sql + $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2 ORDER BY $ordering DESC $pager_sql " @@ -222,7 +227,8 @@ 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 = '%s' $uids $item_normal_update $simple_update + WHERE item.mid = '%s' and item.item_private = 0 + $uids $site_firehose_sql $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2", dbesc($mid) @@ -232,7 +238,8 @@ class Pubstream extends \Zotlabs\Web\Controller { $r = dbq("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query - WHERE true $uids $item_normal_update + WHERE item.item_private = 0 $thread_top + $uids $site_firehose_sql $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2" @@ -250,15 +257,22 @@ class Pubstream extends \Zotlabs\Web\Controller { $items = dbq("SELECT item.*, item.id AS item_id FROM item WHERE true $uids $item_normal AND item.parent IN ( $parents_str ) - $sql_extra" + $sql_extra $sql_extra_order" ); + + // use effective_uid param of xchan_query to help sort out comment permission // for sys_channel owned items. - xchan_query($items,true,(($sys) ? local_channel() : 0)); + xchan_query($items, true, local_channel()); $items = fetch_post_tags($items,true); - $items = conv_sort($items,$ordering); + + if (!$hashtags) { + $items = conv_sort($items, $ordering); + } + + } } diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php index 97cc9389a..5e1fb176e 100644 --- a/Zotlabs/Module/Settings/Account.php +++ b/Zotlabs/Module/Settings/Account.php @@ -6,11 +6,11 @@ class Account { function post() { check_form_security_token_redirectOnErr('/settings/account', 'settings_account'); - + call_hooks('account_settings_post', $_POST); - + $errs = array(); - + $email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : ''); $account = \App::get_account(); @@ -34,38 +34,38 @@ class Account { } } } - + if($errs) { foreach($errs as $err) notice($err . EOL); $errs = array(); } - - + + if((x($_POST,'npassword')) || (x($_POST,'confirm'))) { - + $origpass = trim($_POST['origpass']); - + require_once('include/auth.php'); if(! account_verify_password($email,$origpass)) { $errs[] = t('Password verification failed.'); } - + $newpass = trim($_POST['npassword']); $confirm = trim($_POST['confirm']); - + if($newpass != $confirm ) { $errs[] = t('Passwords do not match. Password unchanged.'); } - + if((! x($newpass)) || (! x($confirm))) { $errs[] = t('Empty passwords are not allowed. Password unchanged.'); } - + if(! $errs) { $salt = random_string(32); $password_encoded = hash('whirlpool', $salt . $newpass); - $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' + $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' where account_id = %d", dbesc($salt), dbesc($password_encoded), @@ -78,36 +78,37 @@ class Account { $errs[] = t('Password update failed. Please try again.'); } } - - + + if($errs) { foreach($errs as $err) notice($err . EOL); } goaway(z_root() . '/settings/account' ); } - - + + function get() { $account_settings = ""; - + call_hooks('account_settings', $account_settings); - + $email = \App::$account['account_email']; - $attremail = (!strpos($email, '@')) ? 'disabled="disabled"' : ''; + $attremail = ((!strpos($email, '@')) ? 'disabled="disabled"' : ''); $tpl = get_markup_template("settings_account.tpl"); $o .= replace_macros($tpl, array( '$form_security_token' => get_form_security_token("settings_account"), - '$title' => t('Account Settings'), - '$origpass' => array('origpass', t('Current Password'), ' ',''), - '$password1'=> array('npassword', t('Enter New Password'), '', ''), - '$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), - '$submit' => t('Submit'), - '$email' => array('email', t('DId2 or Email Address:'), $email, '', '', $attremail), - '$removeme' => t('Remove Account'), - '$removeaccount' => t('Remove this account including all its channels'), + '$title' => t('Account Settings'), + '$origpass' => array('origpass', t('Current Password'), ' ',''), + '$password1' => array('npassword', t('Enter New Password'), '', ''), + '$password2' => array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), + '$submit' => t('Submit'), + '$email' => array('email', t('DId2 or Email Address:'), $email, '', '', $attremail), + '$email_hidden' => (($attremail) ? $email : ''), + '$removeme' => t('Remove Account'), + '$removeaccount' => t('Remove this account including all its channels'), '$account_settings' => $account_settings )); return $o; diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php index 4211a3af8..c294079d4 100644 --- a/Zotlabs/Module/Sharedwithme.php +++ b/Zotlabs/Module/Sharedwithme.php @@ -19,13 +19,13 @@ class Sharedwithme extends Controller { notice( t('Permission denied.') . EOL); return; } - + $channel = \App::get_channel(); - + $is_owner = (local_channel() && (local_channel() == $channel['channel_id'])); $item_normal = item_normal(); - + //drop single file - localuser if((argc() > 2) && (argv(2) === 'drop')) { @@ -36,7 +36,7 @@ class Sharedwithme extends Controller { goaway(z_root() . '/sharedwithme'); } - + //drop all files - localuser if((argc() > 1) && (argv(1) === 'dropall')) { @@ -62,33 +62,34 @@ class Sharedwithme extends Controller { dbesc($channel['channel_hash']) ); + $r = fetch_post_tags($r, true); + $items = []; $ids = []; if($r) { - + foreach($r as $rr) { - $object = json_decode($rr['obj'],true); - $meta = self::get_meta($object); + $meta = get_iconfig($rr, 'attach', 'meta'); $item = []; $item['id'] = $rr['id']; $item['objfiletype'] = $meta['type']; $item['objfiletypeclass'] = getIconFromType($meta['type']); $item['objurl'] = $meta['path'] . '?f=&zid=' . $channel['xchan_addr']; - $item['objfilename'] = $object['name']; + $item['objfilename'] = $meta['name']; $item['objfilesize'] = userReadableSize($meta['size']); $item['objedited'] = $meta['edited']; $item['unseen'] = $rr['item_unseen']; - + $items[] = $item; - + if($item['unseen']) { $ids[] = $rr['id']; } - + } - + } $ids = implode(',', $ids); @@ -98,9 +99,9 @@ class Sharedwithme extends Controller { intval(local_channel()) ); } - + $o = ''; - + $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array( '$header' => t('Files: shared with me'), '$name' => t('Name'), @@ -111,27 +112,9 @@ class Sharedwithme extends Controller { '$drop' => t('Remove this file'), '$items' => $items )); - - return $o; - - } - - function get_meta($object) { - - $ret = []; - - if(! is_array($object['attachment'])) - return; - foreach($object['attachment'] as $a) { - if($a['name'] === 'zot.attach.meta') { - $ret = $a['value']; - break; - } - } - - return $ret; + return $o; } - + } diff --git a/Zotlabs/Module/Sse.php b/Zotlabs/Module/Sse.php index f87a19821..8b46dcafd 100644 --- a/Zotlabs/Module/Sse.php +++ b/Zotlabs/Module/Sse.php @@ -50,7 +50,7 @@ class Sse extends Controller { self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify'); } - $sleep_seconds = 3; + $sleep = 1000000; // microseconds self::$sse_enabled = get_config('system', 'sse_enabled', 0); @@ -63,17 +63,24 @@ class Sse extends Controller { header("Connection: keep-alive"); header("X-Accel-Buffering: no"); - while(true) { + $i = 0; - if(! self::$sse_id) { + while(true) { - // Update chat presence indication + // reset counter for updating chatpresence about every minute + if (($i * $sleep)/60 > 1000000) { + $i = 0; + } + if(!self::$sse_id && $i === 0) { + // Update chat presence indication about once per minute $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", @@ -81,7 +88,8 @@ class Sse extends Controller { intval($r[0]['cp_id']) ); } - if(! $basic_presence) { + + if(!$basic_presence) { q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) values( '%s', '%s', '%s', '%s' ) ", dbesc(self::$ob_hash), @@ -94,9 +102,14 @@ class Sse extends Controller { XConfig::Load(self::$ob_hash); - $result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []); + $result = []; $lock = XConfig::Get(self::$ob_hash, 'sse', 'lock'); + if (!$lock) { + $result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []); + } + + // We do not have the local_channel in the addon. // Reset pubs here if the app is not installed. if (self::$uid && (!(self::$vnotify & VNOTIFY_PUBS) || !Apps::system_app_installed(self::$uid, 'Public Stream'))) { @@ -105,7 +118,7 @@ class Sse extends Controller { } } - if($result && !$lock) { + if($result) { echo "event: notifications\n"; echo 'data: ' . json_encode($result); echo "\n\n"; @@ -121,6 +134,7 @@ class Sse extends Controller { if(ob_get_length() > 0) ob_end_flush(); + flush(); if(connection_status() != CONNECTION_NORMAL || connection_aborted()) { @@ -129,7 +143,9 @@ class Sse extends Controller { break; } - sleep($sleep_seconds); + $i++; + + usleep($sleep); } diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php index 4aabcafcb..052870cc9 100644 --- a/Zotlabs/Module/Sse_bs.php +++ b/Zotlabs/Module/Sse_bs.php @@ -173,6 +173,9 @@ class Sse_bs extends Controller { $item_normal = item_normal(); + // FEP-5624 filter approvals for comments + $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + if ($notifications) { $items = q("SELECT * FROM item WHERE uid = %d @@ -181,6 +184,7 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal + $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", @@ -210,6 +214,7 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal + $approvals $sql_extra LIMIT 100", intval(self::$uid), dbesc(self::$ob_hash) @@ -253,6 +258,9 @@ class Sse_bs extends Controller { $item_normal = item_normal(); + // FEP-5624 filter approvals for comments + $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + if ($notifications) { $items = q("SELECT * FROM item WHERE uid = %d @@ -261,6 +269,7 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal + $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", @@ -288,6 +297,7 @@ class Sse_bs extends Controller { $r = q("SELECT id FROM item WHERE uid = %d and item_unseen = 1 AND item_private = 2 $item_normal + $approvals $sql_extra AND author_xchan != '%s' LIMIT 100", intval(self::$uid), @@ -333,6 +343,9 @@ class Sse_bs extends Controller { $item_normal = item_normal(); + // FEP-5624 filter approvals for comments + $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + if ($notifications) { $items = q("SELECT * FROM item WHERE uid = %d @@ -341,6 +354,7 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal + $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", @@ -368,6 +382,7 @@ class Sse_bs extends Controller { $r = q("SELECT id FROM item WHERE uid = %d and item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1) $item_normal + $approvals $sql_extra AND author_xchan != '%s' LIMIT 100", intval(self::$uid), @@ -421,21 +436,30 @@ class Sse_bs extends Controller { if(self::$xchans) $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") "; + $uids = " AND uid IN ( " . $sys['channel_id'] . " ) "; + + $site_firehose = get_config('system', 'site_firehose', 0); + if($site_firehose) { + $uids = " AND uid IN ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) AND item_private = 0 AND item_wall = 1 "; + } + $item_normal = item_normal(); + // FEP-5624 filter approvals for comments + $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + if ($notifications) { $items = q("SELECT * FROM item - WHERE uid = %d + WHERE true $uids AND created <= '%s' - AND item_unseen = 1 AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' AND created > '%s' $item_normal + $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", - intval($sys['channel_id']), dbescdate($_SESSION['sse_loadtime']), dbesc(self::$ob_hash), dbescdate($_SESSION['static_loadtime']) @@ -454,17 +478,15 @@ class Sse_bs extends Controller { else { $result['pubs']['offset'] = -1; } - - } $r = q("SELECT id FROM item - WHERE uid = %d AND item_unseen = 1 + WHERE true $uids AND created > '%s' $item_normal + $approvals $sql_extra AND author_xchan != '%s' LIMIT 100", - intval($sys['channel_id']), dbescdate($_SESSION['static_loadtime']), dbesc(self::$ob_hash) ); diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index 4f909d33d..870fd760c 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -45,9 +45,7 @@ class Vote extends Controller { if ($obj['oneOf']) { foreach($obj['oneOf'] as $selection) { - // logger('selection: ' . $selection); - // logger('response: ' . $response); - if($selection['name'] && $selection['name'] === $response) { + if($selection['name'] && htmlspecialchars_decode($selection['name']) === $response) { $valid = true; } } @@ -56,7 +54,7 @@ class Vote extends Controller { $choices = []; if ($obj['anyOf']) { foreach ($obj['anyOf'] as $selection) { - $choices[] = $selection['name']; + $choices[] = htmlspecialchars_decode($selection['name']); } foreach ($response as $res) { if (! in_array($res,$choices)) { diff --git a/Zotlabs/Update/_1254.php b/Zotlabs/Update/_1254.php new file mode 100644 index 000000000..f316fe65b --- /dev/null +++ b/Zotlabs/Update/_1254.php @@ -0,0 +1,55 @@ +<?php + +namespace Zotlabs\Update; + +class _1254 { + + function run() { + + dbq("START TRANSACTION"); + + if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = dbq("CREATE TABLE IF NOT EXISTS workerq ( + workerq_id bigserial NOT NULL, + workerq_priority smallint, + workerq_reservationid varchar(25) DEFAULT NULL, + workerq_processtimeout timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', + workerq_data text, + workerq_uuid UUID NOT NULL, + PRIMARY KEY (workerq_id))" + ); + + $r2 = dbq("CREATE INDEX idx_workerq_priority ON workerq (workerq_priority)"); + $r3 = dbq("CREATE INDEX idx_workerq_reservationid ON workerq (workerq_reservationid)"); + $r4 = dbq("CREATE INDEX idx_workerq_processtimeout ON workerq (workerq_processtimeout)"); + $r5 = dbq("CREATE INDEX idx_workerq_uuid ON workerq (workerq_uuid)"); + + $r = ($r1 && $r2 && $r3 && $r4 && $r5); + } + else { + $r = dbq("CREATE TABLE IF NOT EXISTS workerq ( + workerq_id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + workerq_priority smallint, + workerq_reservationid varchar(25) DEFAULT NULL, + workerq_processtimeout datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + workerq_data text, + workerq_uuid char(36) NOT NULL DEFAULT '', + KEY workerq_priority (workerq_priority), + KEY workerq_reservationid (workerq_reservationid), + KEY workerq_processtimeout (workerq_uuid), + KEY workerq_uuid (workerq_processtimeout) + ) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4" + ); + } + + if($r) { + dbq("COMMIT"); + return UPDATE_SUCCESS; + } + + q("ROLLBACK"); + return UPDATE_FAILED; + + } + +} diff --git a/Zotlabs/Update/_1255.php b/Zotlabs/Update/_1255.php new file mode 100644 index 000000000..4f1da1a4a --- /dev/null +++ b/Zotlabs/Update/_1255.php @@ -0,0 +1,29 @@ +<?php + +namespace Zotlabs\Update; + +class _1255 { + + function run() { + + dbq("START TRANSACTION"); + + if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r = q("ALTER TABLE workerq add workerq_cmd text NOT NULL DEFAULT ''"); + } + + if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE workerq add workerq_cmd varchar(191) NOT NULL DEFAULT ''"); + } + + if($r) { + dbq("COMMIT"); + return UPDATE_SUCCESS; + } + + q("ROLLBACK"); + return UPDATE_FAILED; + + } + +} diff --git a/Zotlabs/Web/SessionRedis.php b/Zotlabs/Web/SessionRedis.php index 66eb7a02d..f32e6a4f4 100644 --- a/Zotlabs/Web/SessionRedis.php +++ b/Zotlabs/Web/SessionRedis.php @@ -42,7 +42,7 @@ class SessionRedis implements \SessionHandlerInterface { }
}
-
+ #[\ReturnTypeWillChange]
function open($s, $n) {
return true;
@@ -53,6 +53,7 @@ class SessionRedis implements \SessionHandlerInterface { // some which call read explicitly and some that do not. So we call it explicitly
// just after sid regeneration to force a record to exist.
+ #[\ReturnTypeWillChange]
function read($id) {
if ($id) {
@@ -67,7 +68,7 @@ class SessionRedis implements \SessionHandlerInterface { return '';
}
-
+ #[\ReturnTypeWillChange]
function write($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
@@ -100,13 +101,13 @@ class SessionRedis implements \SessionHandlerInterface { return true;
}
-
+ #[\ReturnTypeWillChange]
function close() {
return true;
}
-
+ #[\ReturnTypeWillChange]
function destroy ($id) {
$this->redis->del($id);
@@ -114,7 +115,7 @@ class SessionRedis implements \SessionHandlerInterface { return true;
}
-
+ #[\ReturnTypeWillChange]
function gc($expire) {
return true;
diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php index 0a7a6925f..aa88de36a 100644 --- a/Zotlabs/Widget/Admin.php +++ b/Zotlabs/Widget/Admin.php @@ -32,6 +32,7 @@ class Admin { 'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'), 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), + 'queueworker' => array(z_root() . '/admin/queueworker', t('Queueworker'), 'queueworker'), 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'), 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') ]; diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index b31856e48..7e6a3c6f7 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -3,7 +3,7 @@ /** * * Name: Categories * * Description: Display a menu with links to categories - * * Requires: channel, articles, cards, cloud + * * Requires: channel, cloud */ namespace Zotlabs\Widget; @@ -24,15 +24,16 @@ class Categories { } $cat = ((x($_REQUEST, 'cat')) ? htmlspecialchars($_REQUEST['cat'], ENT_COMPAT, 'UTF-8') : ''); - $srchurl = App::$query_string; - $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); - $srchurl = str_replace(['?f=','&f=', '/?'], ['', '', ''], $srchurl); + + // Discard queries from the current URL, as the template expects a base + // URL without any queries. + $base = substr(App::$query_string, 0, strcspn(App::$query_string, '?')); if($files) { - return filecategories_widget($srchurl, $cat); + return filecategories_widget($base, $cat); } - return categories_widget($srchurl, $cat); + return categories_widget($base, $cat); } } diff --git a/Zotlabs/Widget/Channel_activities.php b/Zotlabs/Widget/Channel_activities.php index 9acde591d..06080f8c8 100644 --- a/Zotlabs/Widget/Channel_activities.php +++ b/Zotlabs/Widget/Channel_activities.php @@ -26,7 +26,7 @@ class Channel_activities { self::$channel = App::get_channel(); $o = '<div id="channel-activities" class="d-none overflow-hidden">'; - $o .= '<h2 class="mb-4">Welcome ' . self::$channel['channel_name'] . '!</h2>'; + $o .= '<h2 class="mb-4">' . t('Welcome') . ' ' . self::$channel['channel_name'] . '!</h2>'; //$o .= 'Last login date: ' . get_pconfig(self::$uid, 'system', 'stored_login_date') . ' from ' . get_pconfig(self::$uid, 'system', 'stored_login_addr'); self::get_photos_activity(); @@ -43,7 +43,7 @@ class Channel_activities { call_hooks('channel_activities_widget', $hookdata); if (!$hookdata['activities']) { - $o .= '<h3>No recent activity to display</h3>'; + $o .= '<h3>' . t('No recent activities') . '</h3>'; $o .= '</div>'; return $o; } diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php index 0f57a8d85..8c413e16e 100644 --- a/Zotlabs/Widget/Messages.php +++ b/Zotlabs/Widget/Messages.php @@ -58,7 +58,8 @@ class Messages { } $channel = App::get_channel(); - $item_normal = str_replace('item.', 'i.', item_normal()); + $item_normal_i = str_replace('item.', 'i.', item_normal()); + $item_normal_c = str_replace('item.', 'c.', item_normal()); $entries = []; $limit = 30; $dummy_order_sql = ''; @@ -68,10 +69,12 @@ class Messages { $vnotify_sql = ''; if (!($vnotify & VNOTIFY_LIKE)) { - $vnotify_sql = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; + $vnotify_sql_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; + $vnotify_sql_i = " AND i.verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; } elseif (!feature_enabled(local_channel(), 'dislike')) { - $vnotify_sql = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') "; + $vnotify_sql_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') "; + $vnotify_sql_i = " AND i.verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') "; } switch($type) { @@ -88,13 +91,16 @@ class Messages { $type_sql = ' AND i.item_private IN (0, 1) '; } + // FEP-5624 filter approvals for comments + $approvals_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + $items = q("SELECT *, - (SELECT count(*) FROM item c WHERE c.uid = %d AND c.parent = i.parent AND c.item_unseen = 1 AND c.item_thread_top = 0 $vnotify_sql) AS unseen_count + (SELECT count(*) FROM item c WHERE c.uid = %d AND c.parent = i.parent AND c.item_unseen = 1 AND c.item_thread_top = 0 $item_normal_c $approvals_c $vnotify_sql_c) AS unseen_count FROM item i WHERE i.uid = %d AND i.created <= '%s' $type_sql AND i.item_thread_top = 1 - $item_normal + $item_normal_i ORDER BY i.created DESC $dummy_order_sql LIMIT $limit OFFSET $offset", intval(local_channel()), diff --git a/Zotlabs/Widget/Pubtagcloud.php b/Zotlabs/Widget/Pubtagcloud.php index db7ea02e7..90bf5eb97 100644 --- a/Zotlabs/Widget/Pubtagcloud.php +++ b/Zotlabs/Widget/Pubtagcloud.php @@ -22,24 +22,19 @@ class Pubtagcloud { } } - $site_firehose = ((intval(get_config('system','site_firehose',0))) ? true : false); - $net_firehose = ((get_config('system','disable_discover_tab',1)) ? false : true); + $net_firehose = ((get_config('system','disable_discover_tab',1)) ? false : true); - if(! ($site_firehose || $net_firehose)) { - return EMPTY_STR; - } + if(!$net_firehose) { + return ''; + } - if($net_firehose) { - $site_firehose = false; - } + $site_firehose = ((intval(get_config('system','site_firehose',0))) ? true : false); $safemode = get_xconfig(get_observer_hash(),'directory','safemode',1); - - $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 75); - return pubtagblock($net_firehose,$site_firehose, $limit, $trending, $safemode); + return pubtagblock($net_firehose, $site_firehose, $limit, $trending, $safemode); return ''; } @@ -60,10 +60,10 @@ require_once('include/bbcode.php'); require_once('include/items.php'); define('PLATFORM_NAME', 'hubzilla'); -define('STD_VERSION', '7.9.9'); +define('STD_VERSION', '7.9.17'); define('ZOT_REVISION', '6.0'); -define('DB_UPDATE_VERSION', 1253); +define('DB_UPDATE_VERSION', 1255); define('PROJECT_BASE', __DIR__); @@ -2045,24 +2045,8 @@ function proc_run() { if (!$arr['run_cmd']) return; - if (count($args) && $args[0] === 'php') + if (count($args) && $args[0] === 'php') { $args[0] = ((x(App::$config, 'system')) && (x(App::$config['system'], 'php_path')) && (strlen(App::$config['system']['php_path'])) ? App::$config['system']['php_path'] : 'php'); - - - // redirect proc_run statements of legacy daemon processes to the newer Daemon Master object class - // We will keep this interface until everybody has transitioned. (2016-05-20) - - if (strstr($args[1], 'include/')) { - // convert 'include/foo.php' to 'Foo' - $orig = substr(ucfirst(substr($args[1], 8)), 0, -4); - logger('proc_run_redirect: ' . $orig); - if (file_exists('Zotlabs/Daemon/' . $orig . '.php')) { - array_shift($args); // daemons are all run by php, pop it off the top of the array - $args[0] = $orig; // replace with the new daemon name - logger('Redirecting old proc_run interface: ' . print_r($args, true), LOGGER_DEBUG, LOG_DEBUG); - Master::Summon($args); // summon the daemon - return; - } } $args = array_map('escapeshellarg', $args); @@ -2284,6 +2268,7 @@ function load_pdl() { 'module' => App::$module, 'layout' => '' ]; + /** * @hooks load_pdl * Called when we load a PDL file or description. @@ -2297,20 +2282,26 @@ function load_pdl() { $u = App::$comanche->get_channel_id(); $s = ''; - if ($u) + if ($u) { $s = get_pconfig($u, 'system', $n); - if (!$s) + } + + if (!$s) { $s = $layout; + } - if ((!$s) && (($p = theme_include($n)) != '')) + if ((!$s) && (($p = theme_include($n)) != '')) { $s = @file_get_contents($p); - elseif (file_exists('addon/' . App::$module . '/' . $n)) + } + elseif ((!$s) && file_exists('addon/' . App::$module . '/' . $n)) { $s = @file_get_contents('addon/' . App::$module . '/' . $n); + } $arr = [ 'module' => App::$module, 'layout' => $s ]; + call_hooks('alter_pdl', $arr); $s = $arr['layout']; diff --git a/include/attach.php b/include/attach.php index fd418103d..fc146d008 100644 --- a/include/attach.php +++ b/include/attach.php @@ -2105,8 +2105,22 @@ function attach_store_item($channel, $observer, $file) { $arr['verb'] = ACTIVITY_CREATE; $arr['obj_type'] = $type; $arr['title'] = $file['filename']; - $body_str = sprintf(t('%s shared a %s with you'), '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]', '[zrl=' . $path . ']' . t('file') . '[/zrl]'); - $arr['body'] = $body_str; + + if ($type === 'Image') { + $arr['body'] = '[zrl=' . $path . '][zmg=' . $path . ']' . $file['display_path'] . '[/zmg][/zrl]'; + } + else { + $arr['attach'][] = [ + 'href' => z_root() . '/attach/' . $resource_id, + 'length' => $file['filesize'], + 'type' => $file['filetype'], + 'title' => urlencode($file['filename']), + 'revision' => $file['revision'] + ]; + } + + $body_str = sprintf((($type === 'Image') ? t('%s shared an %s with you') : t('%s shared a %s with you')), '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]', '[zrl=' . $path . ']' . (($type === 'Image') ? t('image') : t('file')) . '[/zrl]'); + $arr['body'] .= $body_str; $meta = [ 'name' => $file['filename'], diff --git a/include/auth.php b/include/auth.php index 4f4d26a6c..125aedffd 100644 --- a/include/auth.php +++ b/include/auth.php @@ -94,7 +94,7 @@ function account_verify_password($login, $pass) { $where = " where account_email = '" . dbesc($login) . "' "; } - $a = q("select * from account $where"); + $a = dbq("select * from account $where"); if(! $a) { return null; } @@ -112,6 +112,7 @@ function account_verify_password($login, $pass) { } if($channel) { + // Try the authentication plugin again since weve determined we are using the channel login instead of account login $addon_auth = [ 'username' => $account['account_email'], diff --git a/include/event.php b/include/event.php index 7c81d6934..b27504296 100644 --- a/include/event.php +++ b/include/event.php @@ -502,7 +502,6 @@ function ev_compare($a, $b) { function event_store_event($arr) { - $arr['created'] = $arr['created'] ?? datetime_convert(); $arr['edited'] = $arr['edited'] ?? datetime_convert(); $arr['etype'] = $arr['etype'] ?? 'event'; @@ -533,7 +532,7 @@ function event_store_event($arr) { $existing_event = null; - if(isset($arr['event_hash'])) { + if(isset($arr['event_hash']) && $arr['event_hash']) { $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", dbesc($arr['event_hash']), intval($arr['uid']) @@ -543,7 +542,7 @@ function event_store_event($arr) { } } - if(isset($arr['id'])) { + if(isset($arr['id']) && $arr['id']) { $r = q("SELECT * FROM event WHERE id = %d AND uid = %d LIMIT 1", intval($arr['id']), intval($arr['uid']) @@ -647,7 +646,6 @@ function event_store_event($arr) { $hash = random_string(48); } } - $r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,dtstart,dtend,summary,description,location,etype, adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, event_vdata, allow_cid,allow_gid,deny_cid,deny_gid) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' ) ", diff --git a/include/html2bbcode.php b/include/html2bbcode.php index 0aa067371..c928b91b1 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -171,6 +171,7 @@ function html2bbcode($message) node2bbcode($doc, 'i', array(), '[i]', '[/i]'); node2bbcode($doc, 'u', array(), '[u]', '[/u]'); node2bbcode($doc, 's', array(), '[s]', '[/s]'); + node2bbcode($doc, 'mark', array(), '[mark]', '[/mark]'); node2bbcode($doc, 'big', array(), "[size=large]", "[/size]"); node2bbcode($doc, 'small', array(), "[size=small]", "[/size]"); diff --git a/include/hubloc.php b/include/hubloc.php index bf5d8f120..0236e4ae7 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -79,9 +79,10 @@ function prune_hub_reinstalls() { $r = q("select site_url from site where site_type = %d", intval(SITE_TYPE_ZOT) ); + if($r) { foreach($r as $rr) { - $x = q("select count(*) as t, hubloc_sitekey, max(hubloc_connected) as c from hubloc where hubloc_url = '%s' group by hubloc_sitekey order by c", + $x = q("select count(*) as t, hubloc_sitekey, max(hubloc_connected) as c from hubloc where hubloc_url = '%s' and hubloc_network = 'zot6' group by hubloc_sitekey order by c", dbesc($rr['site_url']) ); @@ -155,8 +156,7 @@ function remove_obsolete_hublocs() { logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.'); - $interval = ((get_config('system', 'delivery_interval') !== false) - ? intval(get_config('system', 'delivery_interval')) : 2 ); + $interval = get_config('queueworker', 'queue_interval', 500000); foreach($r as $rr) { q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d", @@ -168,8 +168,10 @@ function remove_obsolete_hublocs() { ); if($x) { Master::Summon(array('Notifier', 'refresh_all', $x[0]['channel_id'])); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + + if($interval) { + usleep($interval); + } } } } diff --git a/include/items.php b/include/items.php index 752251a7e..891f16b7f 100644 --- a/include/items.php +++ b/include/items.php @@ -97,7 +97,6 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { $private_envelope = false; require_once('include/channel.php'); - //$sys = get_sys_channel(); if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') { @@ -114,7 +113,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { $r = $hookinfo['recipients']; } else { $r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 ", - intval($item['uid']) + intval($item['uid']) ); } @@ -141,18 +140,19 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { } } } -// we probably want to check that discovery channel delivery is allowed before uncommenting this. -// if($policy === 'pub') -// $recipients[] = $sys['xchan_hash']; } - // Forward to thread listeners, *unless* there is even a remote hint that the item - // might have some privacy attached. This could be (for instance) an ActivityPub DM + // Forward to thread listeners and pubstream (sys channel), *unless* there is even + // a remote hint that the item might have some privacy attached. + // This could be (for instance) an ActivityPub DM // in the middle of a public thread. Unless we can guarantee beyond all doubt that // this is public, don't allow it to go to thread listeners. if(! intval($item['item_private'])) { + $sys = get_sys_channel(); + $recipients[] = $sys['xchan_hash']; + $r = ThreadListener::fetch_by_target($item['parent_mid']); if($r) { foreach($r as $rv) { @@ -4124,21 +4124,24 @@ function posted_dates($uid,$wall) { */ function fetch_post_tags($items, $link = false) { - $tag_finder = array(); - if($items) { - foreach($items as $item) { - if(is_array($item)) { - if(array_key_exists('item_id',$item)) { - if(! in_array($item['item_id'],$tag_finder)) - $tag_finder[] = $item['item_id']; - } - else { - if(! in_array($item['id'],$tag_finder)) - $tag_finder[] = $item['id']; - } + if (!is_array($items) || !$items) { + return $items; + } + + $tag_finder = []; + foreach($items as $item) { + if(is_array($item)) { + if(array_key_exists('item_id',$item)) { + if(! in_array($item['item_id'],$tag_finder)) + $tag_finder[] = $item['item_id']; + } + else { + if(! in_array($item['id'],$tag_finder)) + $tag_finder[] = $item['id']; } } } + $tag_finder_str = implode(', ', $tag_finder); if(strlen($tag_finder_str)) { @@ -4599,10 +4602,11 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $items = array(); } + /** @FIXME finish mark unseen sql if ($parents_str && (isset($arr['mark_seen']) && $arr['mark_seen'])) { $update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )'; - /** @FIXME finish mark unseen sql */ } + */ } return $items; diff --git a/include/network.php b/include/network.php index 36859bc2f..f0642d8f7 100644 --- a/include/network.php +++ b/include/network.php @@ -1467,7 +1467,7 @@ function do_delivery($deliveries, $force = false) { if(! (is_array($deliveries) && count($deliveries))) return; - + /* $x = q("select count(outq_hash) as total from outq where outq_delivered = 0"); if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000)) && (! $force)) { logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); @@ -1476,10 +1476,10 @@ function do_delivery($deliveries, $force = false) { } return; } + */ - $interval = ((get_config('system','delivery_interval') !== false) - ? intval(get_config('system','delivery_interval')) : 2 ); + $interval = get_config('queueworker', 'queue_interval', 500000); $deliveries_per_process = intval(get_config('system','delivery_batch_count')); @@ -1487,7 +1487,7 @@ function do_delivery($deliveries, $force = false) { $deliveries_per_process = 1; - $deliver = array(); + $deliver = []; foreach($deliveries as $d) { if(! $d) @@ -1496,17 +1496,20 @@ function do_delivery($deliveries, $force = false) { $deliver[] = $d; if(count($deliver) >= $deliveries_per_process) { - Zotlabs\Daemon\Master::Summon(array('Deliver',$deliver)); - $deliver = array(); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + Zotlabs\Daemon\Master::Summon(['Deliver', $deliver]); + $deliver = []; + + if($interval) { + usleep($interval); + } } } // catch any stragglers - if($deliver) - Zotlabs\Daemon\Master::Summon(array('Deliver',$deliver)); + if($deliver) { + Zotlabs\Daemon\Master::Summon(['Deliver', $deliver]); + } } diff --git a/include/photos.php b/include/photos.php index de9cc6b13..6e00ffbf0 100644 --- a/include/photos.php +++ b/include/photos.php @@ -64,7 +64,7 @@ function photo_upload($channel, $observer, $args) { } $ac = $acl->get(); - +hz_syslog(print_r($ac,true)); $width = $height = 0; if ($args['getimagesize']) { @@ -405,7 +405,7 @@ function photo_upload($channel, $observer, $args) { } } - $attribution = (($visitor) ? $visitor['xchan_url'] : $channel['xchan_url']); + $attribution = (($visitor) ? $visitor : $channel['xchan_url']); //// Create item object $object = [ diff --git a/include/plugin.php b/include/plugin.php index ff5014c8b..ae73a847c 100644 --- a/include/plugin.php +++ b/include/plugin.php @@ -189,7 +189,7 @@ function plugin_is_installed($name) { function reload_plugins() { $plugins = get_config('system', 'addon'); if(strlen($plugins)) { - $r = q("SELECT * FROM addon WHERE installed = 1"); + $r = dbq("SELECT * FROM addon WHERE installed = 1"); if(count($r)) $installed = $r; else @@ -243,7 +243,7 @@ function reload_plugins() { function plugins_installed_list() { - $r = q("select * from addon where installed = 1 order by aname asc"); + $r = dbq("select * from addon where installed = 1 order by aname asc"); return(($r) ? ids_to_array($r,'aname') : []); } @@ -313,7 +313,7 @@ function plugins_sync() { */ function visible_plugin_list() { - $r = q("select * from addon where hidden = 0 order by aname asc"); + $r = dbq("select * from addon where hidden = 0 order by aname asc"); $x = (($r) ? ids_to_array($r,'aname') : array()); $y = []; if($x) { @@ -392,7 +392,7 @@ function load_hooks() { App::$hooks = []; - $r = q("SELECT * FROM hook WHERE true ORDER BY priority DESC"); + $r = dbq("SELECT * FROM hook WHERE true ORDER BY priority DESC"); if($r) { foreach($r as $rv) { @@ -613,6 +613,17 @@ function get_widget_info($widget){ "addon/$widget.php" ]; + $addons = plugins_installed_list(); + + if ($addons) { + foreach ($addons as $name) { + $path = 'addon/' . $name . '/Widget/' . $ucwidget . '.php'; + if (is_file($path)) { + $checkpaths[] = $path ; + } + } + } + $widget_found = false; foreach ($checkpaths as $path) { diff --git a/include/taxonomy.php b/include/taxonomy.php index 1eded055a..671f96c2e 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -322,7 +322,7 @@ function pubtagblock($net,$site,$limit,$recent = 0,$safemode = 1, $type = TERM_H if($r) { $o = '<div class="tagblock widget"><h3>' . (($recent) ? t('Trending') : t('Tags')) . '</h3><div class="tags" align="center">'; foreach($r as $rr) { - $o .= '<span class="tag'.$rr[2].'">#</span><a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; + $o .= '<span class="tag'.$rr[2].'">#</span><a href="'.$link . '?tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; } $o .= '</div></div>'; } @@ -335,53 +335,55 @@ function pub_tagadelic($net, $site, $limit, $recent, $safemode, $type) { $item_normal = item_normal(); $count = intval($limit); - $sql_extra = ""; - if($site) - $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 "; - else { - $sys = get_sys_channel(); - $uids = " and item.uid = " . intval($sys['channel_id']) . " "; - $sql_extra = " and item_private = 0 "; - } - - if($recent) - $sql_extra .= " and item.created > NOW() - INTERVAL " . db_quoteinterval(intval($recent) . ' DAY') . " "; - - - if($safemode) { - $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]); - if($unsafetags) { - $sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") "; - } - } - - $key = __FUNCTION__ . "-" . md5($site . $recent . $safemode . $limit . $type); - - $content = Cache::get($key, '5 MINUTE'); - if(! $content) { - - $content = Cache::get($key, '1 MONTH'); - $arr = [ - "SELECT term, count(term) AS total FROM term LEFT JOIN item ON term.oid = item.id - WHERE term.ttype = %d - AND otype = %d - AND item_type = %d - $sql_extra $uids $item_normal - GROUP BY term ORDER BY total DESC %s", - intval($type), - intval(TERM_OBJ_POST), - intval(ITEM_TYPE_POST), - (intval($count) ? "LIMIT $count" : '') - ]; - - \Zotlabs\Daemon\Master::Summon([ 'Cache_query', $key, base64_encode(json_encode($arr)) ]); + $sys = get_sys_channel(); + $uids = " and item.uid = " . intval($sys['channel_id']) . " "; + $sql_extra = item_permissions_sql($sys['channel_id']); + + $site_firehose_sql = ''; + + if ($site) { + $site_firehose_sql = " and owner_xchan in (select channel_hash from channel where channel_system = 0 and channel_removed = 0) "; + } + + if($recent) { + $sql_extra .= " and item.created > NOW() - INTERVAL " . db_quoteinterval(intval($recent) . ' DAY') . " "; + } + + if($safemode) { + $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]); + if($unsafetags) { + $sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") "; } + } + + $key = __FUNCTION__ . "-" . md5($site . $recent . $safemode . $limit . $type); - $r = unserialize($content); - if(! $r) - return []; + $content = Cache::get($key, '5 MINUTE'); + if(! $content) { - return Zotlabs\Text\Tagadelic::calc($r); + $content = Cache::get($key, '1 MONTH'); + $arr = [ + "SELECT term, count(term) AS total FROM term LEFT JOIN item ON term.oid = item.id + WHERE term.ttype = %d + AND otype = %d + AND item_type = %d + AND item_private = 0 + $uids $item_normal $site_firehose_sql $sql_extra + GROUP BY term ORDER BY total DESC %s", + intval($type), + intval(TERM_OBJ_POST), + intval(ITEM_TYPE_POST), + (intval($count) ? "LIMIT $count" : '') + ]; + + \Zotlabs\Daemon\Master::Summon([ 'Cache_query', $key, base64_encode(json_encode($arr)) ]); + } + + $r = unserialize($content); + if(! $r) + return []; + + return Zotlabs\Text\Tagadelic::calc($r); } diff --git a/include/text.php b/include/text.php index af6ad7ea2..35ce465d6 100644 --- a/include/text.php +++ b/include/text.php @@ -303,6 +303,7 @@ function purify_html($s, $allow_position = false) { $def->addElement('footer', 'Block', 'Flow', 'Common'); //Inline $def->addElement('button', 'Inline', 'Inline', 'Common'); + $def->addElement('mark', 'Inline', 'Inline', 'Common'); if($allow_position) { @@ -2969,7 +2970,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) $newname = substr($name,1); $newname = substr($newname,0,-1); - $r = q("SELECT * FROM xchan WHERE ( xchan_addr = '%s' OR xchan_url = '%s' ) AND xchan_deleted = 0", + $r = q("SELECT * FROM xchan LEFT JOIN hubloc ON hubloc_hash = xchan_hash WHERE ( xchan_addr = '%s' OR xchan_url = '%s' ) AND xchan_deleted = 0 AND NOT xchan_network IN ('rss', 'anon', 'unknown') ORDER BY hubloc_id DESC", dbesc($newname), dbesc($newname) ); @@ -2995,7 +2996,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) // select someone from this user's contacts by name $r = q("SELECT * FROM abook LEFT JOIN xchan ON abook_xchan = xchan_hash - WHERE xchan_name = '%s' AND abook_channel = %d AND xchan_deleted = 0", + WHERE xchan_name = '%s' AND abook_channel = %d AND xchan_deleted = 0 AND NOT xchan_network IN ('rss', 'anon', 'unknown')", dbesc($newname), intval($profile_uid) ); @@ -3004,7 +3005,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) if((! $r) && strpos($newname,'@')) { $r = q("SELECT * FROM xchan LEFT JOIN hubloc ON xchan_hash = hubloc_hash - WHERE hubloc_addr = '%s' AND xchan_deleted = 0 ", + WHERE hubloc_addr = '%s' AND xchan_deleted = 0 AND NOT xchan_network IN ('rss', 'anon', 'unknown') ORDER BY hubloc_id DESC", dbesc($newname) ); } @@ -3016,7 +3017,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) $newname = str_replace('%','',$newname); $r = q("SELECT * FROM abook LEFT JOIN xchan ON abook_xchan = xchan_hash - WHERE xchan_addr LIKE ('%s') AND abook_channel = %d AND xchan_deleted = 0", + WHERE xchan_addr LIKE ('%s') AND abook_channel = %d AND xchan_deleted = 0 AND NOT xchan_network IN ('rss', 'anon', 'unknown')", dbesc(((strpos($newname,'@')) ? $newname : $newname . '@%')), intval($profile_uid) ); diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql index 80ae20d7b..0f407960d 100644 --- a/install/schema_mysql.sql +++ b/install/schema_mysql.sql @@ -1232,7 +1232,7 @@ CREATE TABLE IF NOT EXISTS `verify` ( CREATE TABLE IF NOT EXISTS `vote` ( `vote_id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `vote_guid` varchar(191) NOT NULL, + `vote_guid` varchar(191) NOT NULL, `vote_poll` int(11) NOT NULL DEFAULT 0 , `vote_element` int(11) NOT NULL DEFAULT 0 , `vote_result` text NOT NULL, @@ -1616,3 +1616,17 @@ CREATE TABLE if not exists oauth_jwt ( subject VARCHAR(80), public_key VARCHAR(2000) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS workerq ( + workerq_id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + workerq_priority smallint, + workerq_reservationid varchar(25) DEFAULT NULL, + workerq_processtimeout datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + workerq_data text, + workerq_uuid char(36) NOT NULL DEFAULT '', + workerq_cmd varchar(191) NOT NULL DEFAULT '', + KEY workerq_priority (workerq_priority), + KEY workerq_reservationid (workerq_reservationid), + KEY workerq_processtimeout (workerq_uuid), + KEY workerq_uuid (workerq_processtimeout) +) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql index 96d0cc33c..5a97ebca1 100644 --- a/install/schema_postgres.sql +++ b/install/schema_postgres.sql @@ -1652,4 +1652,17 @@ CREATE TABLE oauth_jwt ( public_key VARCHAR(2000) NOT NULL ); - +CREATE TABLE IF NOT EXISTS workerq ( + workerq_id bigserial NOT NULL, + workerq_priority smallint, + workerq_reservationid varchar(25) DEFAULT NULL, + workerq_processtimeout timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', + workerq_data text, + workerq_uuid UUID NOT NULL, + workerq_cmd text NOT NULL DEFAULT '', + PRIMARY KEY (workerq_id) +) +CREATE INDEX idx_workerq_priority ON workerq (workerq_priority); +CREATE INDEX idx_workerq_reservationid ON workerq (workerq_reservationid); +CREATE INDEX idx_workerq_processtimeout ON workerq (workerq_processtimeout); +CREATE INDEX idx_workerq_uuid ON workerq (workerq_uuid); diff --git a/view/css/bootstrap-red.css b/view/css/bootstrap-red.css index b0bd4fd75..f1296d7b2 100644 --- a/view/css/bootstrap-red.css +++ b/view/css/bootstrap-red.css @@ -65,7 +65,3 @@ label { a { text-decoration: none !important; } - -.mark { - background-color: yellow; -} diff --git a/view/css/conversation.css b/view/css/conversation.css index 97d7857cc..d6a99f853 100644 --- a/view/css/conversation.css +++ b/view/css/conversation.css @@ -94,7 +94,6 @@ /* conversation */ - /* conv_item */ .wall-item-head-new { @@ -220,12 +219,6 @@ a.wall-item-name-link { border-left: 0.2rem solid #007bff; } -.item-highlight .wall-item-head, -.item-highlight .wall-item-content, -.item-highlight .wall-item-tools { - padding-left: 0.3rem; -} - /* comment_item */ diff --git a/view/fr/invite.formal.tpl b/view/fr/invite.formal.tpl index 404059af6..5d4d34caa 100644 --- a/view/fr/invite.formal.tpl +++ b/view/fr/invite.formal.tpl @@ -1,6 +1,6 @@ {{* tpl FR formel, pour inviter de manière plus polie des personnes comme des membres d'entreprise ou des partenaires professionnels *}}. -Veuillez rejoindre le réseau social {{$nom du projet}}. Ce message contient les données essentielles pour la première connexion. +Veuillez rejoindre le réseau social {{$projectname}}. Ce message contient les données essentielles pour la première connexion. Le site est à rejoindre se trouve ici : {{$invite_whereami}} diff --git a/view/js/mod_cloud.js b/view/js/mod_cloud.js index 7f9cb4fd1..e0f59beab 100644 --- a/view/js/mod_cloud.js +++ b/view/js/mod_cloud.js @@ -411,6 +411,9 @@ function UploadInit() { var filedrag = $(".cloud-index.attach-drop"); var reload = false; + if (!$('#invisible-cloud-file-upload').length) + return; + $('#invisible-cloud-file-upload').fileupload({ url: 'file_upload', dataType: 'json', diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index 20309b709..9069500d9 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -13,6 +13,7 @@ --bs-link-color: $link_colour; --bs-link-hover-color: $link_hover_colour; --bs-body-bg: $bgcolour; + --bs-highlight-bg: yellow; } .nav-tabs { @@ -1790,11 +1791,6 @@ dl.bb-dl > dd > li { opacity: 1; } -/* default highlighted text if not specified by schema: */ -span.default-highlight { - background-color: yellow; -} - .bootstrap-tagsinput { width: 100%; } diff --git a/view/tpl/admin_site.tpl b/view/tpl/admin_site.tpl index fa942baff..bad68361b 100644 --- a/view/tpl/admin_site.tpl +++ b/view/tpl/admin_site.tpl @@ -20,7 +20,7 @@ {{include file="field_input.tpl" field=$frontpage}} {{include file="field_checkbox.tpl" field=$mirror_frontpage}} {{include file="field_checkbox.tpl" field=$login_on_homepage}} - {{include file="field_checkbox.tpl" field=$enable_context_help}} + {{** include file="field_checkbox.tpl" field=$enable_context_help **}} {{if $directory_server}} {{include file="field_select.tpl" field=$directory_server}} {{/if}} @@ -72,10 +72,10 @@ {{include file="field_input.tpl" field=$proxy}} {{include file="field_input.tpl" field=$proxyuser}} {{include file="field_input.tpl" field=$timeout}} - {{include file="field_input.tpl" field=$delivery_interval}} + {{**include file="field_input.tpl" field=$delivery_interval**}} {{include file="field_input.tpl" field=$delivery_batch_count}} - {{include file="field_input.tpl" field=$force_queue}} - {{include file="field_input.tpl" field=$poll_interval}} + {{**include file="field_input.tpl" field=$force_queue**}} + {{**include file="field_input.tpl" field=$poll_interval**}} {{include file="field_input.tpl" field=$maxloadavg}} {{include file="field_input.tpl" field=$default_expire_days}} {{include file="field_input.tpl" field=$active_expire_days}} diff --git a/view/tpl/settings_account.tpl b/view/tpl/settings_account.tpl index c81f1abbb..2b942d694 100644 --- a/view/tpl/settings_account.tpl +++ b/view/tpl/settings_account.tpl @@ -8,6 +8,9 @@ <input type='hidden' name='form_security_token' value='{{$form_security_token}}'> <div class="section-content-tools-wrapper"> {{include file="field_input.tpl" field=$email}} + {{if $email_hidden}} + <input type='hidden' name='email' value='{{$email_hidden}}'> + {{/if}} {{include file="field_password.tpl" field=$origpass}} {{include file="field_password.tpl" field=$password1}} {{include file="field_password.tpl" field=$password2}} |