From 3df5d854b8935b11c67893bbbd24cdf8829eda00 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Wed, 29 Jan 2020 14:29:06 -0800 Subject: z6 transition work - prevent z6 sync packets from being unpacked into an incompatible schema --- Zotlabs/Lib/Libsync.php | 4 ++-- Zotlabs/Lib/Libzot.php | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index d93270bc5..b9e9bb38a 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -83,7 +83,7 @@ class Libsync { $info = (($packet) ? $packet : array()); $info['type'] = 'sync'; - $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific + $info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ]; if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) { @@ -144,7 +144,7 @@ class Libsync { foreach($synchubs as $hub) { $hash = random_string(); - $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']); + $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']); Queue::insert(array( 'hash' => $hash, 'account_id' => $channel['channel_account_id'], diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index ad00aa97a..bb70dfbf2 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1277,7 +1277,12 @@ class Libzot { logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); - $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); + if ($env['encoding'] === 'hz') { + $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); + } + else { + logger('sync packet type not supported.'); + } } } if ($result) { -- cgit v1.2.3 From 2c42daf6090ba8d0e3a50b8350ea5a3750891b68 Mon Sep 17 00:00:00 2001 From: Zot Date: Thu, 30 Jan 2020 20:06:15 +0100 Subject: z6 compat work --- Zotlabs/Lib/Libsync.php | 4 ++-- Zotlabs/Lib/Libzot.php | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index d93270bc5..b9e9bb38a 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -83,7 +83,7 @@ class Libsync { $info = (($packet) ? $packet : array()); $info['type'] = 'sync'; - $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific + $info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ]; if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) { @@ -144,7 +144,7 @@ class Libsync { foreach($synchubs as $hub) { $hash = random_string(); - $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']); + $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']); Queue::insert(array( 'hash' => $hash, 'account_id' => $channel['channel_account_id'], diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index ad00aa97a..bb70dfbf2 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1277,7 +1277,12 @@ class Libzot { logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); - $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); + if ($env['encoding'] === 'hz') { + $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); + } + else { + logger('sync packet type not supported.'); + } } } if ($result) { -- cgit v1.2.3 From 8ed3971ef05be4015b65c9a5b721954c7767ba22 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 30 Jan 2020 20:18:25 +0100 Subject: Prevent multiple database requests on name platform check --- Zotlabs/Lib/System.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index 7bf1343bb..3f500486c 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -5,9 +5,14 @@ namespace Zotlabs\Lib; class System { static public function get_platform_name() { - if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system'])) - return \App::$config['system']['platform_name']; - return PLATFORM_NAME; + + if(! isset($platform_name)) { + if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system'])) + static $platform_name = \App::$config['system']['platform_name']; + else + static $platform_name = PLATFORM_NAME; + } + return $platform_name; } static public function get_site_name() { -- cgit v1.2.3 From 5e76318e44d682ce631aa575550ce666eff2ea79 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 30 Jan 2020 20:28:55 +0100 Subject: Update System.php --- Zotlabs/Lib/System.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index 3f500486c..b66f66bce 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -6,11 +6,12 @@ class System { static public function get_platform_name() { - if(! isset($platform_name)) { + static $platform_name = ''; + if(empty($platform_name)) { if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system'])) - static $platform_name = \App::$config['system']['platform_name']; + $platform_name = \App::$config['system']['platform_name']; else - static $platform_name = PLATFORM_NAME; + $platform_name = PLATFORM_NAME; } return $platform_name; } -- cgit v1.2.3 From b37e5a426abee519f20a9cec557538bde3841ad8 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 30 Jan 2020 20:36:00 +0100 Subject: Update System.php --- Zotlabs/Lib/System.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index b66f66bce..3cc46fbda 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -5,8 +5,7 @@ namespace Zotlabs\Lib; class System { static public function get_platform_name() { - - static $platform_name = ''; + static $platform_name = ''; if(empty($platform_name)) { if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system'])) $platform_name = \App::$config['system']['platform_name']; -- cgit v1.2.3 From 989443a5698adf5e7a93f874048699526aa103a7 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Thu, 30 Jan 2020 15:56:33 -0800 Subject: basic poll support and patch to not call System::get_platform_name() within t() unless needed. Polls probably need refining and have not yet been fully tested after porting --- Zotlabs/Lib/Activity.php | 45 +++++++++++++++-- Zotlabs/Module/Item.php | 63 ++++++++++++++++++++++- Zotlabs/Module/Vote.php | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 Zotlabs/Module/Vote.php (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 43315a87f..66b1ee4b8 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -813,6 +813,10 @@ class Activity { static function activity_mapper($verb) { + if ($verb === 'Answer') { + return 'Note'; + } + if(strpos($verb,'/') === false) { return $verb; } @@ -932,10 +936,6 @@ class Activity { static function activity_obj_mapper($obj) { - if(strpos($obj,'/') === false) { - return $obj; - } - $objs = [ 'http://activitystrea.ms/schema/1.0/note' => 'Note', 'http://activitystrea.ms/schema/1.0/comment' => 'Note', @@ -956,6 +956,15 @@ class Activity { call_hooks('activity_obj_mapper',$objs); + if ($obj === 'Answer') { + return 'Note'; + } + + if (strpos($obj,'/') === false) { + return $obj; + } + + if(array_key_exists($obj,$objs)) { return $objs[$obj]; } @@ -1644,6 +1653,13 @@ class Activity { $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); } + if ($act->type === 'Note' && $act->obj['type'] === 'Question' && $act->data['name']) { + $s['mid'] = $act->id; + $s['parent_mid'] = $act->obj['id']; + $s['replyto'] = $act->replyto; + $s['verb'] = 'Answer'; + $content['content'] = EMPTY_STR; + } if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) { @@ -1711,6 +1727,15 @@ class Activity { $s['verb'] = self::activity_decode_mapper($act->type); + if ($act->type === 'Note' && $act->obj['type'] === 'Question' && $act->data['name'] && ! $content['content']) { + $s['verb'] = 'Answer'; + $s['title'] = purify_html($act->data['name']); + } + + // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. + if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) { + $s['edited'] = datetime_convert(); + } if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { $s['item_deleted'] = 1; @@ -1798,6 +1823,18 @@ class Activity { } + if ($act->obj['type'] === 'Question' && in_array($act->type,['Create','Update'])) { + if ($act->obj['endTime']) { + $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['endTime']); + } + } + + if ($act->obj['closed']) { + $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['closed']); + } + + + // we will need a hook here to extract magnet links e.g. peertube // right now just link to the largest mp4 we find that will fit in our // standard content region diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 1a25e54df..8b4bbae91 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -718,7 +718,14 @@ class Item extends Controller { // BBCODE alert: the following functions assume bbcode input // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) // we may need virtual or template classes to implement the possible alternatives - + + $obj = $this->extract_poll_data($body); + if ($obj) { + $datarray['obj'] = $obj; + $obj_type = 'Question'; + } + + if(strpos($body,'[/summary]') !== false) { $match = ''; @@ -1387,5 +1394,57 @@ class Item extends Controller { return $ret; } - + function extract_poll_data(&$body) { + + $multiple = false; + + if (strpos($body,'[/question]') === false && strpos($body,'[/answer]') === false) { + return false; + } + if (strpos($body,'[nobb]') !== false) { + return false; + } + + + $obj = []; + $ptr = []; + $matches = null; + $obj['type'] = 'Question'; + + if (preg_match_all('/\[answer\](.*?)\[\/answer\]/',$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); + } + } + + $matches = null; + + if (preg_match('/\[question\](.*?)\[\/question\]/',$body,$matches)) { + $obj['content'] = bbcode($matches[1]); + $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['oneOf'] = $ptr; + } + + $matches = null; + + if (preg_match('/\[question=multiple\](.*?)\[\/question\]/',$body,$matches)) { + $obj['content'] = bbcode($matches[1]); + $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['anyOf'] = $ptr; + } + + $matches = null; + + if (preg_match('/\[ends\](.*?)\[\/ends\]',$body,$matches)) { + $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); + $body = str_replace('[ends]' . $match[1] . '[/ends]', EMPTY_STR, $body); + } + + return $obj; + + } + + + } diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php new file mode 100644 index 000000000..52d6a4bea --- /dev/null +++ b/Zotlabs/Module/Vote.php @@ -0,0 +1,129 @@ + false, 'message' => EMPTY_STR ]; + + $channel = App::get_channel(); + + if (! $channel) { + $ret['message'] = t('Permission denied.'); + json_return_and_die($ret); + } + + + $fetch = null; + $id = argv(1); + $response = $_REQUEST['answer']; + + if ($id) { + $fetch = q("select * from item where id = %d limit 1", + intval($id) + ); + } + + + if ($fetch && $fetch[0]['obj_type'] === 'Question') { + $obj = json_decode($fetch[0]['obj'],true); + + } + else { + $ret['message'] = t('Poll not found.'); + json_return_and_die($ret); + } + + $valid = false; + + if ($obj['oneOf']) { + foreach($obj['oneOf'] as $selection) { + // logger('selection: ' . $selection); + // logger('response: ' . $response); + if($selection['name'] && $selection['name'] === $response) { + $valid = true; + } + } + } + + $choices = []; + if ($obj['anyOf']) { + foreach ($obj['anyOf'] as $selection) { + $choices[] = $selection['name']; + } + foreach ($response as $res) { + if (! in_array($res,$choices)) { + $valid = false; + break; + } + $valid = true; + } + } + + if (! $valid) { + $ret['message'] = t('Invalid response.'); + json_return_and_die($ret); + } + + if (! is_array($response)) { + $response = [ $response ]; + } + + foreach ($response as $res) { + + $item = []; + + + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item['item_origin'] = true; + $item['parent'] = $fetch[0]['id']; + $item['parent_mid'] = $fetch[0]['mid']; + $item['uuid'] = new_uuid(); + $item['mid'] = z_root() . '/item/' . $item['uuid']; + $item['verb'] = 'Answer'; + $item['title'] = $res; + $item['author_xchan'] = $channel['channel_hash']; + $item['owner_xchan'] = $fetch[0]['author_xchan']; + + $item['obj'] = $obj; + $item['obj_type'] = 'Question'; + + $x = item_store($item); + + retain_item($fetch[0]['id']); + + if($x['success']) { + $itemid = $x['item_id']; + Master::Summon( [ 'Notifier', 'like', $itemid ] ); + } + + $r = q("select * from item where id = %d", + intval($itemid) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]); + } + } + $ret['success'] = true; + $ret['message'] = t('Response submitted. Updates may not appear instantly.'); + json_return_and_die($ret); + } +} + + + + + + + + -- cgit v1.2.3 From 6838342d625236a05695d73efd99f1afdab67d96 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 31 Jan 2020 10:29:20 +0000 Subject: =?UTF-8?q?fix=20php=20warning=C3=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zotlabs/Module/Item.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 8b4bbae91..21d59fbc1 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -1436,7 +1436,7 @@ class Item extends Controller { $matches = null; - if (preg_match('/\[ends\](.*?)\[\/ends\]',$body,$matches)) { + if (preg_match('/\[ends\](.*?)\[\/ends\]/',$body,$matches)) { $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); $body = str_replace('[ends]' . $match[1] . '[/ends]', EMPTY_STR, $body); } -- cgit v1.2.3 From fc9e6d289acf30f89da0051a90cbf16f0bc006fb Mon Sep 17 00:00:00 2001 From: zotlabs Date: Fri, 31 Jan 2020 12:51:23 -0800 Subject: missing piece of poll code --- Zotlabs/Lib/Activity.php | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 66b1ee4b8..edc65d8e9 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1615,6 +1615,73 @@ class Activity { } + + static function update_poll($item,$mid,$content) { + $multi = false; + if (! $item) { + return false; + } + + $o = json_decode($item['obj'],true); + if ($o && array_key_exists('anyOf',$o)) { + $multi = true; + } + $answer_found = false; + $found = false; + if ($multi) { + for ($c = 0; $c < count($o['anyOf']); $c ++) { + if ($o['anyOf'][$c]['name'] === $content) { + $answer_found = true; + if (is_array($o['anyOf'][$c]['replies'])) { + foreach($o['anyOf'][$c]['replies'] as $reply) { + if(array_key_exists('id',$reply) && $reply['id'] === $mid) { + $found = true; + } + } + } + + if (! $found) { + $o['anyOf'][$c]['replies']['totalItems'] ++; + $o['anyOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ]; + } + } + } + } + else { + for ($c = 0; $c < count($o['oneOf']); $c ++) { + if ($o['oneOf'][$c]['name'] === $content) { + $answer_found = true; + if (is_array($o['oneOf'][$c]['replies'])) { + foreach($o['oneOf'][$c]['replies'] as $reply) { + if(array_key_exists('id',$reply) && $reply['id'] === $mid) { + $found = true; + } + } + } + + if (! $found) { + $o['oneOf'][$c]['replies']['totalItems'] ++; + $o['oneOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ]; + } + } + } + } + logger('updated_poll: ' . print_r($o,true),LOGGER_DATA); + if ($answer_found && ! $found) { + $x = q("update item set obj = '%s', edited = '%s' where id = %d", + dbesc(json_encode($o)), + dbesc(datetime_convert()), + intval($item['id']) + ); + Master::Summon( [ 'Notifier', 'wall-new', $item['id'] ] ); + return true; + } + + return false; + } + + + static function decode_note($act) { $response_activity = false; -- cgit v1.2.3 From bbcb237f5b996e94af37611152105b2e965ea493 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Sun, 9 Feb 2020 16:32:18 -0800 Subject: poll updates --- Zotlabs/Lib/Activity.php | 44 +++++++++++++++++++++++++------------------- Zotlabs/Lib/Libzot.php | 12 +++++++++++- Zotlabs/Module/Item.php | 27 +++++++++++++++++---------- Zotlabs/Module/Vote.php | 18 ++++++++++++++---- 4 files changed, 67 insertions(+), 34 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index edc65d8e9..06aa3b931 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -325,6 +325,22 @@ class Activity { $ret['type'] = $objtype; + if ($objtype === 'Question') { + if ($i['obj']) { + if (is_array($i['obj'])) { + $ret = $i['obj']; + } + else { + $ret = json_decode($i['obj'],true); + } + + if(array_path_exists('actor/id',$ret)) { + $ret['actor'] = $ret['actor']['id']; + } + } + } + + $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid'])); if($i['title']) @@ -813,10 +829,6 @@ class Activity { static function activity_mapper($verb) { - if ($verb === 'Answer') { - return 'Note'; - } - if(strpos($verb,'/') === false) { return $verb; } @@ -916,7 +928,6 @@ class Activity { 'http://purl.org/zot/activity/file' => 'zot:File', 'http://purl.org/zot/activity/mood' => 'zot:Mood', 'Invite' => 'Invite', - ]; call_hooks('activity_obj_decode_mapper',$objs); @@ -1720,14 +1731,6 @@ class Activity { $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); } - if ($act->type === 'Note' && $act->obj['type'] === 'Question' && $act->data['name']) { - $s['mid'] = $act->id; - $s['parent_mid'] = $act->obj['id']; - $s['replyto'] = $act->replyto; - $s['verb'] = 'Answer'; - $content['content'] = EMPTY_STR; - } - if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) { $response_activity = true; @@ -1794,11 +1797,6 @@ class Activity { $s['verb'] = self::activity_decode_mapper($act->type); - if ($act->type === 'Note' && $act->obj['type'] === 'Question' && $act->data['name'] && ! $content['content']) { - $s['verb'] = 'Answer'; - $s['title'] = purify_html($act->data['name']); - } - // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) { $s['edited'] = datetime_convert(); @@ -2190,7 +2188,7 @@ class Activity { set_iconfig($item,'activitypub','recips',$act->raw_recips); if(! $is_parent) { - $p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1", + $p = q("select parent_mid, id, obj_type from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($item['uid']) ); @@ -2220,6 +2218,14 @@ class Activity { // $s['thr_parent'] = $s['mid']; } } + + if ($p[0]['obj_type'] === 'Question') { + if ($item['obj_type'] === ACTIVITY_OBJ_NOTE && $item['title'] && (! $item['content'])) { + $item['obj_type'] = 'Answer'; + } + } + + if($p[0]['parent_mid'] !== $item['parent_mid']) { $item['thr_parent'] = $item['parent_mid']; } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index bb70dfbf2..2776a681e 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1613,7 +1613,7 @@ class Libzot { // As a side effect we will also do a preliminary check that we have the top-level-post, otherwise // processing it is pointless. - $r = q("select route, id, owner_xchan, item_private from item where mid = '%s' and uid = %d limit 1", + $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", dbesc($arr['parent_mid']), intval($channel['channel_id']) ); @@ -1639,6 +1639,16 @@ class Libzot { continue; } + if ($r[0]['obj_type'] === 'Question') { + // route checking doesn't work correctly here because we've changed the privacy + $r[0]['route'] = EMPTY_STR; + // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type + if ($arr['obj_type'] === ACTIVITY_OBJ_NOTE && $arr['title'] && (! $arr['content'])) { + $arr['obj_type'] = 'Answer'; + } + } + + if($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) { // reset the route in case it travelled a great distance upstream // use our parent's route so when we go back downstream we'll match diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 21d59fbc1..e55192c7f 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -719,14 +719,6 @@ class Item extends Controller { // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) // we may need virtual or template classes to implement the possible alternatives - $obj = $this->extract_poll_data($body); - if ($obj) { - $datarray['obj'] = $obj; - $obj_type = 'Question'; - } - - - if(strpos($body,'[/summary]') !== false) { $match = ''; $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match); @@ -928,6 +920,13 @@ class Item extends Controller { $mid = z_root() . '/item/' . $uuid; } + $obj = $this->extract_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + if ($obj) { + $obj['url'] = $mid; + $obj['attributedTo'] = channel_url($channel); + $datarray['obj'] = $obj; + $obj_type = 'Question'; + } if(! $parent_mid) { $parent_mid = $mid; @@ -1394,7 +1393,7 @@ class Item extends Controller { return $ret; } - function extract_poll_data(&$body) { + function extract_poll_data(&$body,$item) { $multiple = false; @@ -1438,7 +1437,15 @@ class Item extends Controller { if (preg_match('/\[ends\](.*?)\[\/ends\]/',$body,$matches)) { $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); - $body = str_replace('[ends]' . $match[1] . '[/ends]', EMPTY_STR, $body); + $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); + } + + + if ($item['item_private']) { + $obj['to'] = Activity::map_acl($item); + } + else { + $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; } return $obj; diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index 52d6a4bea..2c31d84dc 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -88,15 +88,25 @@ class Vote extends Controller { $item['parent_mid'] = $fetch[0]['mid']; $item['uuid'] = new_uuid(); $item['mid'] = z_root() . '/item/' . $item['uuid']; - $item['verb'] = 'Answer'; + $item['verb'] = 'Create'; $item['title'] = $res; $item['author_xchan'] = $channel['channel_hash']; $item['owner_xchan'] = $fetch[0]['author_xchan']; - $item['obj'] = $obj; - $item['obj_type'] = 'Question'; + $item['obj_type'] = 'Note'; + $item['author'] = channelx_by_n($channel['channel_id']); + + $item['obj'] = Activity::encode_item($item,true); + + // now reset the placeholders + + $item['obj_type'] = 'Answer'; + unset($item['author']); + + + $x = item_store($item); + - $x = item_store($item); retain_item($fetch[0]['id']); -- cgit v1.2.3 From a39d436f9f46138db623ee3c9ddef2c501ea8bd2 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 10 Feb 2020 20:37:35 +0000 Subject: poll fixes --- Zotlabs/Lib/Activity.php | 7 ++++++- Zotlabs/Lib/Libzot.php | 2 +- Zotlabs/Module/Vote.php | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 06aa3b931..5a406beb7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -928,6 +928,7 @@ class Activity { 'http://purl.org/zot/activity/file' => 'zot:File', 'http://purl.org/zot/activity/mood' => 'zot:Mood', 'Invite' => 'Invite', + 'Question' => 'Question' ]; call_hooks('activity_obj_decode_mapper',$objs); @@ -962,7 +963,8 @@ class Activity { 'http://purl.org/zot/activity/thing' => 'Object', 'http://purl.org/zot/activity/file' => 'zot:File', 'http://purl.org/zot/activity/mood' => 'zot:Mood', - 'Invite' => 'Invite', + 'Invite' => 'Invite', + 'Question' => 'Question' ]; call_hooks('activity_obj_mapper',$objs); @@ -1806,6 +1808,8 @@ class Activity { $s['item_deleted'] = 1; } + + $s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']); if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { $s['obj_type'] = ACTIVITY_OBJ_COMMENT; @@ -2219,6 +2223,7 @@ class Activity { } } + if ($p[0]['obj_type'] === 'Question') { if ($item['obj_type'] === ACTIVITY_OBJ_NOTE && $item['title'] && (! $item['content'])) { $item['obj_type'] = 'Answer'; diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 2776a681e..d64421926 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1643,7 +1643,7 @@ class Libzot { // route checking doesn't work correctly here because we've changed the privacy $r[0]['route'] = EMPTY_STR; // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type - if ($arr['obj_type'] === ACTIVITY_OBJ_NOTE && $arr['title'] && (! $arr['content'])) { + if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (! $arr['body'])) { $arr['obj_type'] = 'Answer'; } } diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index 2c31d84dc..e1932da23 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -86,6 +86,7 @@ class Vote extends Controller { $item['item_origin'] = true; $item['parent'] = $fetch[0]['id']; $item['parent_mid'] = $fetch[0]['mid']; + $item['thr_parent'] = $fetch[0]['mid']; $item['uuid'] = new_uuid(); $item['mid'] = z_root() . '/item/' . $item['uuid']; $item['verb'] = 'Create'; @@ -96,10 +97,11 @@ class Vote extends Controller { $item['obj_type'] = 'Note'; $item['author'] = channelx_by_n($channel['channel_id']); - $item['obj'] = Activity::encode_item($item,true); + $item['obj'] = Activity::encode_item($item); // now reset the placeholders + $item['verb'] = ACTIVITY_POST; $item['obj_type'] = 'Answer'; unset($item['author']); @@ -107,7 +109,6 @@ class Vote extends Controller { $x = item_store($item); - retain_item($fetch[0]['id']); if($x['success']) { -- cgit v1.2.3 From d4a6aa7801d7bad862436990418a7aba34ddef1f Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 10 Feb 2020 15:34:33 -0800 Subject: this allows polls to federate from hubzilla to zap, though still a remaining issue with voting --- Zotlabs/Lib/Activity.php | 11 +++++++++-- Zotlabs/Module/Item.php | 6 +++++- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 5a406beb7..1ac3135db 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -592,8 +592,15 @@ class Activity { } } - - $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid'])); + if (strpos($i['mid'],z_root() . '/item/') !== false) { + $ret['id'] = str_replace('/item/','/activity/',$i['mid']); + } + elseif (strpos($i['mid'],z_root() . '/event/') !== false) { + $ret['id'] = str_replace('/event/','/activity/',$i['mid']); + } + else { + $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid'])); + } if($i['title']) $ret['name'] = html2plain(bbcode($i['title'], [ 'cache' => true ])); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index e55192c7f..dbcbe5d22 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -976,7 +976,11 @@ class Item extends Controller { $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid); $plink = substr($plink,0,190); } - + + if ($datarray['obj']) { + $datarray['obj']['id'] = $mid; + } + $datarray['aid'] = $channel['channel_account_id']; $datarray['uid'] = $profile_uid; $datarray['uuid'] = $uuid; -- cgit v1.2.3 From bf7c96807a50433b7241ddf6df9e01d4ef11f43d Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 10 Feb 2020 18:17:41 -0800 Subject: fix poll responses --- Zotlabs/Daemon/Notifier.php | 12 +++++++++++- Zotlabs/Lib/Libzot.php | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 1d0be10d9..00c6fb077 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -3,6 +3,7 @@ namespace Zotlabs\Daemon; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Activity; require_once('include/queue_fn.php'); require_once('include/html2plain.php'); @@ -366,9 +367,18 @@ class Notifier { $activity = json_decode($m,true); } else { - $activity = \Zotlabs\Lib\Activity::encode_activity($target_item); + $activity = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + z_root() . ZOT_APSCHEMA_REV + ]], Activity::encode_activity($target_item) + ); } + logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG); + logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG); + + // Send comments to the owner to re-deliver to everybody in the conversation // We only do this if the item in question originated on this site. This prevents looping. // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay. diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index d64421926..42e706754 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1617,6 +1617,7 @@ class Libzot { dbesc($arr['parent_mid']), intval($channel['channel_id']) ); + if(! $r) { $DR->update('comment parent not found'); $result[] = $DR->get(); -- cgit v1.2.3 From 9f029336cab322e04d29af842ba0a666189c8683 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 11 Feb 2020 09:20:32 +0000 Subject: fix notifications for polls --- Zotlabs/Lib/Enotify.php | 5 +++-- Zotlabs/Lib/ThreadItem.php | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index f6f8ad0cb..85e90d67c 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -810,8 +810,9 @@ class Enotify { } else { $itemem_text = (($item['item_thread_top']) - ? t('created a new post') - : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]')); + ? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post')) + : (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]')) + ); if($item['verb'] === ACTIVITY_SHARE) { $itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]'); diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 2386a1f0d..dee7cda56 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -204,6 +204,10 @@ class ThreadItem { } } + if($item['obj_type'] === 'Question') { + $response_verbs[] = 'answer'; + } + $consensus = (intval($item['item_consensus']) ? true : false); if($consensus) { $response_verbs[] = 'agree'; -- cgit v1.2.3 From 83256c9ccd2cf3cff74ac10c0ea8e46cb9f77aca Mon Sep 17 00:00:00 2001 From: zotlabs Date: Wed, 12 Feb 2020 14:17:28 -0800 Subject: issue with multi-line poll elements --- Zotlabs/Module/Item.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index dbcbe5d22..4b866eace 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -1414,7 +1414,7 @@ class Item extends Controller { $matches = null; $obj['type'] = 'Question'; - if (preg_match_all('/\[answer\](.*?)\[\/answer\]/',$body,$matches,PREG_SET_ORDER)) { + 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); @@ -1423,7 +1423,7 @@ class Item extends Controller { $matches = null; - if (preg_match('/\[question\](.*?)\[\/question\]/',$body,$matches)) { + if (preg_match('/\[question\](.*?)\[\/question\]/ism',$body,$matches)) { $obj['content'] = bbcode($matches[1]); $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); $obj['oneOf'] = $ptr; @@ -1431,7 +1431,7 @@ class Item extends Controller { $matches = null; - if (preg_match('/\[question=multiple\](.*?)\[\/question\]/',$body,$matches)) { + if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) { $obj['content'] = bbcode($matches[1]); $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); $obj['anyOf'] = $ptr; @@ -1439,7 +1439,7 @@ class Item extends Controller { $matches = null; - if (preg_match('/\[ends\](.*?)\[\/ends\]/',$body,$matches)) { + if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) { $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); } -- cgit v1.2.3 From 7d05b8e5fdcf628f6badaff60c73811dcc19e45c Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 20 Feb 2020 17:16:14 +0000 Subject: vote issue --- Zotlabs/Module/Vote.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index e1932da23..d67a6f176 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -83,7 +83,7 @@ class Vote extends Controller { $item['aid'] = $channel['channel_account_id']; $item['uid'] = $channel['channel_id']; - $item['item_origin'] = true; + $item['item_origin'] = 1; $item['parent'] = $fetch[0]['id']; $item['parent_mid'] = $fetch[0]['mid']; $item['thr_parent'] = $fetch[0]['mid']; @@ -93,6 +93,9 @@ class Vote extends Controller { $item['title'] = $res; $item['author_xchan'] = $channel['channel_hash']; $item['owner_xchan'] = $fetch[0]['author_xchan']; + $item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>'; + $item['item_private'] = 1; + $item['obj_type'] = 'Note'; $item['author'] = channelx_by_n($channel['channel_id']); -- cgit v1.2.3 From b7bac45427a400275597faa9b51c4d277fe1f5c7 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 20 Feb 2020 20:03:50 +0100 Subject: Revert "Use argv() instead URI parsing" This reverts commit bcfb69eeeef6a0506a0ec0574a03b673df84a55a --- Zotlabs/Lib/Libsync.php | 5 +- Zotlabs/Module/Cdav.php | 417 +++++++++++++++++++++--------------------------- 2 files changed, 187 insertions(+), 235 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index b9e9bb38a..d1756cf47 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -244,7 +244,10 @@ class Libsync { if(array_key_exists('app',$arr) && $arr['app']) sync_apps($channel,$arr['app']); - + + if(array_key_exists('addressbook',$arr) && $arr['addressbook']) + sync_addressbook($channel,$arr['addressbook']); + if(array_key_exists('chatroom',$arr) && $arr['chatroom']) sync_chatrooms($channel,$arr['chatroom']); diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index af40689c1..593a78a53 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -10,6 +10,7 @@ require_once('include/event.php'); require_once('include/auth.php'); require_once('include/security.php'); +require_once('include/cdav.php'); class Cdav extends Controller { @@ -156,6 +157,69 @@ class Cdav extends Controller { } } + + // Track CDAV updates from remote clients + + $httpmethod = $_SERVER['REQUEST_METHOD']; + + if($httpmethod === 'PUT' || $httpmethod === 'DELETE') { + + $httpuri = $_SERVER['REQUEST_URI']; + + logger("debug: method: " . $httpmethod, LOGGER_DEBUG); + logger("debug: uri: " . $httpuri, LOGGER_DEBUG); + + // currently we process CardDAV requests only + if(strpos($httpuri, 'cdav/addressbooks')) { + + $uri = basename($httpuri); + $httpbody = file_get_contents('php://input'); + + logger("debug: body: " . $httpbody, LOGGER_DEBUG); + + if($id = get_cdav_id($principalUri, explode("/", $httpuri)[4], 'addressbooks')) { + + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + + $etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false); + + // delete + if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'delete_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri + ] + ]); + else { + if($etag) { + // update + if($cdavdata['etag'] !== $etag) + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'update_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri, + 'card' => $httpbody + ] + ]); + } + else { + // new + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => [ $uri ], + 'card' => $httpbody + ] + ]); + } + } + } + } + } $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); @@ -523,6 +587,14 @@ class Cdav extends Controller { $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); + + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'create', + 'uri' => $addressbookUri, + 'properties' => $properties + ] + ]); } //edit addressbook @@ -530,6 +602,8 @@ class Cdav extends Controller { $id = $_REQUEST['id']; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + if(! cdav_perms($id,$addressbooks)) return; @@ -538,16 +612,24 @@ class Cdav extends Controller { ]; $patch = new \Sabre\DAV\PropPatch($mutations); - $carddavBackend->updateAddressBook($id, $patch); - $patch->commit(); + + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'edit', + 'uri' => $cdavdata['uri'], + 'mutations' => $mutations, + ] + ]); } //create addressbook card if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { $id = $_REQUEST['target']; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + do { $duplicate = false; $uri = random_string(40) . '.vcf'; @@ -569,86 +651,22 @@ class Cdav extends Controller { 'N' => array_reverse(explode(' ', $fn)) ]); - $org = $_REQUEST['org']; - if($org) { - $vcard->ORG = $org; - } + $fields = $this->request_to_array($_REQUEST); - $title = $_REQUEST['title']; - if($title) { - $vcard->TITLE = $title; - } - - $tel = $_REQUEST['tel']; - $tel_type = $_REQUEST['tel_type']; - if($tel) { - $i = 0; - foreach($tel as $item) { - if($item) { - $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); - } - $i++; - } - } - - $email = $_REQUEST['email']; - $email_type = $_REQUEST['email_type']; - if($email) { - $i = 0; - foreach($email as $item) { - if($item) { - $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); - } - $i++; - } - } - - $impp = $_REQUEST['impp']; - $impp_type = $_REQUEST['impp_type']; - if($impp) { - $i = 0; - foreach($impp as $item) { - if($item) { - $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); - } - $i++; - } - } - - $url = $_REQUEST['url']; - $url_type = $_REQUEST['url_type']; - if($url) { - $i = 0; - foreach($url as $item) { - if($item) { - $vcard->add('URL', $item, ['type' => $url_type[$i]]); - } - $i++; - } - } - - $adr = $_REQUEST['adr']; - $adr_type = $_REQUEST['adr_type']; - - if($adr) { - $i = 0; - foreach($adr as $item) { - if($item) { - $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); - } - $i++; - } - } - - $note = $_REQUEST['note']; - if($note) { - $vcard->NOTE = $note; - } + process_cdav_card($fields, $vcard); $cardData = $vcard->serialize(); $carddavBackend->createCard($id, $uri, $cardData); + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => [ $uri ], + 'card' => $cardData + ] + ]); } //edit addressbook card @@ -656,6 +674,8 @@ class Cdav extends Controller { $id = $_REQUEST['target']; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + if(!cdav_perms($id,$addressbooks)) return; @@ -670,113 +690,23 @@ class Cdav extends Controller { $vcard->N = array_reverse(explode(' ', $fn)); } - $org = $_REQUEST['org']; - if($org) { - $vcard->ORG = $org; - } - else { - unset($vcard->ORG); - } + $fields = $this->request_to_array($_REQUEST); - $title = $_REQUEST['title']; - if($title) { - $vcard->TITLE = $title; - } - else { - unset($vcard->TITLE); - } - - $tel = $_REQUEST['tel']; - $tel_type = $_REQUEST['tel_type']; - if($tel) { - $i = 0; - unset($vcard->TEL); - foreach($tel as $item) { - if($item) { - $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->TEL); - } - - $email = $_REQUEST['email']; - $email_type = $_REQUEST['email_type']; - if($email) { - $i = 0; - unset($vcard->EMAIL); - foreach($email as $item) { - if($item) { - $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->EMAIL); - } - - $impp = $_REQUEST['impp']; - $impp_type = $_REQUEST['impp_type']; - if($impp) { - $i = 0; - unset($vcard->IMPP); - foreach($impp as $item) { - if($item) { - $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->IMPP); - } - - $url = $_REQUEST['url']; - $url_type = $_REQUEST['url_type']; - if($url) { - $i = 0; - unset($vcard->URL); - foreach($url as $item) { - if($item) { - $vcard->add('URL', $item, ['type' => $url_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->URL); - } - - $adr = $_REQUEST['adr']; - $adr_type = $_REQUEST['adr_type']; - if($adr) { - $i = 0; - unset($vcard->ADR); - foreach($adr as $item) { - if($item) { - $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->ADR); - } - - $note = $_REQUEST['note']; - if($note) { - $vcard->NOTE = $note; - } - else { - unset($vcard->NOTE); - } + process_cdav_card($fields, $vcard, true); $cardData = $vcard->serialize(); $carddavBackend->updateCard($id, $uri, $cardData); + + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'update_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri, + 'card' => $cardData + ] + ]); + } //delete addressbook card @@ -784,12 +714,22 @@ class Cdav extends Controller { $id = $_REQUEST['target']; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + if(!cdav_perms($id,$addressbooks)) return; $uri = $_REQUEST['uri']; $carddavBackend->deleteCard($id, $uri); + + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'delete_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri + ] + ]); } } @@ -799,6 +739,8 @@ class Cdav extends Controller { $src = $_FILES['userfile']['tmp_name']; if($src) { + + $carddata = @file_get_contents($src); if($_REQUEST['c_upload']) { if($_REQUEST['target'] == 'channel_calendar') { @@ -812,76 +754,39 @@ class Cdav extends Controller { return; } - $id = explode(':', $_REQUEST['target']); + $id = explode(':', $_REQUEST['target'])[0]; $ext = 'ics'; $table = 'calendarobjects'; $column = 'calendarid'; - $objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src)); + $objects = new \Sabre\VObject\Splitter\ICalendar($carddata); $profile = \Sabre\VObject\Node::PROFILE_CALDAV; $backend = new \Sabre\CalDAV\Backend\PDO($pdo); } if($_REQUEST['a_upload']) { - $id[] = intval($_REQUEST['target']); + $id = intval($_REQUEST['target']); $ext = 'vcf'; $table = 'cards'; $column = 'addressbookid'; - $objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src)); + $objects = new \Sabre\VObject\Splitter\VCard($carddata); $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; $backend = new \Sabre\CardDAV\Backend\PDO($pdo); + + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); } - - while ($object = $objects->getNext()) { - - if($_REQUEST['a_upload']) { - $object = $object->convert(\Sabre\VObject\Document::VCARD40); - } - - $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR); - - //level 3 Means that the document is invalid, - //level 2 means a warning. A warning means it's valid but it could cause interopability issues, - //level 1 means that there was a problem earlier, but the problem was automatically repaired. - - if($ret[0]['level'] < 3) { - do { - $duplicate = false; - $objectUri = random_string(40) . '.' . $ext; - - $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1", - dbesc($id[0]), - dbesc($objectUri) - ); - - if (count($r)) - $duplicate = true; - } while ($duplicate == true); - - if($_REQUEST['c_upload']) { - $backend->createCalendarObject($id, $objectUri, $object->serialize()); - } - - if($_REQUEST['a_upload']) { - $backend->createCard($id[0], $objectUri, $object->serialize()); - } - } - else { - if($_REQUEST['c_upload']) { - notice( '' . t('INVALID EVENT DISMISSED!') . '' . EOL . - '' . t('Summary: ') . '' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . - '' . t('Date: ') . '' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . - '' . t('Reason: ') . '' . $ret[0]['message'] . EOL - ); - } - - if($_REQUEST['a_upload']) { - notice( '' . t('INVALID CARD DISMISSED!') . '' . EOL . - '' . t('Name: ') . '' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . - '' . t('Reason: ') . '' . $ret[0]['message'] . EOL - ); - } - } - } + + $ids = []; + import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true); + + if(isset($cdavdata)) + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => $ids, + 'card' => $carddata + ] + ]); } @unlink($src); } @@ -1408,7 +1313,19 @@ class Cdav extends Controller { if(! cdav_perms($id,$addressbooks)) return; + // get metadata before we delete it + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $carddavBackend->deleteAddressBook($id); + + if($cdavdata) + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'drop', + 'uri' => $cdavdata['uri'] + ] + ]); + killme(); } @@ -1460,4 +1377,36 @@ class Cdav extends Controller { } + function get_cdav_data($id, $table) { + + $r = q("SELECT * FROM $table WHERE id = %d LIMIT 1", + intval($id) + ); + + if(! $r) + return false; + + return $r[0]; + } + + function request_to_array($req) { + + $f = []; + + $f['org'] = $req['org']; + $f['title'] = $req['title']; + $f['tel'] = $req['tel']; + $f['tel_type'] = $req['tel_type']; + $f['email'] = $req['email']; + $f['email_type'] = $req['email_type']; + $f['impp'] = $req['impp']; + $f['impp_type'] = $req['impp_type']; + $f['url'] = $req['url']; + $f['url_type'] = $req['url_type']; + $f['adr'] = $req['adr']; + $f['adr_type'] = $req['adr_type']; + $f['note'] = $req['note']; + + return $f; + } } -- cgit v1.2.3 From 60311eb04bc0fa564b9fbe179eb907989ff09d8f Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 20 Feb 2020 21:25:41 +0000 Subject: fix warning --- Zotlabs/Lib/Activity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 1ac3135db..5cb111381 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1654,7 +1654,7 @@ class Activity { $answer_found = true; if (is_array($o['anyOf'][$c]['replies'])) { foreach($o['anyOf'][$c]['replies'] as $reply) { - if(array_key_exists('id',$reply) && $reply['id'] === $mid) { + if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) { $found = true; } } @@ -1673,7 +1673,7 @@ class Activity { $answer_found = true; if (is_array($o['oneOf'][$c]['replies'])) { foreach($o['oneOf'][$c]['replies'] as $reply) { - if(array_key_exists('id',$reply) && $reply['id'] === $mid) { + if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) { $found = true; } } -- cgit v1.2.3 From 9d97cc2a1d28cd201912870a5342e7eaf9285491 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 21 Feb 2020 10:44:26 +0000 Subject: implement optional events and polls filter --- Zotlabs/Module/Network.php | 24 +++++++++++++++++++----- Zotlabs/Widget/Activity_filter.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index a8efd0d9e..adfdc011b 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -340,7 +340,7 @@ class Network extends \Zotlabs\Web\Controller { // The special div is needed for liveUpdate to kick in for this page. // We only launch liveUpdate if you aren't filtering in some incompatible // way and also you aren't writing a comment (discovered in javascript). - + $maxheight = get_pconfig(local_channel(),'system','network_divmore_height'); if(! $maxheight) $maxheight = 400; @@ -411,10 +411,24 @@ class Network extends \Zotlabs\Web\Controller { } } - if($verb) { - $sql_extra .= sprintf(" AND item.verb like '%s' ", - dbesc(protect_sprintf('%' . $verb . '%')) - ); + if ($verb) { + + // the presence of a leading dot in the verb determines + // whether to match the type of activity or the child object. + // The name 'verb' is a holdover from the earlier XML + // ActivityStreams specification. + + if (substr($verb,0,1) === '.') { + $verb = substr($verb,1); + $sql_extra .= sprintf(" AND item.obj_type like '%s' ", + dbesc(protect_sprintf('%' . $verb . '%')) + ); + } + else { + $sql_extra .= sprintf(" AND item.verb like '%s' ", + dbesc(protect_sprintf('%' . $verb . '%')) + ); + } } if(strlen($file)) { diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php index 0fc60ca9b..002a642cb 100644 --- a/Zotlabs/Widget/Activity_filter.php +++ b/Zotlabs/Widget/Activity_filter.php @@ -22,6 +22,13 @@ class Activity_filter { $filter_active = 'dm'; } + if(x($_GET,'verb')) { + $events_active = (($_GET['verb'] == '.Event') ? 'active' : ''); + $polls_active = (($_GET['verb'] == '.Question') ? 'active' : ''); + $filter_active = (($events_active) ? 'events' : 'polls'); + } + + $tabs[] = [ 'label' => t('Direct Messages'), 'icon' => 'envelope-o', @@ -30,6 +37,27 @@ class Activity_filter { 'title' => t('Show direct (private) messages') ]; + if(feature_enabled(local_channel(),'events_tab')) { + $tabs[] = [ + 'label' => t('Events'), + 'icon' => 'calendar', + 'url' => z_root() . '/' . $cmd . '/?verb=%2EEvent', + 'sel' => $events_active, + 'title' => t('Show posts that include events') + ]; + } + + if(feature_enabled(local_channel(),'polls_tab')) { + $tabs[] = [ + 'label' => t('Polls'), + 'icon' => 'bar-chart', + 'url' => z_root() . '/' . $cmd . '/?verb=%2EQuestion', + 'sel' => $polls_active, + 'title' => t('Show posts that include polls') + ]; + } + + if(Apps::system_app_installed(local_channel(), 'Privacy Groups')) { $groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval(local_channel()) -- cgit v1.2.3 From 85cf25a2a8bfbbfe10de485d4affd54626fbbfa4 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Sun, 23 Feb 2020 15:28:16 -0800 Subject: add iconfig to zot6 objects --- Zotlabs/Lib/Activity.php | 52 ++++++++++++++++++++++++++++++++++++++++----- Zotlabs/Module/Apschema.php | 5 ++++- 2 files changed, 51 insertions(+), 6 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 1ac3135db..0d8dab95c 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -504,10 +504,47 @@ class Activity { } } } + if ($item['iconfig']) { + foreach ($item['iconfig'] as $att) { + if ($att['sharing']) { + $value = ((preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']); + $ret[] = [ 'type' => 'PropertyValue', 'name' => 'zot.' . $att['cat'] . '.' . $att['k'], 'value' => $value ]; + } + } + } return $ret; } + static function decode_iconfig($item) { + + $ret = []; + + if (is_array($item['attachment']) && $item['attachment']) { + $ptr = $item['attachment']; + if (! array_key_exists(0,$ptr)) { + $ptr = [ $ptr ]; + } + foreach ($ptr as $att) { + $entry = []; + if ($att['type'] === 'PropertyValue') { + if (array_key_exists('name',$att) && $att['name']) { + $key = explode('.',$att['name']); + if (count($key) === 3 && $key[0] === 'zot') { + $entry['cat'] = $key[1]; + $entry['k'] = $key[2]; + $entry['v'] = $att['value']; + $entry['sharing'] = '1'; + $ret[] = $entry; + } + } + } + } + } + return $ret; + } + + static function decode_attachment($item) { @@ -1888,17 +1925,22 @@ class Activity { } } - $a = self::decode_attachment($act->obj); - if($a) { - $s['attach'] = $a; - } + } + + $a = self::decode_attachment($act->obj); + if ($a) { + $s['attach'] = $a; + } + + $a = self::decode_iconfig($act->obj); + if ($a) { + $s['iconfig'] = $a; } if($act->obj['type'] === 'Note' && $s['attach']) { $s['body'] .= self::bb_attach($s['attach'],$s['body']); } - if ($act->obj['type'] === 'Question' && in_array($act->type,['Create','Update'])) { if ($act->obj['endTime']) { $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['endTime']); diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php index 756057a8a..6b0325d44 100644 --- a/Zotlabs/Module/Apschema.php +++ b/Zotlabs/Module/Apschema.php @@ -29,7 +29,10 @@ class Apschema extends \Zotlabs\Web\Controller { 'emojiReaction' => 'zot:emojiReaction', 'expires' => 'zot:expires', 'directMessage' => 'zot:directMessage', - + 'schema' => 'http://schema.org#', + 'PropertyValue' => 'schema:PropertyValue', + 'value' => 'schema:value', + 'magicEnv' => [ '@id' => 'zot:magicEnv', '@type' => '@id' -- cgit v1.2.3 From 989fbe70cd566da4c5757527aa77022036af6274 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Mon, 24 Feb 2020 10:02:09 +0100 Subject: Implement DAV calendars sync with clones --- Zotlabs/Lib/Libsync.php | 5 +- Zotlabs/Module/Cdav.php | 156 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 127 insertions(+), 34 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index d1756cf47..c39720735 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -246,7 +246,10 @@ class Libsync { sync_apps($channel,$arr['app']); if(array_key_exists('addressbook',$arr) && $arr['addressbook']) - sync_addressbook($channel,$arr['addressbook']); + sync_addressbook($channel,$arr['addressbook']); + + if(array_key_exists('calendar',$arr) && $arr['calendar']) + sync_calendar($channel,$arr['calendar']); if(array_key_exists('chatroom',$arr) && $arr['chatroom']) sync_chatrooms($channel,$arr['chatroom']); diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index 593a78a53..ac73b8a5b 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -169,24 +169,34 @@ class Cdav extends Controller { logger("debug: method: " . $httpmethod, LOGGER_DEBUG); logger("debug: uri: " . $httpuri, LOGGER_DEBUG); - // currently we process CardDAV requests only if(strpos($httpuri, 'cdav/addressbooks')) { + $sync = 'addressbook'; + $cdavtable = 'addressbooks'; + } + elseif(strpos($httpuri, 'cdav/calendars')) { + $sync = 'calendar'; + $cdavtable = 'calendarinstances'; + } + else + $sync = false; + + if($sync) { $uri = basename($httpuri); $httpbody = file_get_contents('php://input'); logger("debug: body: " . $httpbody, LOGGER_DEBUG); - if($id = get_cdav_id($principalUri, explode("/", $httpuri)[4], 'addressbooks')) { + if($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) { - $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $cdavdata = $this->get_cdav_data($x['id'], $cdavtable); $etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false); // delete if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) build_sync_packet($channel['channel_id'], [ - 'addressbook' => [ + $sync => [ 'action' => 'delete_card', 'uri' => $cdavdata['uri'], 'carduri' => $uri @@ -197,7 +207,7 @@ class Cdav extends Controller { // update if($cdavdata['etag'] !== $etag) build_sync_packet($channel['channel_id'], [ - 'addressbook' => [ + $sync => [ 'action' => 'update_card', 'uri' => $cdavdata['uri'], 'carduri' => $uri, @@ -208,7 +218,7 @@ class Cdav extends Controller { else { // new build_sync_packet($channel['channel_id'], [ - 'addressbook' => [ + $sync => [ 'action' => 'import', 'uri' => $cdavdata['uri'], 'ids' => [ $uri ], @@ -326,6 +336,14 @@ class Cdav extends Controller { // set new calendar to be visible set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); + + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'create', + 'uri' => $calendarUri, + 'properties' => $properties + ] + ]); } //create new calendar object via ajax request @@ -336,6 +354,8 @@ class Cdav extends Controller { if(!cdav_perms($id[0],$calendars,true)) return; + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : ''); $tz = (($timezone) ? $timezone : date_default_timezone_get()); @@ -391,9 +411,17 @@ class Cdav extends Controller { $vcalendar->VEVENT->DTSTART['TZID'] = $tz; $calendarData = $vcalendar->serialize(); - $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => [ $objectUri ], + 'card' => $calendarData + ] + ]); + killme(); } @@ -405,17 +433,24 @@ class Cdav extends Controller { if(! cdav_perms($id[0],$calendars)) return; + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $mutations = [ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'] ]; $patch = new \Sabre\DAV\PropPatch($mutations); - $caldavBackend->updateCalendar($id, $patch); - $patch->commit(); + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'edit', + 'uri' => $cdavdata['uri'], + 'mutations' => $mutations, + ] + ]); } //edit calendar object via ajax request @@ -423,9 +458,11 @@ class Cdav extends Controller { $id = explode(':', $_REQUEST['target']); - if(!cdav_perms($id[0],$calendars,true)) + if(! cdav_perms($id[0],$calendars,true)) return; + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : ''); $tz = (($timezone) ? $timezone : date_default_timezone_get()); @@ -471,9 +508,17 @@ class Cdav extends Controller { $vcalendar->VEVENT->LOCATION = $location; $calendarData = $vcalendar->serialize(); - $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'update_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri, + 'card' => $calendarData + ] + ]); + killme(); } @@ -482,13 +527,23 @@ class Cdav extends Controller { $id = explode(':', $_REQUEST['target']); - if(!cdav_perms($id[0],$calendars,true)) + if(! cdav_perms($id[0],$calendars,true)) return; + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $uri = $_REQUEST['uri']; $caldavBackend->deleteCalendarObject($id, $uri); + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'delete_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri + ] + ]); + killme(); } @@ -497,9 +552,11 @@ class Cdav extends Controller { $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; - if(!cdav_perms($id[0],$calendars,true)) + if(! cdav_perms($id[0],$calendars,true)) return; + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : ''); $tz = (($timezone) ? $timezone : date_default_timezone_get()); @@ -535,9 +592,17 @@ class Cdav extends Controller { unset($vcalendar->VEVENT->DTEND); $calendarData = $vcalendar->serialize(); - $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'update_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri, + 'card' => $calendarData + ] + ]); + killme(); } @@ -602,11 +667,11 @@ class Cdav extends Controller { $id = $_REQUEST['id']; - $cdavdata = $this->get_cdav_data($id, 'addressbooks'); - if(! cdav_perms($id,$addressbooks)) return; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $mutations = [ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] ]; @@ -626,6 +691,7 @@ class Cdav extends Controller { //create addressbook card if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { + $id = $_REQUEST['target']; $cdavdata = $this->get_cdav_data($id, 'addressbooks'); @@ -656,7 +722,6 @@ class Cdav extends Controller { process_cdav_card($fields, $vcard); $cardData = $vcard->serialize(); - $carddavBackend->createCard($id, $uri, $cardData); build_sync_packet($channel['channel_id'], [ @@ -674,11 +739,11 @@ class Cdav extends Controller { $id = $_REQUEST['target']; - $cdavdata = $this->get_cdav_data($id, 'addressbooks'); - - if(!cdav_perms($id,$addressbooks)) + if(! cdav_perms($id,$addressbooks)) return; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $uri = $_REQUEST['uri']; $object = $carddavBackend->getCard($id, $uri); @@ -714,11 +779,11 @@ class Cdav extends Controller { $id = $_REQUEST['target']; - $cdavdata = $this->get_cdav_data($id, 'addressbooks'); - - if(!cdav_perms($id,$addressbooks)) + if(! cdav_perms($id,$addressbooks)) return; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $uri = $_REQUEST['uri']; $carddavBackend->deleteCard($id, $uri); @@ -758,9 +823,12 @@ class Cdav extends Controller { $ext = 'ics'; $table = 'calendarobjects'; $column = 'calendarid'; + $sync = 'calendar'; $objects = new \Sabre\VObject\Splitter\ICalendar($carddata); $profile = \Sabre\VObject\Node::PROFILE_CALDAV; $backend = new \Sabre\CalDAV\Backend\PDO($pdo); + + $cdavdata = $this->get_cdav_data($id, 'calendarinstances'); } if($_REQUEST['a_upload']) { @@ -768,6 +836,7 @@ class Cdav extends Controller { $ext = 'vcf'; $table = 'cards'; $column = 'addressbookid'; + $sync = 'addressbook'; $objects = new \Sabre\VObject\Splitter\VCard($carddata); $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; $backend = new \Sabre\CardDAV\Backend\PDO($pdo); @@ -778,15 +847,14 @@ class Cdav extends Controller { $ids = []; import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true); - if(isset($cdavdata)) - build_sync_packet($channel['channel_id'], [ - 'addressbook' => [ - 'action' => 'import', - 'uri' => $cdavdata['uri'], - 'ids' => $ids, - 'card' => $carddata - ] - ]); + build_sync_packet($channel['channel_id'], [ + $sync => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => $ids, + 'card' => $carddata + ] + ]); } @unlink($src); } @@ -1095,7 +1163,18 @@ class Cdav extends Controller { if(! cdav_perms($id,$calendars)) killme(); - set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4)); + $cdavdata = $this->get_cdav_data($id, 'calendarinstances'); + + set_pconfig(local_channel(), 'cdav_calendar', $id, argv(4)); + + build_sync_packet(local_channel(), [ + 'calendar' => [ + 'action' => 'switch', + 'uri' => $cdavdata['uri'], + 'switch' => intval(argv(4)) + ] + ]); + killme(); } @@ -1106,7 +1185,18 @@ class Cdav extends Controller { if(! cdav_perms($id[0],$calendars)) killme(); + // get metadata before we delete it + $cdavdata = $this->get_cdav_data($id[0], 'calendarinstances'); + $caldavBackend->deleteCalendar($id); + + build_sync_packet($channel['channel_id'], [ + 'calendar' => [ + 'action' => 'drop', + 'uri' => $cdavdata['uri'] + ] + ]); + killme(); } -- cgit v1.2.3 From 8bcdc24fcbb308f052d996291f5ef0b8f4b606f1 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Mon, 24 Feb 2020 11:38:23 +0100 Subject: Code reuse --- Zotlabs/Module/Well_known.php | 5 ----- 1 file changed, 5 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Well_known.php b/Zotlabs/Module/Well_known.php index 140ab260d..0d7b222b8 100644 --- a/Zotlabs/Module/Well_known.php +++ b/Zotlabs/Module/Well_known.php @@ -65,11 +65,6 @@ class Well_known extends \Zotlabs\Web\Controller { killme(); case 'caldav': - if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') { - http_status('301', 'moved permanently'); - goaway(z_root() . '/cdav'); - }; - case 'carddav': if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') { http_status('301', 'moved permanently'); -- cgit v1.2.3 From e7f25b84664c158343621c391b8653042d5be53c Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 26 Feb 2020 09:51:40 +0000 Subject: implement poll UI in jot --- Zotlabs/Module/Item.php | 61 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 4b866eace..86b5c1c7a 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -271,7 +271,9 @@ class Item extends Controller { $consensus = intval($_REQUEST['consensus']); $nocomment = intval($_REQUEST['nocomment']); - + + $is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false); + // 'origin' (if non-zero) indicates that this network is where the message originated, // for the purpose of relaying comments to other conversation members. // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset. @@ -920,7 +922,21 @@ class Item extends Controller { $mid = z_root() . '/item/' . $uuid; } - $obj = $this->extract_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + + if($is_poll) { + $poll = [ + 'question' => $body, + 'answers' => $_REQUEST['poll_answers'], + 'multiple_answers' => $_REQUEST['poll_multiple_answers'], + 'expire_value' => $_REQUEST['poll_expire_value'], + 'expire_unit' => $_REQUEST['poll_expire_unit'] + ]; + $obj = $this->extract_poll_data($poll, [ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + } + else { + $obj = $this->extract_bb_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); + } + if ($obj) { $obj['url'] = $mid; $obj['attributedTo'] = channel_url($channel); @@ -1397,7 +1413,7 @@ class Item extends Controller { return $ret; } - function extract_poll_data(&$body,$item) { + function extract_bb_poll_data(&$body,$item) { $multiple = false; @@ -1457,5 +1473,44 @@ class Item extends Controller { } + function extract_poll_data($poll, $item) { + + $multiple = intval($poll['multiple_answers']); + $expire_value = intval($poll['expire_value']); + $expire_unit = $poll['expire_unit']; + $question = $poll['question']; + $answers = $poll['answers']; + + $obj = []; + $ptr = []; + $obj['type'] = 'Question'; + $obj['content'] = bbcode($question); + + foreach($answers as $answer) { + if(trim($answer)) + $ptr[] = [ 'name' => escape_tags($answer), 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]]; + } + + if($multiple) { + $obj['anyOf'] = $ptr; + } + else { + $obj['oneOf'] = $ptr; + } + + $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME); + + if ($item['item_private']) { + $obj['to'] = Activity::map_acl($item); + } + else { + $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + } + + return $obj; + + } + + } -- cgit v1.2.3 From c74c41c3b88669802c96c565f04b2682a54d43e9 Mon Sep 17 00:00:00 2001 From: BattleMage Date: Thu, 27 Feb 2020 11:44:51 +0100 Subject: Allow wiki link titles Allow linking to wiki pages with alternating titles by separating the title from the link with a pipe, like regular wiki markup does. --- Zotlabs/Lib/NativeWikiPage.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php index dddd26af3..d84cc50a8 100644 --- a/Zotlabs/Lib/NativeWikiPage.php +++ b/Zotlabs/Lib/NativeWikiPage.php @@ -530,8 +530,11 @@ class NativeWikiPage { foreach ($match[1] as $m) { // TODO: Why do we need to double urlencode for this to work? //$pageURLs[] = urlencode(urlencode(escape_tags($m))); - $pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($m)); - $pages[] = $m; + $titleUri = explode('|',$m); + $page = $titleUri[0] ?? ''; + $title = $titleUri[1] ?? $page; + $pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($page)); + $pages[] = $title; } $idx = 0; while(strpos($s,'[[') !== false) { -- cgit v1.2.3 From 06f2979e04db2c5eb7e10bc4967d750209a4cc73 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 29 Feb 2020 10:25:22 +0000 Subject: prevent duplicate votes --- Zotlabs/Lib/Activity.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 2f219af1f..02ec7614e 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1673,8 +1673,11 @@ class Activity { - static function update_poll($item,$mid,$content) { + static function update_poll($item,$post) { $multi = false; + $mid = $post['mid']; + $content = $post['title']; + if (! $item) { return false; } @@ -1683,6 +1686,31 @@ class Activity { if ($o && array_key_exists('anyOf',$o)) { $multi = true; } + + $r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s'", + dbesc($item['mid']), + dbesc($post['author_xchan']) + ); + + // prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf + + if ($r) { + if ($multi) { + foreach ($r as $rv) { + if ($rv['title'] === $content && $rv['mid'] !== $mid) { + return false; + } + } + } + else { + foreach ($r as $rv) { + if ($rv['mid'] !== $mid) { + return false; + } + } + } + } + $answer_found = false; $found = false; if ($multi) { -- cgit v1.2.3