aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Lib/Activity.php34
-rw-r--r--Zotlabs/Lib/Enotify.php5
-rw-r--r--Zotlabs/Lib/Libsync.php8
-rw-r--r--Zotlabs/Lib/NativeWikiPage.php7
-rw-r--r--Zotlabs/Lib/ThreadItem.php4
-rw-r--r--Zotlabs/Module/Cdav.php531
-rw-r--r--Zotlabs/Module/Item.php61
-rw-r--r--Zotlabs/Module/Network.php24
-rw-r--r--Zotlabs/Module/Vote.php5
-rw-r--r--Zotlabs/Module/Well_known.php5
-rw-r--r--Zotlabs/Module/Z6trans.php130
-rw-r--r--Zotlabs/Widget/Activity_filter.php28
12 files changed, 574 insertions, 268 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 0d8dab95c..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) {
@@ -1691,7 +1719,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 +1738,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/Module/Z6trans.php b/Zotlabs/Module/Z6trans.php
new file mode 100644
index 000000000..98832ad98
--- /dev/null
+++ b/Zotlabs/Module/Z6trans.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @file Zotlabs/Module/Z6trans.php
+ *
+ * @brief replace all occurances of an zot xchan with the zot6 xchan in DB.
+ *
+ */
+
+namespace Zotlabs\Module;
+
+use Zotlabs\Web\Controller;
+
+class Z6trans extends Controller {
+
+ function get() {
+ if(!is_site_admin())
+ return 'Not Allowed';
+
+ $path = 'store/z6trans.sql';
+
+ $r = q("SELECT channel.channel_name, channel.channel_portable_id, xchan.xchan_network FROM channel
+ LEFT JOIN xchan ON channel_portable_id = xchan_hash
+ WHERE xchan.xchan_network = 'zot'
+ AND channel.channel_removed = 0"
+ );
+
+ $q = '';
+
+ foreach($r as $rr) {
+
+ $zot_xchan = $rr['channel_portable_id'];
+
+ $r = q("SELECT xchan_guid FROM xchan WHERE xchan_hash = '%s' AND xchan_network = 'zot'",
+ dbesc($zot_xchan)
+ );
+
+ if(!$r) {
+ $q .= '-- ' . $zot_xchan . 'failed: zot xchan not found' . "\r\n";
+ continue;
+ }
+
+ $guid = $r[0]['xchan_guid'];
+
+ $r = q("SELECT xchan_hash, xchan_guid_sig FROM xchan WHERE xchan_guid = '%s' AND xchan_network = 'zot6'",
+ dbesc($guid)
+ );
+
+ if(!$r) {
+ $q .= '-- ' . $zot_xchan . 'failed: zot6 xchan not found' . "\r\n";
+ continue;
+ }
+
+ $zot6_xchan = $r[0]['xchan_hash'];
+
+ $core = self::get_core_cols();
+
+ $q .= '-- Transforming ' . $rr['channel_name'] . "\r\n";
+
+ foreach($core as $table => $cols) {
+
+ foreach($cols as $col) {
+
+ $q .= sprintf("UPDATE %s SET %s = replace(%s, '%s', '%s');\r\n",
+ dbesc($table),
+ dbesc($col),
+ dbesc($col),
+ dbesc($zot_xchan),
+ dbesc($zot6_xchan)
+ );
+
+ }
+
+ }
+
+ }
+
+ if($q)
+ file_put_contents($path, $q);
+
+ $o = '<h2>' . t('Update to Hubzilla 5.0 setp 2') . '</h2><br>';
+
+ $o .= '<h3>' . t('To complete the update please run') . '</h3>';
+ if(ACTIVE_DBTYPE == DBTYPE_MYSQL)
+ $o .= '<code>source ' . $_SERVER["DOCUMENT_ROOT"] . '/' . $path . '</code><h3>from the mysql console.</h3>';
+ else
+ $o .= '<code>\i ' . $_SERVER["DOCUMENT_ROOT"] . '/' . $path . '</code><h3>from the postgresql console.</h3>';
+
+ $o .= '<br><h3>' . t('INFO: this command can take a very long time depending on your DB size.') . '</h3>';
+
+ return $o;
+
+ }
+
+ function get_core_cols() {
+
+ $core = [
+ 'abconfig' => ['xchan'],
+ 'abook' => ['abook_xchan'],
+ 'app' => ['app_author'],
+ 'attach' => ['creator', 'allow_cid', 'deny_cid'],
+ 'channel' => ['channel_allow_cid', 'channel_deny_cid'],
+ 'chat' => ['chat_xchan'],
+ 'chatpresence' => ['cp_xchan'],
+ 'chatroom' => ['allow_cid', 'deny_cid'],
+ 'config' => ['v'],
+ 'dreport' => ['dreport_recip', 'dreport_xchan'],
+ 'event' => ['event_xchan', 'allow_cid', 'deny_cid'],
+ 'iconfig' => ['v'],
+ 'item' => ['owner_xchan', 'author_xchan', 'source_xchan', 'route', 'allow_cid', 'deny_cid'],
+ 'mail' => ['from_xchan', 'to_xchan'],
+ 'menu_item' => ['allow_cid', 'deny_cid'],
+ 'obj' => ['allow_cid', 'deny_cid'],
+ 'pconfig' => ['v'],
+ 'pgrp_member' => ['xchan'],
+ 'photo' => ['xchan', 'allow_cid', 'deny_cid'],
+ 'source' => ['src_channel_xchan', 'src_xchan'],
+ 'updates' => ['ud_hash'],
+ 'xchat' => ['xchat_xchan'],
+ 'xconfig' => ['xchan', 'v'],
+ 'xign' => ['xchan'],
+ 'xlink' => ['xlink_xchan', 'xlink_link'],
+ 'xprof' => ['xprof_hash'],
+ 'xtag' => ['xtag_hash'],
+ ];
+
+ return $core;
+
+ }
+
+}
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())