diff options
Diffstat (limited to 'Zotlabs')
-rw-r--r-- | Zotlabs/Lib/Activity.php | 4 | ||||
-rw-r--r-- | Zotlabs/Lib/Enotify.php | 5 | ||||
-rw-r--r-- | Zotlabs/Lib/Libsync.php | 8 | ||||
-rw-r--r-- | Zotlabs/Lib/NativeWikiPage.php | 7 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 4 | ||||
-rw-r--r-- | Zotlabs/Module/Cdav.php | 531 | ||||
-rw-r--r-- | Zotlabs/Module/Item.php | 61 | ||||
-rw-r--r-- | Zotlabs/Module/Network.php | 24 | ||||
-rw-r--r-- | Zotlabs/Module/Vote.php | 5 | ||||
-rw-r--r-- | Zotlabs/Module/Well_known.php | 5 | ||||
-rw-r--r-- | Zotlabs/Widget/Activity_filter.php | 28 |
11 files changed, 415 insertions, 267 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 0d8dab95c..2f219af1f 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1691,7 +1691,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; } } @@ -1710,7 +1710,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; } } 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/Libsync.php b/Zotlabs/Lib/Libsync.php index b9e9bb38a..c39720735 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -244,7 +244,13 @@ 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('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/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) { 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'; diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index af40689c1..ac73b8a5b 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,79 @@ 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); + + 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($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) { + + $cdavdata = $this->get_cdav_data($x['id'], $cdavtable); + + $etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false); + + // delete + if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) + build_sync_packet($channel['channel_id'], [ + $sync => [ + 'action' => 'delete_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri + ] + ]); + else { + if($etag) { + // update + if($cdavdata['etag'] !== $etag) + build_sync_packet($channel['channel_id'], [ + $sync => [ + 'action' => 'update_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri, + 'card' => $httpbody + ] + ]); + } + else { + // new + build_sync_packet($channel['channel_id'], [ + $sync => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => [ $uri ], + 'card' => $httpbody + ] + ]); + } + } + } + } + } $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); @@ -262,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 @@ -272,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()); @@ -327,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(); } @@ -341,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 @@ -359,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()); @@ -407,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(); } @@ -418,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(); } @@ -433,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()); @@ -471,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(); } @@ -523,6 +652,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 @@ -533,21 +670,32 @@ class Cdav extends Controller { if(! cdav_perms($id,$addressbooks)) return; + $cdavdata = $this->get_cdav_data($id, 'addressbooks'); + $mutations = [ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] ]; $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 +717,21 @@ class Cdav extends Controller { 'N' => array_reverse(explode(' ', $fn)) ]); - $org = $_REQUEST['org']; - if($org) { - $vcard->ORG = $org; - } - - $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++; - } - } + $fields = $this->request_to_array($_REQUEST); - $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,9 +739,11 @@ class Cdav extends Controller { $id = $_REQUEST['target']; - 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); @@ -670,113 +755,23 @@ class Cdav extends Controller { $vcard->N = array_reverse(explode(' ', $fn)); } - $org = $_REQUEST['org']; - if($org) { - $vcard->ORG = $org; - } - else { - unset($vcard->ORG); - } - - $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); - } + $fields = $this->request_to_array($_REQUEST); - $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 +779,22 @@ class Cdav extends Controller { $id = $_REQUEST['target']; - 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); + + build_sync_packet($channel['channel_id'], [ + 'addressbook' => [ + 'action' => 'delete_card', + 'uri' => $cdavdata['uri'], + 'carduri' => $uri + ] + ]); } } @@ -799,6 +804,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 +819,42 @@ 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)); + $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']) { - $id[] = intval($_REQUEST['target']); + $id = intval($_REQUEST['target']); $ext = 'vcf'; $table = 'cards'; $column = 'addressbookid'; - $objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src)); + $sync = 'addressbook'; + $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( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL . - '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . - '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . - '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL - ); - } - - if($_REQUEST['a_upload']) { - notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL . - '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . - '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL - ); - } - } - } + + $ids = []; + import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true); + + build_sync_packet($channel['channel_id'], [ + $sync => [ + 'action' => 'import', + 'uri' => $cdavdata['uri'], + 'ids' => $ids, + 'card' => $carddata + ] + ]); } @unlink($src); } @@ -1190,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(); } @@ -1201,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(); } @@ -1408,7 +1403,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 +1467,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; + } } 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; + + } + + } 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/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']); 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'); 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()) |