From cbc417114da142ca82f55676272ca2b7337f615c Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Fri, 26 Oct 2018 04:13:26 +0000
Subject: [PATCH] AP: We now transmit and process events

---
 src/Protocol/ActivityPub/Processor.php   | 37 ++++++++++++++++++
 src/Protocol/ActivityPub/Receiver.php    | 11 +++++-
 src/Protocol/ActivityPub/Transmitter.php | 48 +++++++++++++++++++-----
 3 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php
index 8a80bd2be..e7073ab87 100644
--- a/src/Protocol/ActivityPub/Processor.php
+++ b/src/Protocol/ActivityPub/Processor.php
@@ -10,6 +10,7 @@ use Friendica\Model\Conversation;
 use Friendica\Model\Contact;
 use Friendica\Model\APContact;
 use Friendica\Model\Item;
+use Friendica\Model\Event;
 use Friendica\Model\User;
 use Friendica\Content\Text\HTML;
 use Friendica\Util\JsonLD;
@@ -172,6 +173,38 @@ class Processor
 		self::postItem($activity, $item);
 	}
 
+	/**
+	 * Create an event
+	 *
+	 * @param array  $activity Activity array
+	 */
+	public static function createEvent($activity, $item)
+	{
+		$event['summary'] = $activity['name'];
+		$event['desc'] = $activity['content'];
+		$event['start'] = $activity['start-time'];
+		$event['finish'] = $activity['end-time'];
+		$event['nofinish'] = empty($event['finish']);
+		$event['location'] = $activity['location'];
+		$event['adjust'] = true;
+		$event['cid'] = $item['contact-id'];
+		$event['uid'] = $item['uid'];
+		$event['uri'] = $item['uri'];
+		$event['edited'] = $item['edited'];
+		$event['private'] = $item['private'];
+		$event['guid'] = $item['guid'];
+		$event['plink'] = $item['plink'];
+
+		$condition = ['uri' => $item['uri'], 'uid' => $item['uid']];
+		$ev = DBA::selectFirst('event', ['id'], $condition);
+		if (DBA::isResult($ev)) {
+			$event['id'] = $ev['id'];
+		}
+
+		$event_id = Event::store($event);
+		logger('Event '.$event_id.' was stored', LOGGER_DEBUG);
+	}
+
 	/**
 	 * Creates an item post
 	 *
@@ -238,6 +271,10 @@ class Processor
 				$item['contact-id'] = Contact::getIdForURL($activity['author'], 0, true);
 			}
 
+			if ($activity['object_type'] == 'as:Event') {
+				self::createEvent($activity, $item);
+			}
+
 			$item_id = Item::insert($item);
 			logger('Storing for user ' . $item['uid'] . ': ' . $item_id);
 		}
diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php
index 472341d06..f7c041a8a 100644
--- a/src/Protocol/ActivityPub/Receiver.php
+++ b/src/Protocol/ActivityPub/Receiver.php
@@ -22,8 +22,13 @@ use Friendica\Util\DateTimeFormat;
  *
  * To-Do:
  * - Update (Image, Video, Article, Note)
- * - Event
  * - Undo Announce
+ * - Accept Event
+ * - Reject Event
+ * - TentativeAccept Even
+ * - Undo Accept Event
+ * - Undo Reject Event
+ * - Undo TentativeAccept Event
  *
  * Check what this is meant to do:
  * - Add
@@ -31,7 +36,7 @@ use Friendica\Util\DateTimeFormat;
  * - Flag
  * - Remove
  * - Undo Block
- * - Undo Accept (Problem: This could invert a contact accept or an event accept)
+ * - Undo Accept Person
  */
 class Receiver
 {
@@ -687,6 +692,8 @@ class Receiver
 		$object_data['summary'] = JsonLD::fetchElement($object, 'as:summary');
 		$object_data['content'] = JsonLD::fetchElement($object, 'as:content');
 		$object_data['source'] = JsonLD::fetchElement($object, 'as:source', 'as:content', 'as:mediaType', 'text/bbcode');
+		$object_data['start-time'] = JsonLD::fetchElement($object, 'as:startTime', '@value');
+		$object_data['end-time'] = JsonLD::fetchElement($object, 'as:endTime', '@value');
 		$object_data['location'] = JsonLD::fetchElement($object, 'as:location', 'as:name', '@type', 'as:Place');
 		$object_data['latitude'] = JsonLD::fetchElement($object, 'as:location', 'as:latitude', '@type', 'as:Place');
 		$object_data['latitude'] = JsonLD::fetchElement($object_data, 'latitude', '@value');
diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php
index e1da96153..9f98409c3 100644
--- a/src/Protocol/ActivityPub/Transmitter.php
+++ b/src/Protocol/ActivityPub/Transmitter.php
@@ -33,11 +33,6 @@ require_once 'include/api.php';
  * @brief ActivityPub Transmitter Protocol class
  *
  * To-Do:
- *
- * Missing object types:
- * - Event
- *
- * Complicated object types:
  * - Undo Announce
  */
 class Transmitter
@@ -853,6 +848,32 @@ class Transmitter
 		return DBA::exists('term', $condition);
 	}
 
+	/**
+	 * Creates event data
+	 *
+	 * @param array $item
+	 *
+	 * @return array with the event data
+	 */
+	public static function createEvent($item)
+	{
+		$event = [];
+		$event['name'] = $item['event-summary'];
+		$event['content'] = BBCode::convert($item['event-desc'], false, 7);
+		$event['startTime'] = DateTimeFormat::utc($item['event-start'] . '+00:00', DateTimeFormat::ATOM);
+
+		if (!$item['event-nofinish']) {
+			$event['endTime'] = DateTimeFormat::utc($item['event-finish'] . '+00:00', DateTimeFormat::ATOM);
+		}
+
+		if (!empty($item['event-location'])) {
+			$item['location'] = $item['event-location'];
+			$event['location'] = self::createLocation($item);
+		}
+
+		return $event;
+	}
+
 	/**
 	 * Creates a note/article object array
 	 *
@@ -862,7 +883,9 @@ class Transmitter
 	 */
 	public static function createNote($item)
 	{
-		if (!empty($item['title'])) {
+		if ($item['event-type'] == 'event') {
+			$type = 'Event';
+		} elseif (!empty($item['title'])) {
 			$type = 'Article';
 		} else {
 			$type = 'Note';
@@ -910,10 +933,15 @@ class Transmitter
 			$body = self::removePictures($body);
 		}
 
-		$regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
-		$body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
+		if ($type == 'Event') {
+			$data = array_merge($data, self::createEvent($item));
+		} else {
+			$regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
+			$body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
+
+			$data['content'] = BBCode::convert($body, false, 7);
+		}
 
-		$data['content'] = BBCode::convert($body, false, 7);
 		$data['source'] = ['content' => $item['body'], 'mediaType' => "text/bbcode"];
 
 		if (!empty($item['signed_text']) && ($item['uri'] != $item['thr-parent'])) {
@@ -923,7 +951,7 @@ class Transmitter
 		$data['attachment'] = self::createAttachmentList($item, $type);
 		$data['tag'] = self::createTagList($item);
 
-		if (!empty($item['coord']) || !empty($item['location'])) {
+		if (empty($data['location']) && (!empty($item['coord']) || !empty($item['location']))) {
 			$data['location'] = self::createLocation($item);
 		}