aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/ActivityStreams/ASObject.php776
-rw-r--r--Zotlabs/ActivityStreams/Activity.php122
-rw-r--r--Zotlabs/ActivityStreams/Actor.php428
-rw-r--r--Zotlabs/ActivityStreams/AssertionMethod.php87
-rw-r--r--Zotlabs/ActivityStreams/Collection.php124
-rw-r--r--Zotlabs/ActivityStreams/CollectionPage.php73
-rw-r--r--Zotlabs/ActivityStreams/IntransitiveActivity.php104
-rw-r--r--Zotlabs/ActivityStreams/Link.php183
-rw-r--r--Zotlabs/ActivityStreams/OrderedCollection.php8
-rw-r--r--Zotlabs/ActivityStreams/OrderedCollectionPage.php92
-rw-r--r--Zotlabs/ActivityStreams/Place.php125
-rw-r--r--Zotlabs/ActivityStreams/Profile.php29
-rw-r--r--Zotlabs/ActivityStreams/PublicKey.php68
-rw-r--r--Zotlabs/ActivityStreams/Question.php67
-rw-r--r--Zotlabs/ActivityStreams/Relationship.php67
-rw-r--r--Zotlabs/ActivityStreams/Signature.php65
-rw-r--r--Zotlabs/ActivityStreams/Tombstone.php48
-rw-r--r--Zotlabs/ActivityStreams/UnhandledElementException.php8
-rw-r--r--Zotlabs/Daemon/Channel_purge.php2
-rw-r--r--Zotlabs/Daemon/Content_importer.php4
-rw-r--r--Zotlabs/Daemon/Cron.php3
-rw-r--r--Zotlabs/Daemon/Expire.php2
-rw-r--r--Zotlabs/Daemon/Importdoc.php18
-rw-r--r--Zotlabs/Daemon/Notifier.php5
-rw-r--r--Zotlabs/Entity/Account.php352
-rw-r--r--Zotlabs/Entity/Channel.php714
-rw-r--r--Zotlabs/Entity/Item.php1534
-rw-r--r--Zotlabs/Lib/Activity.php398
-rw-r--r--Zotlabs/Lib/BaseObject.php80
-rw-r--r--Zotlabs/Lib/Libzot.php131
-rw-r--r--Zotlabs/Lib/ThreadItem.php3
-rw-r--r--Zotlabs/Module/Channel_calendar.php30
-rw-r--r--Zotlabs/Module/Conversation.php4
-rw-r--r--Zotlabs/Module/Impel.php4
-rw-r--r--Zotlabs/Module/Import.php3
-rw-r--r--Zotlabs/Module/Import_progress.php20
-rw-r--r--Zotlabs/Module/Item.php58
-rw-r--r--Zotlabs/Module/Like.php18
-rw-r--r--Zotlabs/Module/Moderate.php2
-rw-r--r--Zotlabs/Module/React.php3
-rw-r--r--Zotlabs/Module/Share.php6
-rw-r--r--Zotlabs/Module/Subthread.php2
-rw-r--r--Zotlabs/Module/Tagrm.php98
-rw-r--r--Zotlabs/Module/Vote.php9
-rw-r--r--boot.php4
-rw-r--r--include/attach.php43
-rw-r--r--include/connections.php4
-rw-r--r--include/datetime.php2
-rw-r--r--include/event.php102
-rw-r--r--include/feedutils.php6
-rw-r--r--include/help.php4
-rw-r--r--include/html2bbcode.php3
-rw-r--r--include/import.php8
-rw-r--r--include/items.php539
-rw-r--r--include/network.php2
-rw-r--r--include/photos.php59
-rw-r--r--view/css/conversation.css4
-rw-r--r--view/js/mod_import_progress.js6
-rw-r--r--view/theme/redbasic/css/style.css10
-rw-r--r--view/tpl/conv_item.tpl12
-rw-r--r--view/tpl/conv_list.tpl4
61 files changed, 6238 insertions, 551 deletions
diff --git a/Zotlabs/ActivityStreams/ASObject.php b/Zotlabs/ActivityStreams/ASObject.php
new file mode 100644
index 000000000..1006943af
--- /dev/null
+++ b/Zotlabs/ActivityStreams/ASObject.php
@@ -0,0 +1,776 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+
+use Zotlabs\Lib\BaseObject;
+
+class ASObject extends BaseObject
+{
+ public $id;
+ public $type;
+ public $attachment;
+ public $attributedTo;
+ public $audience;
+ public $content;
+ public $context;
+ public $name;
+ public $endTime;
+ public $generator;
+ public $icon;
+ public $image;
+ public $inReplyTo;
+ public $location;
+ public $preview;
+ public $published;
+ public $replies;
+ public $startTime;
+ public $summary;
+ public $tag;
+ public $updated;
+ public $url;
+ public $to;
+ public $bto;
+ public $cc;
+ public $bcc;
+ public $mediaType;
+ public $duration;
+ public $source;
+
+
+ // Extension properties
+
+ public $signature;
+ public $proof;
+ public $sensitive;
+ public $replyTo;
+ public $wall;
+ public $isContainedConversation;
+ public $expires;
+ public $canReply;
+ public $canSearch;
+ public $directMessage;
+ public $commentPolicy;
+
+ /**
+ * @return mixed
+ */
+ public function getDirectMessage()
+ {
+ return $this->directMessage;
+ }
+
+ /**
+ * @param mixed $directMessage
+ * @return ASObject
+ */
+ public function setDirectMessage($directMessage)
+ {
+ $this->directMessage = $directMessage;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSignature()
+ {
+ return $this->signature;
+ }
+
+ /**
+ * @param mixed $signature
+ * @return ASObject
+ */
+ public function setSignature($signature)
+ {
+ $this->signature = $signature;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getProof()
+ {
+ return $this->proof;
+ }
+
+ /**
+ * @param mixed $proof
+ * @return ASObject
+ */
+ public function setProof($proof)
+ {
+ $this->proof = $proof;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getSensitive()
+ {
+ return $this->sensitive;
+ }
+
+ /**
+ * @param mixed $sensitive
+ * @return ASObject
+ */
+ public function setSensitive($sensitive)
+ {
+ $this->sensitive = $sensitive;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getReplyTo()
+ {
+ return $this->replyTo;
+ }
+
+ /**
+ * @param mixed $replyTo
+ * @return ASObject
+ */
+ public function setReplyTo($replyTo)
+ {
+ $this->replyTo = $replyTo;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getWall()
+ {
+ return $this->wall;
+ }
+
+ /**
+ * @param mixed $wall
+ * @return ASObject
+ */
+ public function setWall($wall)
+ {
+ $this->wall = $wall;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIsContainedConversation()
+ {
+ return $this->isContainedConversation;
+ }
+
+ /**
+ * @param mixed $isContainedConversation
+ * @return ASObject
+ */
+ public function setIsContainedConversation($isContainedConversation)
+ {
+ $this->isContainedConversation = $isContainedConversation;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->expires;
+ }
+
+ /**
+ * @param mixed $expires
+ * @return ASObject
+ */
+ public function setExpires($expires)
+ {
+ $this->expires = $expires;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCanReply()
+ {
+ return $this->canReply;
+ }
+
+ /**
+ * @param mixed $canReply
+ * @return ASObject
+ */
+ public function setCanReply($canReply)
+ {
+ $this->canReply = $canReply;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCanSearch()
+ {
+ return $this->canSearch;
+ }
+
+ /**
+ * @param mixed $canSearch
+ * @return ASObject
+ */
+ public function setCanSearch($canSearch)
+ {
+ $this->canSearch = $canSearch;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCommentPolicy()
+ {
+ return $this->commentPolicy;
+ }
+
+ /**
+ * @param mixed $commentPolicy
+ * @return ASObject
+ */
+ public function setCommentPolicy($commentPolicy)
+ {
+ $this->commentPolicy = $commentPolicy;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param mixed $id
+ * @return ASObject
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @param mixed $type
+ * @return ASObject
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAttachment()
+ {
+ return $this->attachment;
+ }
+
+ /**
+ * @param mixed $attachment
+ * @return ASObject
+ */
+ public function setAttachment($attachment)
+ {
+ $this->attachment = $attachment;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAttributedTo()
+ {
+ return $this->attributedTo;
+ }
+
+ /**
+ * @param mixed $attributedTo
+ * @return ASObject
+ */
+ public function setAttributedTo($attributedTo)
+ {
+ $this->attributedTo = $attributedTo;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAudience()
+ {
+ return $this->audience;
+ }
+
+ /**
+ * @param mixed $audience
+ * @return ASObject
+ */
+ public function setAudience($audience)
+ {
+ $this->audience = $audience;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * @param mixed $content
+ * @return ASObject
+ */
+ public function setContent($content)
+ {
+ $this->content = $content;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getContext()
+ {
+ return $this->context;
+ }
+
+ /**
+ * @param mixed $context
+ * @return ASObject
+ */
+ public function setContext($context)
+ {
+ $this->context = $context;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @param mixed $name
+ * @return ASObject
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEndTime()
+ {
+ return $this->endTime;
+ }
+
+ /**
+ * @param mixed $endTime
+ * @return ASObject
+ */
+ public function setEndTime($endTime)
+ {
+ $this->endTime = $endTime;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getGenerator()
+ {
+ return $this->generator;
+ }
+
+ /**
+ * @param mixed $generator
+ * @return ASObject
+ */
+ public function setGenerator($generator)
+ {
+ $this->generator = $generator;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIcon()
+ {
+ return $this->icon;
+ }
+
+ /**
+ * @param mixed $icon
+ * @return ASObject
+ */
+ public function setIcon($icon)
+ {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getImage()
+ {
+ return $this->image;
+ }
+
+ /**
+ * @param mixed $image
+ * @return ASObject
+ */
+ public function setImage($image)
+ {
+ $this->image = $image;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getInReplyTo()
+ {
+ return $this->inReplyTo;
+ }
+
+ /**
+ * @param mixed $inReplyTo
+ * @return ASObject
+ */
+ public function setInReplyTo($inReplyTo)
+ {
+ $this->inReplyTo = $inReplyTo;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLocation()
+ {
+ return $this->location;
+ }
+
+ /**
+ * @param mixed $location
+ * @return ASObject
+ */
+ public function setLocation($location)
+ {
+ $this->location = $location;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPreview()
+ {
+ return $this->preview;
+ }
+
+ /**
+ * @param mixed $preview
+ * @return ASObject
+ */
+ public function setPreview($preview)
+ {
+ $this->preview = $preview;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPublished()
+ {
+ return $this->published;
+ }
+
+ /**
+ * @param mixed $published
+ * @return ASObject
+ */
+ public function setPublished($published)
+ {
+ $this->published = $published;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getReplies()
+ {
+ return $this->replies;
+ }
+
+ /**
+ * @param mixed $replies
+ * @return ASObject
+ */
+ public function setReplies($replies)
+ {
+ $this->replies = $replies;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStartTime()
+ {
+ return $this->startTime;
+ }
+
+ /**
+ * @param mixed $startTime
+ * @return ASObject
+ */
+ public function setStartTime($startTime)
+ {
+ $this->startTime = $startTime;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSummary()
+ {
+ return $this->summary;
+ }
+
+ /**
+ * @param mixed $summary
+ * @return ASObject
+ */
+ public function setSummary($summary)
+ {
+ $this->summary = $summary;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTag()
+ {
+ return $this->tag;
+ }
+
+ /**
+ * @param mixed $tag
+ * @return ASObject
+ */
+ public function setTag($tag)
+ {
+ $this->tag = $tag;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUpdated()
+ {
+ return $this->updated;
+ }
+
+ /**
+ * @param mixed $updated
+ * @return ASObject
+ */
+ public function setUpdated($updated)
+ {
+ $this->updated = $updated;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * @param mixed $url
+ * @return ASObject
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTo()
+ {
+ return $this->to;
+ }
+
+ /**
+ * @param mixed $to
+ * @return ASObject
+ */
+ public function setTo($to)
+ {
+ $this->to = $to;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getBto()
+ {
+ return $this->bto;
+ }
+
+ /**
+ * @param mixed $bto
+ * @return ASObject
+ */
+ public function setBto($bto)
+ {
+ $this->bto = $bto;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCc()
+ {
+ return $this->cc;
+ }
+
+ /**
+ * @param mixed $cc
+ * @return ASObject
+ */
+ public function setCc($cc)
+ {
+ $this->cc = $cc;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getBcc()
+ {
+ return $this->bcc;
+ }
+
+ /**
+ * @param mixed $bcc
+ * @return ASObject
+ */
+ public function setBcc($bcc)
+ {
+ $this->bcc = $bcc;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMediaType()
+ {
+ return $this->mediaType;
+ }
+
+ /**
+ * @param mixed $mediaType
+ * @return ASObject
+ */
+ public function setMediaType($mediaType)
+ {
+ $this->mediaType = $mediaType;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDuration()
+ {
+ return $this->duration;
+ }
+
+ /**
+ * @param mixed $duration
+ * @return ASObject
+ */
+ public function setDuration($duration)
+ {
+ $this->duration = $duration;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ /**
+ * @param mixed $source
+ * @return ASObject
+ */
+ public function setSource($source)
+ {
+ $this->source = $source;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/Activity.php b/Zotlabs/ActivityStreams/Activity.php
new file mode 100644
index 000000000..3fccfb964
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Activity.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Activity extends ASObject
+{
+ public $actor;
+ public $object;
+ public $target;
+ public $result;
+ public $origin;
+ public $instrument;
+
+ /**
+ * @return mixed
+ */
+ public function getActor()
+ {
+ return $this->actor;
+ }
+
+ /**
+ * @param mixed $actor
+ * @return Activity
+ */
+ public function setActor($actor)
+ {
+ $this->actor = $actor;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getObject()
+ {
+ return $this->object;
+ }
+
+ /**
+ * @param mixed $object
+ * @return Activity
+ */
+ public function setObject($object)
+ {
+ $this->object = $object;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTarget()
+ {
+ return $this->target;
+ }
+
+ /**
+ * @param mixed $target
+ * @return Activity
+ */
+ public function setTarget($target)
+ {
+ $this->target = $target;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * @param mixed $result
+ * @return Activity
+ */
+ public function setResult($result)
+ {
+ $this->result = $result;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOrigin()
+ {
+ return $this->origin;
+ }
+
+ /**
+ * @param mixed $origin
+ * @return Activity
+ */
+ public function setOrigin($origin)
+ {
+ $this->origin = $origin;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getInstrument()
+ {
+ return $this->instrument;
+ }
+
+ /**
+ * @param mixed $instrument
+ * @return Activity
+ */
+ public function setInstrument($instrument)
+ {
+ $this->instrument = $instrument;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/Actor.php b/Zotlabs/ActivityStreams/Actor.php
new file mode 100644
index 000000000..4efa2f6b1
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Actor.php
@@ -0,0 +1,428 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Actor extends ASObject
+{
+ public $inbox;
+ public $outbox;
+ public $followers;
+ public $following;
+ public $permissions; /* extension property */
+ public $endpoints;
+ public $publicKey;
+ public $preferredUsername;
+ public $alsoKnownAs;
+
+ // Extension properties
+
+ public $movedTo;
+ public $copiedTo;
+ public $discoverable;
+ public $manuallyApprovesFollowers;
+ public $webfinger;
+ public $canSearch;
+ public $indexable;
+ public $assertionMethod;
+ public $gateways;
+ public $openwebauth;
+ public $authredirect;
+
+ /**
+ * @return mixed
+ */
+ public function getAlsoKnownAs()
+ {
+ return $this->alsoKnownAs;
+ }
+
+ /**
+ * @param mixed $alsoKnownAs
+ * @return Actor
+ */
+ public function setAlsoKnownAs($alsoKnownAs)
+ {
+ $this->alsoKnownAs = $alsoKnownAs;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMovedTo()
+ {
+ return $this->movedTo;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCopiedTo()
+ {
+ return $this->copiedTo;
+ }
+
+ /**
+ * @param mixed $copiedTo
+ * @return Actor
+ */
+ public function setCopiedTo($copiedTo)
+ {
+ $this->copiedTo = $copiedTo;
+ return $this;
+ }
+
+ /**
+ * @param mixed $movedTo
+ * @return Actor
+ */
+ public function setMovedTo($movedTo)
+ {
+ $this->movedTo = $movedTo;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDiscoverable()
+ {
+ return $this->discoverable;
+ }
+
+ /**
+ * @param mixed $discoverable
+ * @return Actor
+ */
+ public function setDiscoverable($discoverable)
+ {
+ $this->discoverable = $discoverable;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getManuallyApprovesFollowers()
+ {
+ return $this->manuallyApprovesFollowers;
+ }
+
+ /**
+ * @param mixed $manuallyApprovesFollowers
+ * @return Actor
+ */
+ public function setManuallyApprovesFollowers($manuallyApprovesFollowers)
+ {
+ $this->manuallyApprovesFollowers = $manuallyApprovesFollowers;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPreferredUsername()
+ {
+ return $this->preferredUsername;
+ }
+
+ /**
+ * @param mixed $preferredUsername
+ * @return Actor
+ */
+ public function setPreferredUsername($preferredUsername)
+ {
+ $this->preferredUsername = $preferredUsername;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param mixed $id
+ * @return Actor
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @param mixed $type
+ * @return Actor
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getInbox()
+ {
+ return $this->inbox;
+ }
+
+ /**
+ * @param mixed $inbox
+ * @return Actor
+ */
+ public function setInbox($inbox)
+ {
+ $this->inbox = $inbox;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOutbox()
+ {
+ return $this->outbox;
+ }
+
+ /**
+ * @param mixed $outbox
+ * @return Actor
+ */
+ public function setOutbox($outbox)
+ {
+ $this->outbox = $outbox;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getFollowers()
+ {
+ return $this->followers;
+ }
+
+ /**
+ * @param mixed $followers
+ * @return Actor
+ */
+ public function setFollowers($followers)
+ {
+ $this->followers = $followers;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getFollowing()
+ {
+ return $this->following;
+ }
+
+ /**
+ * @param mixed $following
+ * @return Actor
+ */
+ public function setFollowing($following)
+ {
+ $this->following = $following;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEndpoints()
+ {
+ return $this->endpoints;
+ }
+
+ /**
+ * @param mixed $endpoints
+ * @return Actor
+ */
+ public function setEndpoints($endpoints)
+ {
+ $this->endpoints = $endpoints;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPublicKey()
+ {
+ return $this->publicKey;
+ }
+
+ /**
+ * @param mixed $publicKey
+ * @return Actor
+ */
+ public function setPublicKey($publicKey)
+ {
+ $this->publicKey = $publicKey;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getWebfinger()
+ {
+ return $this->webfinger;
+ }
+
+ /**
+ * @param mixed $webfinger
+ * @return Actor
+ */
+ public function setWebfinger($webfinger)
+ {
+ $this->webfinger = $webfinger;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCanSearch()
+ {
+ return $this->canSearch;
+ }
+
+ /**
+ * @param mixed $canSearch
+ * @return Actor
+ */
+ public function setCanSearch($canSearch)
+ {
+ $this->canSearch = $canSearch;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIndexable()
+ {
+ return $this->indexable;
+ }
+
+ /**
+ * @param mixed $indexable
+ * @return Actor
+ */
+ public function setIndexable($indexable)
+ {
+ $this->indexable = $indexable;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAssertionMethod()
+ {
+ return $this->assertionMethod;
+ }
+
+ /**
+ * @param mixed $assertionMethod
+ * @return Actor
+ */
+ public function setAssertionMethod($assertionMethod)
+ {
+ $this->assertionMethod = $assertionMethod;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getGateways()
+ {
+ return $this->gateways;
+ }
+
+ /**
+ * @param mixed $gateways
+ * @return Actor
+ */
+ public function setGateways($gateways)
+ {
+ $this->gateways = $gateways;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPermissions()
+ {
+ return $this->permissions;
+ }
+
+ /**
+ * @param mixed $permissions
+ * @return Actor
+ */
+ public function setPermissions($permissions)
+ {
+ $this->permissions = $permissions;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOpenwebauth()
+ {
+ return $this->openwebauth;
+ }
+
+ /**
+ * @param mixed $openwebauth
+ * @return Actor
+ */
+ public function setOpenwebauth($openwebauth)
+ {
+ $this->openwebauth = $openwebauth;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAuthredirect()
+ {
+ return $this->authredirect;
+ }
+
+ /**
+ * @param mixed $authredirect
+ * @return Actor
+ */
+ public function setAuthredirect($authredirect)
+ {
+ $this->authredirect = $authredirect;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/AssertionMethod.php b/Zotlabs/ActivityStreams/AssertionMethod.php
new file mode 100644
index 000000000..d34f0332c
--- /dev/null
+++ b/Zotlabs/ActivityStreams/AssertionMethod.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class AssertionMethod extends ASObject
+{
+ public $id;
+ public $type;
+ public $controller;
+ public $publicKeyMultibase;
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param mixed $id
+ * @return AssertionMethod
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @param mixed $type
+ * @return AssertionMethod
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getController()
+ {
+ return $this->controller;
+ }
+
+ /**
+ * @param mixed $controller
+ * @return AssertionMethod
+ */
+ public function setController($controller)
+ {
+ $this->controller = $controller;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPublicKeyMultibase()
+ {
+ return $this->publicKeyMultibase;
+ }
+
+ /**
+ * @param mixed $publicKeyMultibase
+ * @return AssertionMethod
+ */
+ public function setPublicKeyMultibase($publicKeyMultibase)
+ {
+ $this->publicKeyMultibase = $publicKeyMultibase;
+ return $this;
+ }
+
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/Collection.php b/Zotlabs/ActivityStreams/Collection.php
new file mode 100644
index 000000000..f005166a8
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Collection.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Collection extends ASObject
+{
+ public int $totalItems;
+ public string $current;
+ public string $first;
+ public string $last;
+ public array $items;
+
+ public mixed $collectionOf;
+
+ /**
+ * @return int
+ */
+ public function getTotalItems(): int
+ {
+ return $this->totalItems;
+ }
+
+ /**
+ * @param mixed $totalItems
+ * @return Collection
+ */
+ public function setTotalItems(mixed $totalItems): static
+ {
+ $this->totalItems = $totalItems;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCurrent(): string
+ {
+ return $this->current;
+ }
+
+ /**
+ * @param mixed $current
+ * @return Collection
+ */
+ public function setCurrent(mixed $current): static
+ {
+ $this->current = $current;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFirst(): string
+ {
+ return $this->first;
+ }
+
+ /**
+ * @param mixed $first
+ * @return Collection
+ */
+ public function setFirst(mixed $first): static
+ {
+ $this->first = $first;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLast(): string
+ {
+ return $this->last;
+ }
+
+ /**
+ * @param mixed $last
+ * @return Collection
+ */
+ public function setLast(mixed $last): static
+ {
+ $this->last = $last;
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getItems(): array
+ {
+ return $this->items;
+ }
+
+ /**
+ * @param mixed $items
+ * @return Collection
+ */
+ public function setItems(mixed $items): static
+ {
+ $this->items = $items;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCollectionOf(): mixed
+ {
+ return $this->collectionOf;
+ }
+
+ /**
+ * @param mixed $collectionOf
+ * @return Collection
+ */
+ public function setCollectionOf(mixed $collectionOf): static
+ {
+ $this->collectionOf = $collectionOf;
+ return $this;
+ }
+
+
+}
diff --git a/Zotlabs/ActivityStreams/CollectionPage.php b/Zotlabs/ActivityStreams/CollectionPage.php
new file mode 100644
index 000000000..4bdedc93e
--- /dev/null
+++ b/Zotlabs/ActivityStreams/CollectionPage.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class CollectionPage extends Collection
+{
+ public $partOf;
+ public $next;
+ public $prev;
+
+ // startIndex only applies for OrderedCollectionPage. See
+ // https://www.w3.org/ns/activitystreams#OrderedCollectionPage
+ // It is provided here to avoid multiple inheritance
+
+ public $startIndex;
+
+ /**
+ * @return mixed
+ */
+ public function getPartOf()
+ {
+ return $this->partOf;
+ }
+
+ /**
+ * @param mixed $partOf
+ * @return CollectionPage
+ */
+ public function setPartOf($partOf)
+ {
+ $this->partOf = $partOf;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNext()
+ {
+ return $this->next;
+ }
+
+ /**
+ * @param mixed $next
+ * @return CollectionPage
+ */
+ public function setNext($next)
+ {
+ $this->next = $next;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrev()
+ {
+ return $this->prev;
+ }
+
+ /**
+ * @param mixed $prev
+ * @return CollectionPage
+ */
+ public function setPrev($prev)
+ {
+ $this->prev = $prev;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/IntransitiveActivity.php b/Zotlabs/ActivityStreams/IntransitiveActivity.php
new file mode 100644
index 000000000..62e83f63c
--- /dev/null
+++ b/Zotlabs/ActivityStreams/IntransitiveActivity.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+
+class IntransitiveActivity extends ASObject
+{
+ public $actor;
+ public $target;
+ public $result;
+ public $origin;
+ public $instrument;
+
+ /**
+ * @return mixed
+ */
+ public function getActor()
+ {
+ return $this->actor;
+ }
+
+ /**
+ * @param mixed $actor
+ * @return IntransitiveActivity
+ */
+ public function setActor($actor)
+ {
+ $this->actor = $actor;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTarget()
+ {
+ return $this->target;
+ }
+
+ /**
+ * @param mixed $target
+ * @return IntransitiveActivity
+ */
+ public function setTarget($target)
+ {
+ $this->target = $target;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * @param mixed $result
+ * @return IntransitiveActivity
+ */
+ public function setResult($result)
+ {
+ $this->result = $result;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOrigin()
+ {
+ return $this->origin;
+ }
+
+ /**
+ * @param mixed $origin
+ * @return IntransitiveActivity
+ */
+ public function setOrigin($origin)
+ {
+ $this->origin = $origin;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getInstrument()
+ {
+ return $this->instrument;
+ }
+
+ /**
+ * @param mixed $instrument
+ * @return IntransitiveActivity
+ */
+ public function setInstrument($instrument)
+ {
+ $this->instrument = $instrument;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/Link.php b/Zotlabs/ActivityStreams/Link.php
new file mode 100644
index 000000000..904b354da
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Link.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+use Zotlabs\Lib\BaseObject;
+
+class Link extends BaseObject
+{
+ public $type;
+ public $href;
+ public $rel;
+ public $mediaType;
+ public $name;
+ public $hreflang;
+ public $height;
+ public $width;
+ public $preview;
+
+
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @param mixed $type
+ * @return Link
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHref()
+ {
+ return $this->href;
+ }
+
+ /**
+ * @param mixed $href
+ * @return Link
+ */
+ public function setHref($href)
+ {
+ $this->href = $href;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRel()
+ {
+ return $this->rel;
+ }
+
+ /**
+ * @param mixed $rel
+ * @return Link
+ */
+ public function setRel($rel)
+ {
+ $this->rel = $rel;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMediaType()
+ {
+ return $this->mediaType;
+ }
+
+ /**
+ * @param mixed $mediaType
+ * @return Link
+ */
+ public function setMediaType($mediaType)
+ {
+ $this->mediaType = $mediaType;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @param mixed $name
+ * @return Link
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHreflang()
+ {
+ return $this->hreflang;
+ }
+
+ /**
+ * @param mixed $hreflang
+ * @return Link
+ */
+ public function setHreflang($hreflang)
+ {
+ $this->hreflang = $hreflang;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * @param mixed $height
+ * @return Link
+ */
+ public function setHeight($height)
+ {
+ $this->height = $height;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * @param mixed $width
+ * @return Link
+ */
+ public function setWidth($width)
+ {
+ $this->width = $width;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPreview()
+ {
+ return $this->preview;
+ }
+
+ /**
+ * @param mixed $preview
+ * @return Link
+ */
+ public function setPreview($preview)
+ {
+ $this->preview = $preview;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/OrderedCollection.php b/Zotlabs/ActivityStreams/OrderedCollection.php
new file mode 100644
index 000000000..95f5036f7
--- /dev/null
+++ b/Zotlabs/ActivityStreams/OrderedCollection.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class OrderedCollection extends Collection
+{
+
+}
diff --git a/Zotlabs/ActivityStreams/OrderedCollectionPage.php b/Zotlabs/ActivityStreams/OrderedCollectionPage.php
new file mode 100644
index 000000000..664802eff
--- /dev/null
+++ b/Zotlabs/ActivityStreams/OrderedCollectionPage.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+/**
+ * According to the specification, OrderedCollectionPage extends
+ * both OrderedCollection and CollectionPage, but PHP is still a bit awkward
+ * when it comes to multiple inheritance. Rather than try and do this with
+ * traits, we'll just include the CollectionPage elements here - as this only
+ * consists of three properties.
+ */
+
+class OrderedCollectionPage extends OrderedCollection
+{
+ public $partOf;
+ public $next;
+ public $prev;
+ public $startIndex;
+
+ /**
+ * @return mixed
+ */
+ public function getPartOf()
+ {
+ return $this->partOf;
+ }
+
+ /**
+ * @param mixed $partOf
+ * @return OrderedCollectionPage
+ */
+ public function setPartOf($partOf)
+ {
+ $this->partOf = $partOf;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNext()
+ {
+ return $this->next;
+ }
+
+ /**
+ * @param mixed $next
+ * @return OrderedCollectionPage
+ */
+ public function setNext($next)
+ {
+ $this->next = $next;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrev()
+ {
+ return $this->prev;
+ }
+
+ /**
+ * @param mixed $prev
+ * @return OrderedCollectionPage
+ */
+ public function setPrev($prev)
+ {
+ $this->prev = $prev;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStartIndex()
+ {
+ return $this->startIndex;
+ }
+
+ /**
+ * @param mixed $startIndex
+ * @return OrderedCollectionPage
+ */
+ public function setStartIndex($startIndex)
+ {
+ $this->startIndex = $startIndex;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/Place.php b/Zotlabs/ActivityStreams/Place.php
new file mode 100644
index 000000000..5aadc1c73
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Place.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Place extends ASObject
+{
+
+ public $accuracy;
+ public $altitude;
+ public $latitude;
+ public $longitude;
+ public $radius;
+ public $units;
+
+ /**
+ * @return mixed
+ */
+ public function getAccuracy()
+ {
+ return $this->accuracy;
+ }
+
+ /**
+ * @param mixed $accuracy
+ * @return Place
+ */
+ public function setAccuracy($accuracy)
+ {
+ $this->accuracy = $accuracy;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAltitude()
+ {
+ return $this->altitude;
+ }
+
+ /**
+ * @param mixed $altitude
+ * @return Place
+ */
+ public function setAltitude($altitude)
+ {
+ $this->altitude = $altitude;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLatitude()
+ {
+ return $this->latitude;
+ }
+
+ /**
+ * @param mixed $latitude
+ * @return Place
+ */
+ public function setLatitude($latitude)
+ {
+ $this->latitude = $latitude;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLongitude()
+ {
+ return $this->longitude;
+ }
+
+ /**
+ * @param mixed $longitude
+ * @return Place
+ */
+ public function setLongitude($longitude)
+ {
+ $this->longitude = $longitude;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRadius()
+ {
+ return $this->radius;
+ }
+
+ /**
+ * @param mixed $radius
+ * @return Place
+ */
+ public function setRadius($radius)
+ {
+ $this->radius = $radius;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUnits()
+ {
+ return $this->units;
+ }
+
+ /**
+ * @param mixed $units
+ * @return Place
+ */
+ public function setUnits($units)
+ {
+ $this->units = $units;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/Profile.php b/Zotlabs/ActivityStreams/Profile.php
new file mode 100644
index 000000000..817f4a817
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Profile.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Profile extends ASObject
+{
+
+ public $describes;
+
+ /**
+ * @return mixed
+ */
+ public function getDescribes()
+ {
+ return $this->describes;
+ }
+
+ /**
+ * @param mixed $describes
+ * @return Profile
+ */
+ public function setDescribes($describes)
+ {
+ $this->describes = $describes;
+ return $this;
+ }
+
+
+}
diff --git a/Zotlabs/ActivityStreams/PublicKey.php b/Zotlabs/ActivityStreams/PublicKey.php
new file mode 100644
index 000000000..d5e7b9522
--- /dev/null
+++ b/Zotlabs/ActivityStreams/PublicKey.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class PublicKey extends ASObject
+{
+ public $owner;
+ public $signatureAlgorithm;
+ public $publicKeyPem;
+
+ /**
+ * @return mixed
+ */
+ public function getOwner()
+ {
+ return $this->owner;
+ }
+
+ /**
+ * @param mixed $owner
+ * @return PublicKey
+ */
+ public function setOwner($owner)
+ {
+ $this->owner = $owner;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSignatureAlgorithm()
+ {
+ return $this->signatureAlgorithm;
+ }
+
+ /**
+ * @param mixed $signatureAlgorithm
+ * @return PublicKey
+ */
+ public function setSignatureAlgorithm($signatureAlgorithm)
+ {
+ $this->signatureAlgorithm = $signatureAlgorithm;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPublicKeyPem()
+ {
+ return $this->publicKeyPem;
+ }
+
+ /**
+ * @param mixed $publicKeyPem
+ * @return PublicKey
+ */
+ public function setPublicKeyPem($publicKeyPem)
+ {
+ $this->publicKeyPem = $publicKeyPem;
+ return $this;
+ }
+
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/Question.php b/Zotlabs/ActivityStreams/Question.php
new file mode 100644
index 000000000..63f642eaa
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Question.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Question extends ASObject
+{
+ public $oneOf;
+ public $anyOf;
+ public $closed;
+
+ /**
+ * @return mixed
+ */
+ public function getOneOf()
+ {
+ return $this->oneOf;
+ }
+
+ /**
+ * @param mixed $oneOf
+ * @return Question
+ */
+ public function setOneOf($oneOf)
+ {
+ $this->oneOf = $oneOf;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAnyOf()
+ {
+ return $this->anyOf;
+ }
+
+ /**
+ * @param mixed $anyOf
+ * @return Question
+ */
+ public function setAnyOf($anyOf)
+ {
+ $this->anyOf = $anyOf;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getClosed()
+ {
+ return $this->closed;
+ }
+
+ /**
+ * @param mixed $closed
+ * @return Question
+ */
+ public function setClosed($closed)
+ {
+ $this->closed = $closed;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/Relationship.php b/Zotlabs/ActivityStreams/Relationship.php
new file mode 100644
index 000000000..29669a200
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Relationship.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Relationship extends ASObject
+{
+ public $subject;
+ public $object;
+ public $relationship;
+
+ /**
+ * @return mixed
+ */
+ public function getSubject()
+ {
+ return $this->subject;
+ }
+
+ /**
+ * @param mixed $subject
+ * @return Relationship
+ */
+ public function setSubject($subject)
+ {
+ $this->subject = $subject;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getObject()
+ {
+ return $this->object;
+ }
+
+ /**
+ * @param mixed $object
+ * @return Relationship
+ */
+ public function setObject($object)
+ {
+ $this->object = $object;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRelationship()
+ {
+ return $this->relationship;
+ }
+
+ /**
+ * @param mixed $relationship
+ * @return Relationship
+ */
+ public function setRelationship($relationship)
+ {
+ $this->relationship = $relationship;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/Signature.php b/Zotlabs/ActivityStreams/Signature.php
new file mode 100644
index 000000000..e115dd331
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Signature.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Signature extends ASObject
+{
+ public $nonce;
+ public $creator;
+ public $signatureValue;
+
+ /**
+ * @return mixed
+ */
+ public function getCreator()
+ {
+ return $this->creator;
+ }
+
+ /**
+ * @param mixed $creator
+ * @return Signature
+ */
+ public function setCreator($creator)
+ {
+ $this->creator = $creator;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSignatureValue()
+ {
+ return $this->signatureValue;
+ }
+
+ /**
+ * @param mixed $signatureValue
+ * @return Signature
+ */
+ public function setSignatureValue($signatureValue)
+ {
+ $this->signatureValue = $signatureValue;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNonce()
+ {
+ return $this->nonce;
+ }
+
+ /**
+ * @param mixed $nonce
+ * @return Signature
+ */
+ public function setNonce($nonce)
+ {
+ $this->nonce = $nonce;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/ActivityStreams/Tombstone.php b/Zotlabs/ActivityStreams/Tombstone.php
new file mode 100644
index 000000000..54a6ab76c
--- /dev/null
+++ b/Zotlabs/ActivityStreams/Tombstone.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class Tombstone extends ASObject
+{
+ public $formerType;
+ public $deleted;
+
+ /**
+ * @return mixed
+ */
+ public function getFormerType()
+ {
+ return $this->formerType;
+ }
+
+ /**
+ * @param mixed $formerType
+ * @return Tombstone
+ */
+ public function setFormerType($formerType)
+ {
+ $this->formerType = $formerType;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDeleted()
+ {
+ return $this->deleted;
+ }
+
+ /**
+ * @param mixed $deleted
+ * @return Tombstone
+ */
+ public function setDeleted($deleted)
+ {
+ $this->deleted = $deleted;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/ActivityStreams/UnhandledElementException.php b/Zotlabs/ActivityStreams/UnhandledElementException.php
new file mode 100644
index 000000000..f8b71693d
--- /dev/null
+++ b/Zotlabs/ActivityStreams/UnhandledElementException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Zotlabs\ActivityStreams;
+
+class UnhandledElementException extends \Exception
+{
+
+}
diff --git a/Zotlabs/Daemon/Channel_purge.php b/Zotlabs/Daemon/Channel_purge.php
index 9fceb0fb9..d25edf8ba 100644
--- a/Zotlabs/Daemon/Channel_purge.php
+++ b/Zotlabs/Daemon/Channel_purge.php
@@ -24,7 +24,7 @@ class Channel_purge {
);
if ($r) {
foreach ($r as $rv) {
- drop_item($rv['id'], false);
+ drop_item($rv['id']);
}
}
} while ($r);
diff --git a/Zotlabs/Daemon/Content_importer.php b/Zotlabs/Daemon/Content_importer.php
index baecb8f66..b98a1f10d 100644
--- a/Zotlabs/Daemon/Content_importer.php
+++ b/Zotlabs/Daemon/Content_importer.php
@@ -53,9 +53,9 @@ class Content_importer {
killme();
}
- $j = json_decode($x['body'],true);
+ $j = json_decode($x['body'], true);
- if(! is_array($j['item']) || ! count($j['item'])) {
+ if($j && empty($j['item'])) {
PConfig::Set($channel['channel_id'], 'import', 'content_completed', 1);
return;
}
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index 3f5ce28eb..186f3efcf 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -76,7 +76,8 @@ class Cron {
if ($r) {
require_once('include/items.php');
foreach ($r as $rr) {
- drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
+ drop_item($rr['id'], (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL), uid: intval($rr['uid']));
+
if ($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Master::Summon(['Notifier', 'drop', $rr['id']]);
diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php
index ad52a6b71..3ac3dee3a 100644
--- a/Zotlabs/Daemon/Expire.php
+++ b/Zotlabs/Daemon/Expire.php
@@ -29,7 +29,7 @@ class Expire {
);
if ($r) {
foreach ($r as $rr) {
- drop_item($rr['id'], false, DROPITEM_PHASE2);
+ drop_item($rr['id'], DROPITEM_PHASE2);
}
}
diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php
index c5a81e50c..8f04e05f8 100644
--- a/Zotlabs/Daemon/Importdoc.php
+++ b/Zotlabs/Daemon/Importdoc.php
@@ -18,9 +18,13 @@ class Importdoc {
static public function update_docs_dir($s) {
$f = basename($s);
$d = dirname($s);
- if ($s === 'doc/html')
+
+ if ($s === 'doc/html') {
return;
+ }
+
$files = glob("$d/$f");
+
if ($files) {
foreach ($files as $fi) {
if ($fi === 'doc/html') {
@@ -37,6 +41,18 @@ class Importdoc {
}
}
}
+
+ // remove old files that weren't updated (indicates they were most likely deleted).
+ $i = q("select * from item where item_type = 5 and edited < %s - %s",
+ db_utcnow(),
+ db_quoteinterval('14 DAY', true)
+ );
+
+ if ($i) {
+ foreach ($i as $iv) {
+ drop_item($iv['id'], DROPITEM_NORMAL, true);
+ }
+ }
}
}
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 20134b8fe..1693f9c9f 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -299,7 +299,7 @@ class Notifier {
return;
}
- if ($target_item['verb'] === ACTIVITY_SHARE) {
+ if (in_array($target_item['verb'], [ACTIVITY_SHARE])) {
// Provide correct representation across the wire. Internally this is treated as a comment.
$target_item['parent_mid'] = $target_item['thr_parent'] = $target_item['mid'];
}
@@ -374,7 +374,6 @@ class Notifier {
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('notifier: followup relay', LOGGER_DEBUG);
- // If the Parent item is an Announce the real owner is the parent author
$sendto = (($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
self::$recipients = [$sendto];
self::$private = true;
@@ -589,8 +588,6 @@ class Notifier {
foreach ($dhubs as $hub) {
- logger('notifier_hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
-
if ($hub['hubloc_network'] !== 'zot6') {
$narr = [
'channel' => self::$channel,
diff --git a/Zotlabs/Entity/Account.php b/Zotlabs/Entity/Account.php
new file mode 100644
index 000000000..2d3af5e4b
--- /dev/null
+++ b/Zotlabs/Entity/Account.php
@@ -0,0 +1,352 @@
+<?php
+
+namespace Zotlabs\Entity;
+
+use Zotlabs\Lib\BaseObject;
+
+class Account extends BaseObject
+{
+ public $account_id;
+ public $account_parent;
+ public $account_default_channel;
+ public $account_salt;
+ public $account_password;
+ public $account_email;
+ public $account_external;
+ public $account_language;
+ public $account_created;
+ public $account_lastlog;
+ public $account_flags;
+ public $account_roles;
+ public $account_reset;
+ public $account_expires;
+ public $account_expire_notified;
+ public $account_service_class;
+ public $account_level;
+ public $account_password_change;
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->account_id;
+ }
+
+ /**
+ * @param mixed $account_id
+ * @return Account
+ */
+ public function setId($account_id)
+ {
+ $this->account_id = $account_id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getParent()
+ {
+ return $this->account_parent;
+ }
+
+ /**
+ * @param mixed $account_parent
+ * @return Account
+ */
+ public function setParent($account_parent)
+ {
+ $this->account_parent = $account_parent;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDefaultChannel()
+ {
+ return $this->account_default_channel;
+ }
+
+ /**
+ * @param mixed $account_default_channel
+ * @return Account
+ */
+ public function setDefaultChannel($account_default_channel)
+ {
+ $this->account_default_channel = $account_default_channel;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSalt()
+ {
+ return $this->account_salt;
+ }
+
+ /**
+ * @param mixed $account_salt
+ * @return Account
+ */
+ public function setSalt($account_salt)
+ {
+ $this->account_salt = $account_salt;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPassword()
+ {
+ return $this->account_password;
+ }
+
+ /**
+ * @param mixed $account_password
+ * @return Account
+ */
+ public function setPassword($account_password)
+ {
+ $this->account_password = $account_password;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEmail()
+ {
+ return $this->account_email;
+ }
+
+ /**
+ * @param mixed $account_email
+ * @return Account
+ */
+ public function setEmail($account_email)
+ {
+ $this->account_email = $account_email;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExternal()
+ {
+ return $this->account_external;
+ }
+
+ /**
+ * @param mixed $account_external
+ * @return Account
+ */
+ public function setExternal($account_external)
+ {
+ $this->account_external = $account_external;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLanguage()
+ {
+ return $this->account_language;
+ }
+
+ /**
+ * @param mixed $account_language
+ * @return Account
+ */
+ public function setLanguage($account_language)
+ {
+ $this->account_language = $account_language;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCreated()
+ {
+ return $this->account_created;
+ }
+
+ /**
+ * @param mixed $account_created
+ * @return Account
+ */
+ public function setCreated($account_created)
+ {
+ $this->account_created = $account_created;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLastlog()
+ {
+ return $this->account_lastlog;
+ }
+
+ /**
+ * @param mixed $account_lastlog
+ * @return Account
+ */
+ public function setLastlog($account_lastlog)
+ {
+ $this->account_lastlog = $account_lastlog;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getFlags()
+ {
+ return $this->account_flags;
+ }
+
+ /**
+ * @param mixed $account_flags
+ * @return Account
+ */
+ public function setFlags($account_flags)
+ {
+ $this->account_flags = $account_flags;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRoles()
+ {
+ return $this->account_roles;
+ }
+
+ /**
+ * @param mixed $account_roles
+ * @return Account
+ */
+ public function setRoles($account_roles)
+ {
+ $this->account_roles = $account_roles;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getReset()
+ {
+ return $this->account_reset;
+ }
+
+ /**
+ * @param mixed $account_reset
+ * @return Account
+ */
+ public function setReset($account_reset)
+ {
+ $this->account_reset = $account_reset;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->account_expires;
+ }
+
+ /**
+ * @param mixed $account_expires
+ * @return Account
+ */
+ public function setExpires($account_expires)
+ {
+ $this->account_expires = $account_expires;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExpireNotified()
+ {
+ return $this->account_expire_notified;
+ }
+
+ /**
+ * @param mixed $account_expire_notified
+ * @return Account
+ */
+ public function setExpireNotified($account_expire_notified)
+ {
+ $this->account_expire_notified = $account_expire_notified;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getServiceClass()
+ {
+ return $this->account_service_class;
+ }
+
+ /**
+ * @param mixed $account_service_class
+ * @return Account
+ */
+ public function setServiceClass($account_service_class)
+ {
+ $this->account_service_class = $account_service_class;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLevel()
+ {
+ return $this->account_level;
+ }
+
+ /**
+ * @param mixed $account_level
+ * @return Account
+ */
+ public function setLevel($account_level)
+ {
+ $this->account_level = $account_level;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPasswordChange()
+ {
+ return $this->account_password_change;
+ }
+
+ /**
+ * @param mixed $account_password_change
+ * @return Account
+ */
+ public function setPasswordChange($account_password_change)
+ {
+ $this->account_password_change = $account_password_change;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/Entity/Channel.php b/Zotlabs/Entity/Channel.php
new file mode 100644
index 000000000..e9f7dc14f
--- /dev/null
+++ b/Zotlabs/Entity/Channel.php
@@ -0,0 +1,714 @@
+<?php
+
+namespace Zotlabs\Entity;
+
+use Zotlabs\Lib\BaseObject;
+
+class Channel extends BaseObject
+{
+ public $channel_id;
+ public $channel_account_id;
+ public $channel_primary;
+ public $channel_name;
+ public $channel_parent;
+ public $channel_address;
+ public $channel_guid;
+ public $channel_guid_sig;
+ public $channel_hash;
+ public $channel_timezone;
+ public $channel_location;
+ public $channel_theme;
+ public $channel_startpage;
+ public $channel_pubkey;
+ public $channel_prvkey;
+ public $channel_epubkey;
+ public $channel_eprvkey;
+ public $channel_notifyflags;
+ public $channel_pageflags;
+ public $channel_dirdate;
+ public $channel_lastpost;
+ public $channel_deleted;
+ public $channel_active;
+ public $channel_max_anon_mail;
+ public $channel_max_friend_req;
+ public $channel_expire_days;
+ public $channel_passwd_reset;
+ public $channel_default_group;
+ public $channel_allow_cid;
+ public $channel_allow_gid;
+ public $channel_deny_cid;
+ public $channel_deny_gid;
+ public $channel_removed;
+ public $channel_system;
+ public $channel_moved;
+ public $channel_password;
+ public $channel_salt;
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->channel_id;
+ }
+
+ /**
+ * @param mixed $channel_id
+ * @return Channel
+ */
+ public function setId($channel_id)
+ {
+ $this->channel_id = $channel_id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAccountId()
+ {
+ return $this->channel_account_id;
+ }
+
+ /**
+ * @param mixed $channel_account_id
+ * @return Channel
+ */
+ public function setAccountId($channel_account_id)
+ {
+ $this->channel_account_id = $channel_account_id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrimary()
+ {
+ return $this->channel_primary;
+ }
+
+ /**
+ * @param mixed $channel_primary
+ * @return Channel
+ */
+ public function setPrimary($channel_primary)
+ {
+ $this->channel_primary = $channel_primary;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getName()
+ {
+ return $this->channel_name;
+ }
+
+ /**
+ * @param mixed $channel_name
+ * @return Channel
+ */
+ public function setName($channel_name)
+ {
+ $this->channel_name = $channel_name;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getParent()
+ {
+ return $this->channel_parent;
+ }
+
+ /**
+ * @param mixed $channel_parent
+ * @return Channel
+ */
+ public function setParent($channel_parent)
+ {
+ $this->channel_parent = $channel_parent;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAddress()
+ {
+ return $this->channel_address;
+ }
+
+ /**
+ * @param mixed $channel_address
+ * @return Channel
+ */
+ public function setAddress($channel_address)
+ {
+ $this->channel_address = $channel_address;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getGuid()
+ {
+ return $this->channel_guid;
+ }
+
+ /**
+ * @param mixed $channel_guid
+ * @return Channel
+ */
+ public function setGuid($channel_guid)
+ {
+ $this->channel_guid = $channel_guid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getGuidSig()
+ {
+ return $this->channel_guid_sig;
+ }
+
+ /**
+ * @param mixed $channel_guid_sig
+ * @return Channel
+ */
+ public function setGuidSig($channel_guid_sig)
+ {
+ $this->channel_guid_sig = $channel_guid_sig;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHash()
+ {
+ return $this->channel_hash;
+ }
+
+ /**
+ * @param mixed $channel_hash
+ * @return Channel
+ */
+ public function setHash($channel_hash)
+ {
+ $this->channel_hash = $channel_hash;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTimezone()
+ {
+ return $this->channel_timezone;
+ }
+
+ /**
+ * @param mixed $channel_timezone
+ * @return Channel
+ */
+ public function setTimezone($channel_timezone)
+ {
+ $this->channel_timezone = $channel_timezone;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLocation()
+ {
+ return $this->channel_location;
+ }
+
+ /**
+ * @param mixed $channel_location
+ * @return Channel
+ */
+ public function setLocation($channel_location)
+ {
+ $this->channel_location = $channel_location;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTheme()
+ {
+ return $this->channel_theme;
+ }
+
+ /**
+ * @param mixed $channel_theme
+ * @return Channel
+ */
+ public function setTheme($channel_theme)
+ {
+ $this->channel_theme = $channel_theme;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStartpage()
+ {
+ return $this->channel_startpage;
+ }
+
+ /**
+ * @param mixed $channel_startpage
+ * @return Channel
+ */
+ public function setStartpage($channel_startpage)
+ {
+ $this->channel_startpage = $channel_startpage;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPubkey()
+ {
+ return $this->channel_pubkey;
+ }
+
+ /**
+ * @param mixed $channel_pubkey
+ * @return Channel
+ */
+ public function setPubkey($channel_pubkey)
+ {
+ $this->channel_pubkey = $channel_pubkey;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrvkey()
+ {
+ return $this->channel_prvkey;
+ }
+
+ /**
+ * @param mixed $channel_prvkey
+ * @return Channel
+ */
+ public function setPrvkey($channel_prvkey)
+ {
+ $this->channel_prvkey = $channel_prvkey;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEpubkey()
+ {
+ return $this->channel_epubkey;
+ }
+
+ /**
+ * @param mixed $channel_epubkey
+ * @return Channel
+ */
+ public function setEpubkey($channel_epubkey)
+ {
+ $this->channel_epubkey = $channel_epubkey;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEprvkey()
+ {
+ return $this->channel_eprvkey;
+ }
+
+ /**
+ * @param mixed $channel_eprvkey
+ * @return Channel
+ */
+ public function setEprvkey($channel_eprvkey)
+ {
+ $this->channel_eprvkey = $channel_eprvkey;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getNotifyflags()
+ {
+ return $this->channel_notifyflags;
+ }
+
+ /**
+ * @param mixed $channel_notifyflags
+ * @return Channel
+ */
+ public function setNotifyflags($channel_notifyflags)
+ {
+ $this->channel_notifyflags = $channel_notifyflags;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPageflags()
+ {
+ return $this->channel_pageflags;
+ }
+
+ /**
+ * @param mixed $channel_pageflags
+ * @return Channel
+ */
+ public function setPageflags($channel_pageflags)
+ {
+ $this->channel_pageflags = $channel_pageflags;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDirdate()
+ {
+ return $this->channel_dirdate;
+ }
+
+ /**
+ * @param mixed $channel_dirdate
+ * @return Channel
+ */
+ public function setDirdate($channel_dirdate)
+ {
+ $this->channel_dirdate = $channel_dirdate;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLastpost()
+ {
+ return $this->channel_lastpost;
+ }
+
+ /**
+ * @param mixed $channel_lastpost
+ * @return Channel
+ */
+ public function setLastpost($channel_lastpost)
+ {
+ $this->channel_lastpost = $channel_lastpost;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDeleted()
+ {
+ return $this->channel_deleted;
+ }
+
+ /**
+ * @param mixed $channel_deleted
+ * @return Channel
+ */
+ public function setDeleted($channel_deleted)
+ {
+ $this->channel_deleted = $channel_deleted;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getActive()
+ {
+ return $this->channel_active;
+ }
+
+ /**
+ * @param mixed $channel_active
+ * @return Channel
+ */
+ public function setActive($channel_active)
+ {
+ $this->channel_active = $channel_active;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMaxAnonMail()
+ {
+ return $this->channel_max_anon_mail;
+ }
+
+ /**
+ * @param mixed $channel_max_anon_mail
+ * @return Channel
+ */
+ public function setMaxAnonMail($channel_max_anon_mail)
+ {
+ $this->channel_max_anon_mail = $channel_max_anon_mail;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMaxFriendReq()
+ {
+ return $this->channel_max_friend_req;
+ }
+
+ /**
+ * @param mixed $channel_max_friend_req
+ * @return Channel
+ */
+ public function setMaxFriendReq($channel_max_friend_req)
+ {
+ $this->channel_max_friend_req = $channel_max_friend_req;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExpireDays()
+ {
+ return $this->channel_expire_days;
+ }
+
+ /**
+ * @param mixed $channel_expire_days
+ * @return Channel
+ */
+ public function setExpireDays($channel_expire_days)
+ {
+ $this->channel_expire_days = $channel_expire_days;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPasswdReset()
+ {
+ return $this->channel_passwd_reset;
+ }
+
+ /**
+ * @param mixed $channel_passwd_reset
+ * @return Channel
+ */
+ public function setPasswdReset($channel_passwd_reset)
+ {
+ $this->channel_passwd_reset = $channel_passwd_reset;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDefaultGroup()
+ {
+ return $this->channel_default_group;
+ }
+
+ /**
+ * @param mixed $channel_default_group
+ * @return Channel
+ */
+ public function setDefaultGroup($channel_default_group)
+ {
+ $this->channel_default_group = $channel_default_group;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAllowCid()
+ {
+ return $this->channel_allow_cid;
+ }
+
+ /**
+ * @param mixed $channel_allow_cid
+ * @return Channel
+ */
+ public function setAllowCid($channel_allow_cid)
+ {
+ $this->channel_allow_cid = $channel_allow_cid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAllowGid()
+ {
+ return $this->channel_allow_gid;
+ }
+
+ /**
+ * @param mixed $channel_allow_gid
+ * @return Channel
+ */
+ public function setAllowGid($channel_allow_gid)
+ {
+ $this->channel_allow_gid = $channel_allow_gid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDenyCid()
+ {
+ return $this->channel_deny_cid;
+ }
+
+ /**
+ * @param mixed $channel_deny_cid
+ * @return Channel
+ */
+ public function setDenyCid($channel_deny_cid)
+ {
+ $this->channel_deny_cid = $channel_deny_cid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDenyGid()
+ {
+ return $this->channel_deny_gid;
+ }
+
+ /**
+ * @param mixed $channel_deny_gid
+ * @return Channel
+ */
+ public function setDenyGid($channel_deny_gid)
+ {
+ $this->channel_deny_gid = $channel_deny_gid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRemoved()
+ {
+ return $this->channel_removed;
+ }
+
+ /**
+ * @param mixed $channel_removed
+ * @return Channel
+ */
+ public function setRemoved($channel_removed)
+ {
+ $this->channel_removed = $channel_removed;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSystem()
+ {
+ return $this->channel_system;
+ }
+
+ /**
+ * @param mixed $channel_system
+ * @return Channel
+ */
+ public function setSystem($channel_system)
+ {
+ $this->channel_system = $channel_system;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMoved()
+ {
+ return $this->channel_moved;
+ }
+
+ /**
+ * @param mixed $channel_moved
+ * @return Channel
+ */
+ public function setMoved($channel_moved)
+ {
+ $this->channel_moved = $channel_moved;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPassword()
+ {
+ return $this->channel_password;
+ }
+
+ /**
+ * @param mixed $channel_password
+ * @return Channel
+ */
+ public function setPassword($channel_password)
+ {
+ $this->channel_password = $channel_password;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSalt()
+ {
+ return $this->channel_salt;
+ }
+
+ /**
+ * @param mixed $channel_salt
+ * @return Channel
+ */
+ public function setSalt($channel_salt)
+ {
+ $this->channel_salt = $channel_salt;
+ return $this;
+ }
+
+}
diff --git a/Zotlabs/Entity/Item.php b/Zotlabs/Entity/Item.php
new file mode 100644
index 000000000..9e4bb5ee8
--- /dev/null
+++ b/Zotlabs/Entity/Item.php
@@ -0,0 +1,1534 @@
+<?php
+
+namespace Zotlabs\Entity;
+
+use Zotlabs\Lib\BaseObject;
+
+class Item extends BaseObject
+{
+ // primary index auto-increment
+ public $id;
+ // id of the thread top-level parent
+ public $parent;
+
+ // account id of the owner of this record
+ public $aid;
+ // channel id of the owner of this record
+ public $uid;
+
+ // UUID-V4 // If no UUID is provided UUID-V5 of the message id
+ public $uuid;
+
+ // message id
+ public $mid;
+
+ // message id of top-level parent
+ public $parent_mid;
+ // message id of immediate parent
+ public $thr_parent;
+
+ // int thread depth
+ public $item_level;
+
+ // url pointing to the local copy of this item
+ public $llink;
+
+ // url pointing to permalink or this item origin
+ public $plink;
+
+ // UTC datetime the item was created
+ public $created;
+ // UTC datetime the item was changed
+ public $edited;
+ // UTC datetime the item will self-destruct
+ public $expires;
+ // UTC datetime last comment
+ public $commented;
+ // UTC datetime received here
+ public $received;
+ // UTC datetime this record last modified
+ public $changed;
+ // UTC datetime comments will be refused
+ public $comments_closed;
+
+ // portable id of channel that initiated this conversation thread
+ public $owner_xchan;
+ // portable id of item creator
+ public $author_xchan;
+ // portable id of real (upstream) author if relayed
+ public $source_xchan;
+ // MIME type of item body
+ public $mimetype;
+
+ // ISO language string
+ public $lang;
+ // Name of publishing software
+ public $app;
+ // Title of item
+ public $title;
+ // Sommary of item
+ public $summary;
+ // body of item
+ public $body;
+ // html representation
+ public $html;
+ // Activity type
+ public $verb;
+ // Activity object type
+ public $obj_type;
+ // Activity object content JSON
+ public $obj;
+ // Activity target type
+ public $tgt_type;
+ // Activity target content JSON
+ public $target;
+ // attachments
+ public $attach;
+ // signature information
+ public $sig;
+
+ // version of this item
+ public $revision;
+ // message id of controlling layout (CMS use)
+ public $layout_mid;
+ // shared storage for delivery addons
+ public $postopts;
+ // delivery relay tracking
+ public $route;
+ // UUID of attached resource
+ public $resource_id;
+ // table type of attacched resource
+ public $resource_type;
+
+ // free-form text location
+ public $location;
+ // combined coordinates (text)
+ public $coord;
+ // string public policy
+ public $public_policy;
+ // string comment policy
+ public $comment_policy;
+ // string encoded array of portable ids
+ public $allow_cid;
+ // string encoded array of access group UUIDs
+ public $allow_gid;
+ // string encoded array blocked portable ids
+ public $deny_cid;
+ // string encoded array blocked access group UUIDs
+ public $deny_gid;
+ public $item_restrict;
+ public $item_flags;
+ public $item_private;
+ public $item_origin;
+ public $item_unseen;
+ public $item_starred;
+ public $item_uplink;
+ public $item_consensus;
+ public $item_wall;
+ public $item_thread_top;
+ public $item_notshown;
+ public $item_nsfw;
+ public $item_relay;
+ public $item_mentionsme;
+ public $item_nocomment;
+ public $item_obscured;
+ public $item_verified;
+ public $item_retained;
+ public $item_rss;
+ public $item_deleted;
+ public $item_type;
+ public $item_hidden;
+ public $item_unpublished;
+ public $item_delayed;
+ public $item_pending_remove;
+ public $item_blocked;
+
+ /**
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param mixed $id
+ * @return Item
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMid()
+ {
+ return $this->mid;
+ }
+
+ /**
+ * @param mixed $mid
+ * @return Item
+ */
+ public function setMid($mid)
+ {
+ $this->mid = $mid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUuid()
+ {
+ return $this->uuid;
+ }
+
+ /**
+ * @param mixed $uuid
+ * @return Item
+ */
+ public function setUuid($uuid)
+ {
+ $this->uuid = $uuid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAid()
+ {
+ return $this->aid;
+ }
+
+ /**
+ * @param mixed $aid
+ * @return Item
+ */
+ public function setAid($aid)
+ {
+ $this->aid = $aid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUid()
+ {
+ return $this->uid;
+ }
+
+ /**
+ * @param mixed $uid
+ * @return Item
+ */
+ public function setUid($uid)
+ {
+ $this->uid = $uid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * @param mixed $parent
+ * @return Item
+ */
+ public function setParent($parent)
+ {
+ $this->parent = $parent;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getParentMid()
+ {
+ return $this->parent_mid;
+ }
+
+ /**
+ * @param mixed $parent_mid
+ * @return Item
+ */
+ public function setParentMid($parent_mid)
+ {
+ $this->parent_mid = $parent_mid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getThrParent()
+ {
+ return $this->thr_parent;
+ }
+
+ /**
+ * @param mixed $thr_parent
+ * @return Item
+ */
+ public function setThrParent($thr_parent)
+ {
+ $this->thr_parent = $thr_parent;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLevel()
+ {
+ return $this->item_level;
+ }
+
+ /**
+ * @param mixed $item_level
+ * @return Item
+ */
+ public function setLevel($item_level)
+ {
+ $this->item_level = $item_level;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCreated()
+ {
+ return $this->created;
+ }
+
+ /**
+ * @param mixed $created
+ * @return Item
+ */
+ public function setCreated($created)
+ {
+ $this->created = $created;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getEdited()
+ {
+ return $this->edited;
+ }
+
+ /**
+ * @param mixed $edited
+ * @return Item
+ */
+ public function setEdited($edited)
+ {
+ $this->edited = $edited;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->expires;
+ }
+
+ /**
+ * @param mixed $expires
+ * @return Item
+ */
+ public function setExpires($expires)
+ {
+ $this->expires = $expires;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCommented()
+ {
+ return $this->commented;
+ }
+
+ /**
+ * @param mixed $commented
+ * @return Item
+ */
+ public function setCommented($commented)
+ {
+ $this->commented = $commented;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getReceived()
+ {
+ return $this->received;
+ }
+
+ /**
+ * @param mixed $received
+ * @return Item
+ */
+ public function setReceived($received)
+ {
+ $this->received = $received;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getChanged()
+ {
+ return $this->changed;
+ }
+
+ /**
+ * @param mixed $changed
+ * @return Item
+ */
+ public function setChanged($changed)
+ {
+ $this->changed = $changed;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCommentsClosed()
+ {
+ return $this->comments_closed;
+ }
+
+ /**
+ * @param mixed $comments_closed
+ * @return Item
+ */
+ public function setCommentsClosed($comments_closed)
+ {
+ $this->comments_closed = $comments_closed;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOwnerXchan()
+ {
+ return $this->owner_xchan;
+ }
+
+ /**
+ * @param mixed $owner_xchan
+ * @return Item
+ */
+ public function setOwnerXchan($owner_xchan)
+ {
+ $this->owner_xchan = $owner_xchan;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAuthorXchan()
+ {
+ return $this->author_xchan;
+ }
+
+ /**
+ * @param mixed $author_xchan
+ * @return Item
+ */
+ public function setAuthorXchan($author_xchan)
+ {
+ $this->author_xchan = $author_xchan;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSourceXchan()
+ {
+ return $this->source_xchan;
+ }
+
+ /**
+ * @param mixed $source_xchan
+ * @return Item
+ */
+ public function setSourceXchan($source_xchan)
+ {
+ $this->source_xchan = $source_xchan;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getApproved()
+ {
+ return $this->approved;
+ }
+
+ /**
+ * @param mixed $approved
+ * @return Item
+ */
+ public function setApproved($approved)
+ {
+ $this->approved = $approved;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMimetype()
+ {
+ return $this->mimetype;
+ }
+
+ /**
+ * @param mixed $mimetype
+ * @return Item
+ */
+ public function setMimetype($mimetype)
+ {
+ $this->mimetype = $mimetype;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getReplyto()
+ {
+ return $this->replyto;
+ }
+
+ /**
+ * @param mixed $replyto
+ * @return Item
+ */
+ public function setReplyto($replyto)
+ {
+ $this->replyto = $replyto;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * @param mixed $title
+ * @return Item
+ */
+ public function setTitle($title)
+ {
+ $this->title = $title;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSummary()
+ {
+ return $this->summary;
+ }
+
+ /**
+ * @param mixed $summary
+ * @return Item
+ */
+ public function setSummary($summary)
+ {
+ $this->summary = $summary;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ /**
+ * @param mixed $body
+ * @return Item
+ */
+ public function setBody($body)
+ {
+ $this->body = $body;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHtml()
+ {
+ return $this->html;
+ }
+
+ /**
+ * @param mixed $html
+ * @return Item
+ */
+ public function setHtml($html)
+ {
+ $this->html = $html;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getApp()
+ {
+ return $this->app;
+ }
+
+ /**
+ * @param mixed $app
+ * @return Item
+ */
+ public function setApp($app)
+ {
+ $this->app = $app;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLang()
+ {
+ return $this->lang;
+ }
+
+ /**
+ * @param mixed $lang
+ * @return Item
+ */
+ public function setLang($lang)
+ {
+ $this->lang = $lang;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRevision()
+ {
+ return $this->revision;
+ }
+
+ /**
+ * @param mixed $revision
+ * @return Item
+ */
+ public function setRevision($revision)
+ {
+ $this->revision = $revision;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getVerb()
+ {
+ return $this->verb;
+ }
+
+ /**
+ * @param mixed $verb
+ * @return Item
+ */
+ public function setVerb($verb)
+ {
+ $this->verb = $verb;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getObjType()
+ {
+ return $this->obj_type;
+ }
+
+ /**
+ * @param mixed $obj_type
+ * @return Item
+ */
+ public function setObjType($obj_type)
+ {
+ $this->obj_type = $obj_type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getObj()
+ {
+ return $this->obj;
+ }
+
+ /**
+ * @param mixed $obj
+ * @return Item
+ */
+ public function setObj($obj)
+ {
+ $this->obj = $obj;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTgtType()
+ {
+ return $this->tgt_type;
+ }
+
+ /**
+ * @param mixed $tgt_type
+ * @return Item
+ */
+ public function setTgtType($tgt_type)
+ {
+ $this->tgt_type = $tgt_type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getTarget()
+ {
+ return $this->target;
+ }
+
+ /**
+ * @param mixed $target
+ * @return Item
+ */
+ public function setTarget($target)
+ {
+ $this->target = $target;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLayoutMid()
+ {
+ return $this->layout_mid;
+ }
+
+ /**
+ * @param mixed $layout_mid
+ * @return Item
+ */
+ public function setLayoutMid($layout_mid)
+ {
+ $this->layout_mid = $layout_mid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPostopts()
+ {
+ return $this->postopts;
+ }
+
+ /**
+ * @param mixed $postopts
+ * @return Item
+ */
+ public function setPostopts($postopts)
+ {
+ $this->postopts = $postopts;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRoute()
+ {
+ return $this->route;
+ }
+
+ /**
+ * @param mixed $route
+ * @return Item
+ */
+ public function setRoute($route)
+ {
+ $this->route = $route;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLlink()
+ {
+ return $this->llink;
+ }
+
+ /**
+ * @param mixed $llink
+ * @return Item
+ */
+ public function setLlink($llink)
+ {
+ $this->llink = $llink;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPlink()
+ {
+ return $this->plink;
+ }
+
+ /**
+ * @param mixed $plink
+ * @return Item
+ */
+ public function setPlink($plink)
+ {
+ $this->plink = $plink;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getResourceId()
+ {
+ return $this->resource_id;
+ }
+
+ /**
+ * @param mixed $resource_id
+ * @return Item
+ */
+ public function setResourceId($resource_id)
+ {
+ $this->resource_id = $resource_id;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getResourceType()
+ {
+ return $this->resource_type;
+ }
+
+ /**
+ * @param mixed $resource_type
+ * @return Item
+ */
+ public function setResourceType($resource_type)
+ {
+ $this->resource_type = $resource_type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAttach()
+ {
+ return $this->attach;
+ }
+
+ /**
+ * @param mixed $attach
+ * @return Item
+ */
+ public function setAttach($attach)
+ {
+ $this->attach = $attach;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSig()
+ {
+ return $this->sig;
+ }
+
+ /**
+ * @param mixed $sig
+ * @return Item
+ */
+ public function setSig($sig)
+ {
+ $this->sig = $sig;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLocation()
+ {
+ return $this->location;
+ }
+
+ /**
+ * @param mixed $location
+ * @return Item
+ */
+ public function setLocation($location)
+ {
+ $this->location = $location;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCoord()
+ {
+ return $this->coord;
+ }
+
+ /**
+ * @param mixed $coord
+ * @return Item
+ */
+ public function setCoord($coord)
+ {
+ $this->coord = $coord;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPublicPolicy()
+ {
+ return $this->public_policy;
+ }
+
+ /**
+ * @param mixed $public_policy
+ * @return Item
+ */
+ public function setPublicPolicy($public_policy)
+ {
+ $this->public_policy = $public_policy;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getCommentPolicy()
+ {
+ return $this->comment_policy;
+ }
+
+ /**
+ * @param mixed $comment_policy
+ * @return Item
+ */
+ public function setCommentPolicy($comment_policy)
+ {
+ $this->comment_policy = $comment_policy;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAllowCid()
+ {
+ return $this->allow_cid;
+ }
+
+ /**
+ * @param mixed $allow_cid
+ * @return Item
+ */
+ public function setAllowCid($allow_cid)
+ {
+ $this->allow_cid = $allow_cid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getAllowGid()
+ {
+ return $this->allow_gid;
+ }
+
+ /**
+ * @param mixed $allow_gid
+ * @return Item
+ */
+ public function setAllowGid($allow_gid)
+ {
+ $this->allow_gid = $allow_gid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDenyCid()
+ {
+ return $this->deny_cid;
+ }
+
+ /**
+ * @param mixed $deny_cid
+ * @return Item
+ */
+ public function setDenyCid($deny_cid)
+ {
+ $this->deny_cid = $deny_cid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDenyGid()
+ {
+ return $this->deny_gid;
+ }
+
+ /**
+ * @param mixed $deny_gid
+ * @return Item
+ */
+ public function setDenyGid($deny_gid)
+ {
+ $this->deny_gid = $deny_gid;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRestrict()
+ {
+ return $this->item_restrict;
+ }
+
+ /**
+ * @param mixed $item_restrict
+ * @return Item
+ */
+ public function setRestrict($item_restrict)
+ {
+ $this->item_restrict = $item_restrict;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getFlags()
+ {
+ return $this->item_flags;
+ }
+
+ /**
+ * @param mixed $item_flags
+ * @return Item
+ */
+ public function setFlags($item_flags)
+ {
+ $this->item_flags = $item_flags;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrivate()
+ {
+ return $this->item_private;
+ }
+
+ /**
+ * @param mixed $item_private
+ * @return Item
+ */
+ public function setPrivate($item_private)
+ {
+ $this->item_private = $item_private;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOrigin()
+ {
+ return $this->item_origin;
+ }
+
+ /**
+ * @param mixed $item_origin
+ * @return Item
+ */
+ public function setOrigin($item_origin)
+ {
+ $this->item_origin = $item_origin;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUnseen()
+ {
+ return $this->item_unseen;
+ }
+
+ /**
+ * @param mixed $item_unseen
+ * @return Item
+ */
+ public function setUnseen($item_unseen)
+ {
+ $this->item_unseen = $item_unseen;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStarred()
+ {
+ return $this->item_starred;
+ }
+
+ /**
+ * @param mixed $item_starred
+ * @return Item
+ */
+ public function setStarred($item_starred)
+ {
+ $this->item_starred = $item_starred;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUplink()
+ {
+ return $this->item_uplink;
+ }
+
+ /**
+ * @param mixed $item_uplink
+ * @return Item
+ */
+ public function setUplink($item_uplink)
+ {
+ $this->item_uplink = $item_uplink;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getConsensus()
+ {
+ return $this->item_consensus;
+ }
+
+ /**
+ * @param mixed $item_consensus
+ * @return Item
+ */
+ public function setConsensus($item_consensus)
+ {
+ $this->item_consensus = $item_consensus;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getWall()
+ {
+ return $this->item_wall;
+ }
+
+ /**
+ * @param mixed $item_wall
+ * @return Item
+ */
+ public function setWall($item_wall)
+ {
+ $this->item_wall = $item_wall;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getThreadTop()
+ {
+ return $this->item_thread_top;
+ }
+
+ /**
+ * @param mixed $item_thread_top
+ * @return Item
+ */
+ public function setThreadTop($item_thread_top)
+ {
+ $this->item_thread_top = $item_thread_top;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNotshown()
+ {
+ return $this->item_notshown;
+ }
+
+ /**
+ * @param mixed $item_notshown
+ * @return Item
+ */
+ public function setNotshown($item_notshown)
+ {
+ $this->item_notshown = $item_notshown;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNsfw()
+ {
+ return $this->item_nsfw;
+ }
+
+ /**
+ * @param mixed $item_nsfw
+ * @return Item
+ */
+ public function setNsfw($item_nsfw)
+ {
+ $this->item_nsfw = $item_nsfw;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRelay()
+ {
+ return $this->item_relay;
+ }
+
+ /**
+ * @param mixed $item_relay
+ * @return Item
+ */
+ public function setRelay($item_relay)
+ {
+ $this->item_relay = $item_relay;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getMentionsme()
+ {
+ return $this->item_mentionsme;
+ }
+
+ /**
+ * @param mixed $item_mentionsme
+ * @return Item
+ */
+ public function setMentionsme($item_mentionsme)
+ {
+ $this->item_mentionsme = $item_mentionsme;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getNocomment()
+ {
+ return $this->item_nocomment;
+ }
+
+ /**
+ * @param mixed $item_nocomment
+ * @return Item
+ */
+ public function setNocomment($item_nocomment)
+ {
+ $this->item_nocomment = $item_nocomment;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getObscured()
+ {
+ return $this->item_obscured;
+ }
+
+ /**
+ * @param mixed $item_obscured
+ * @return Item
+ */
+ public function setObscured($item_obscured)
+ {
+ $this->item_obscured = $item_obscured;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getVerified()
+ {
+ return $this->item_verified;
+ }
+
+ /**
+ * @param mixed $item_verified
+ * @return Item
+ */
+ public function setVerified($item_verified)
+ {
+ $this->item_verified = $item_verified;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRetained()
+ {
+ return $this->item_retained;
+ }
+
+ /**
+ * @param mixed $item_retained
+ * @return Item
+ */
+ public function setRetained($item_retained)
+ {
+ $this->item_retained = $item_retained;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getRss()
+ {
+ return $this->item_rss;
+ }
+
+ /**
+ * @param mixed $item_rss
+ * @return Item
+ */
+ public function setRss($item_rss)
+ {
+ $this->item_rss = $item_rss;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDeleted()
+ {
+ return $this->item_deleted;
+ }
+
+ /**
+ * @param mixed $item_deleted
+ * @return Item
+ */
+ public function setDeleted($item_deleted)
+ {
+ $this->item_deleted = $item_deleted;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->item_type;
+ }
+
+ /**
+ * @param mixed $item_type
+ * @return Item
+ */
+ public function setType($item_type)
+ {
+ $this->item_type = $item_type;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHidden()
+ {
+ return $this->item_hidden;
+ }
+
+ /**
+ * @param mixed $item_hidden
+ * @return Item
+ */
+ public function setHidden($item_hidden)
+ {
+ $this->item_hidden = $item_hidden;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUnpublished()
+ {
+ return $this->item_unpublished;
+ }
+
+ /**
+ * @param mixed $item_unpublished
+ * @return Item
+ */
+ public function setUnpublished($item_unpublished)
+ {
+ $this->item_unpublished = $item_unpublished;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getDelayed()
+ {
+ return $this->item_delayed;
+ }
+
+ /**
+ * @param mixed $item_delayed
+ * @return Item
+ */
+ public function setDelayed($item_delayed)
+ {
+ $this->item_delayed = $item_delayed;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPendingRemove()
+ {
+ return $this->item_pending_remove;
+ }
+
+ /**
+ * @param mixed $item_pending_remove
+ * @return Item
+ */
+ public function setPendingRemove($item_pending_remove)
+ {
+ $this->item_pending_remove = $item_pending_remove;
+ return $this;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getBlocked()
+ {
+ return $this->item_blocked;
+ }
+
+ /**
+ * @param mixed $item_blocked
+ * @return Item
+ */
+ public function setBlocked($item_blocked)
+ {
+ $this->item_blocked = $item_blocked;
+ return $this;
+ }
+
+
+
+}
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 448b88ff4..54a1b8d2a 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -8,6 +8,7 @@ use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig;
+use Zotlabs\Entity\Item;
require_once('include/event.php');
require_once('include/html2plain.php');
@@ -598,6 +599,25 @@ class Activity {
if ($i['mid'] !== $i['parent_mid']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
+
+ $cnv = IConfig::Get($i['parent'], 'activitypub', 'context');
+ if (!$cnv) {
+ $cnv = $i['parent_mid'];
+ }
+ }
+
+ if (empty($cnv)) {
+ $cnv = IConfig::Get($i, 'activitypub', 'context');
+ if (!$cnv) {
+ $cnv = $i['parent_mid'];
+ }
+ }
+
+ if (!empty($cnv)) {
+ if (is_string($cnv) && str_starts_with($cnv, z_root())) {
+ $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
+ }
+ $ret['context'] = $cnv;
}
if ($i['mimetype'] === 'text/bbcode') {
@@ -617,6 +637,12 @@ class Activity {
$t = self::encode_taxonomy($i);
if ($t) {
+ foreach($t as $tag) {
+ if (strcasecmp($tag['name'], '#nsfw') === 0 || strcasecmp($tag['name'], '#sensitive') === 0) {
+ $ret['sensitive'] = true;
+ }
+ }
+
$ret['tag'] = $t;
}
@@ -624,7 +650,20 @@ class Activity {
if ($a) {
$ret['attachment'] = $a;
}
-
+/*
+ if ($i['target']) {
+ if (is_string($i['target'])) {
+ $tmp = json_decode($i['target'], true);
+ if ($tmp !== null) {
+ $i['target'] = $tmp;
+ }
+ }
+ $tgt = self::encode_object($i['target']);
+ if ($tgt) {
+ $ret['target'] = $tgt;
+ }
+ }
+*/
if (intval($i['item_private']) === 0) {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
}
@@ -843,12 +882,32 @@ class Activity {
$ret['type'] = self::activity_mapper($i['verb']);
if ((isset($i['item_deleted']) && intval($i['item_deleted'])) && !$recurse) {
- $is_response = false;
- if (ActivityStreams::is_response_activity($ret['type'])) {
+ if ($i['verb'] === 'Add' && str_contains($i['tgt_type'], 'Collection')) {
+ $ret['id'] = str_replace('/item/', '/activity/', $i['mid']) . '#Remove';
+ $ret['type'] = 'Remove';
+ if (is_string($i['obj'])) {
+ $obj = json_decode($i['obj'], true);
+ }
+ elseif(is_array($i['obj'])) {
+ $obj = $i['obj'];
+ }
+ if (isset($obj['id'])) {
+ $ret['object'] = $obj['id'];
+ }
+ else {
+ $ret['object'] = str_replace('/item/', '/activity/', $i['mid']);
+ }
+ $ret['target'] = is_array($i['target']) ? $i['target'] : json_decode($i['target'], true);
+
+ return $ret;
+ }
+
+ $is_response = ActivityStreams::is_response_activity($ret['type']);
+
+ if ($is_response) {
$ret['type'] = 'Undo';
$fragment = 'undo';
- $is_response = true;
}
else {
$ret['type'] = 'Delete';
@@ -971,9 +1030,28 @@ class Activity {
// inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
// but *not* for comments and RSVPs, where it should only be present in the object
- if (!in_array($ret['type'], ['Create', 'Update', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) {
+ if (!in_array($ret['type'], ['Create', 'Update', 'Add', 'Remove', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
+
+ $cnv = IConfig::Get($i['parent'], 'activitypub', 'context');
+ if (!$cnv) {
+ $cnv = $i['parent_mid'];
+ }
+ }
+
+ if (empty($cnv)) {
+ $cnv = IConfig::Get($i, 'activitypub', 'context');
+ if (!$cnv) {
+ $cnv = $i['parent_mid'];
+ }
+ }
+
+ if (!empty($cnv)) {
+ if (is_string($cnv) && str_starts_with($cnv, z_root())) {
+ $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
+ }
+ $ret['context'] = $cnv;
}
$actor = self::encode_person($i['author'], false);
@@ -1046,6 +1124,7 @@ class Activity {
call_hooks('encode_activity', $hookinfo);
return $hookinfo['encoded'];
+
}
// Returns an array of URLS for any mention tags found in the item array $i.
@@ -1567,9 +1646,9 @@ class Activity {
}
if (in_array($observer, [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
- drop_item($r[0]['id'], false, (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
+ drop_item($r[0]['id'], (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL), observer_hash: $observer);
} elseif (in_array($act->actor['id'], [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
- drop_item($r[0]['id'], false, (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
+ drop_item($r[0]['id'], (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
}
sync_an_item($channel['channel_id'], $r[0]['id']);
@@ -1867,129 +1946,170 @@ class Activity {
}
- static function update_poll($item_id, $post) {
+ static function update_poll($pollItem, $response) {
+
+ logger('updating poll');
- $multi = false;
- $mid = $post['mid'];
- $content = $post['title'];
+ $multi = false;
- if (!$item_id) {
+ if (!$pollItem) {
+ logger('no item');
return false;
}
- if (intval($post['item_blocked']) === ITEM_MODERATED) {
+ if (intval($pollItem['item_blocked']) === ITEM_MODERATED) {
+ logger('item blocked');
return false;
}
+ $channel = channelx_by_n($pollItem['uid']);
+ if (!$channel) {
+ logger('no channel');
+ return false;
+ }
+
+ $relatedItem = find_related($pollItem);
+
+ $ids = (($relatedItem) ? $pollItem['id'] . ',' . $relatedItem['id'] : $pollItem['id']);
+
dbq("START TRANSACTION");
+ // Using the provided items as is will produce desastrous race conditions
+ // in case of multiple choice polls - hence:
- $item = q("SELECT * FROM item WHERE id = %d FOR UPDATE",
- intval($item_id)
- );
+ $items = dbq("SELECT * FROM item WHERE id in ($ids) FOR UPDATE");
- if (!$item) {
- dbq("COMMIT");
- return false;
+ foreach ($items as $item) {
+ if ($item['id'] === $pollItem['id']) {
+ $pollItem = $item;
+ }
+ if (!empty($relatedItem['id']) && $item['id'] === $relatedItem['id']) {
+ $relatedItem = $item;
+ }
}
- $item = $item[0];
+ $o = json_decode($pollItem['obj'], true);
- $o = json_decode($item['obj'], true);
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'])
- );
+ if ($response) {
+ $mid = $response['mid'];
+ $content = trim($response['title']);
- // prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf
+ $r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s' and mid != parent_mid ",
+ dbesc($pollItem['mid']),
+ dbesc($response['author_xchan'])
+ );
- if ($r) {
- if ($multi) {
- foreach ($r as $rv) {
- if ($rv['title'] === $content && $rv['mid'] !== $mid) {
- return false;
+ // 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 (trim($rv['title']) === $content && $rv['mid'] !== $mid) {
+ logger('already voted multi');
+ return false;
+ }
}
- }
- }
- else {
- foreach ($r as $rv) {
- if ($rv['mid'] !== $mid) {
- return false;
+ } else {
+ foreach ($r as $rv) {
+ if ($rv['mid'] !== $mid && $content) {
+ logger('already voted');
+ return false;
+ }
}
}
}
- }
- $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 (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
- $found = true;
+ $answer_found = false;
+ $foundPrevious = false;
+ if ($multi) {
+ for ($c = 0; $c < count($o['anyOf']); $c++) {
+ if (trim($o['anyOf'][$c]['name']) === $content) {
+ $answer_found = true;
+
+
+ if (is_array($o['anyOf'][$c]['replies'])) {
+ foreach ($o['anyOf'][$c]['replies'] as $reply) {
+ if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
+ $foundPrevious = true;
+ }
}
}
- }
- if (!$found) {
- $o['anyOf'][$c]['replies']['totalItems']++;
- $o['anyOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
+ if (!$foundPrevious) {
+ $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 (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
- $found = true;
+ } else {
+ for ($c = 0; $c < count($o['oneOf']); $c++) {
+ if (trim($o['oneOf'][$c]['name']) === $content) {
+ $answer_found = true;
+ if (is_array($o['oneOf'][$c]['replies'])) {
+ foreach ($o['oneOf'][$c]['replies'] as $reply) {
+ if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
+ $foundPrevious = true;
+ }
}
}
- }
- if (!$found) {
- $o['oneOf'][$c]['replies']['totalItems']++;
- $o['oneOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
+ if (!$foundPrevious) {
+ $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) {
- $u = q("update item set obj = '%s', edited = '%s' where id = %d",
- dbesc(json_encode($o)),
- dbesc(datetime_convert()),
- intval($item['id'])
- );
+ if ($pollItem['comments_closed'] > NULL_DATE) {
+ if ($pollItem['comments_closed'] > datetime_convert()) {
+ $o['closed'] = datetime_convert('UTC', 'UTC', $pollItem['comments_closed'], ATOM_TIME);
+ // set this to force an update
+ $answer_found = true;
+ }
+ }
- if ($u) {
- dbq("COMMIT");
+ // A change was made locally
+ if ($response && $answer_found && !$foundPrevious) {
- if ($multi) {
- // wait some seconds for possible multiple answers to be processed
- // before calling the notifier
- sleep(3);
- }
+ // update this copy
+ $i = [$pollItem];
+ xchan_query($i, true);
+ $i = fetch_post_tags($i);
+ $i[0]['obj'] = $o;
- Master::Summon(['Notifier', 'wall-new', $item['id']]);
- return true;
- }
+ // create the new object
+ $newObj = self::build_packet(self::encode_activity($i[0]), $channel, true);
- dbq("ROLLBACK");
+ // and immediately update the db
+ $u = q("UPDATE item
+ SET obj = (
+ CASE
+ WHEN item.id = %d THEN '%s'
+ WHEN item.id = %d THEN '%s'
+ END
+ ),
+ edited = '%s'
+ WHERE id IN ($ids)",
+ intval($pollItem['id']),
+ dbesc(json_encode($o)),
+ intval($relatedItem['id']),
+ dbesc($newObj),
+ dbesc(datetime_convert())
+ );
+
+ dbq("COMMIT");
+ Master::Summon(['Notifier', 'edit_post', $pollItem['id'], $response['mid']]);
+ if (!empty($relatedItem['id'])) {
+ Master::Summon(['Notifier', 'edit_post', $relatedItem['id'], $response['mid']]);
+ }
}
- dbq("COMMIT");
- return false;
+ return true;
}
static function decode_note($act) {
@@ -2245,6 +2365,16 @@ class Activity {
$s['obj']['actor'] = $s['obj']['actor']['id'];
}
+ if (is_array($act->tgt) && $act->tgt) {
+ if (array_key_exists('type', $act->tgt)) {
+ $s['tgt_type'] = self::activity_obj_mapper($act->tgt['type']);
+ }
+ // We shouldn't need to store collection contents which could be large. We will often only require the meta-data
+ if (isset($s['tgt_type']) && str_contains($s['tgt_type'], 'Collection')) {
+ $s['target'] = ['id' => $act->tgt['id'], 'type' => $s['tgt_type'], 'attributedTo' => $act->tgt['attributedTo'] ?? $act->tgt['actor']];
+ }
+ }
+
$generator = $act->get_property_obj('generator');
if ((!$generator) && (!$response_activity)) {
$generator = $act->get_property_obj('generator', $act->obj);
@@ -2828,6 +2958,10 @@ class Activity {
// This isn't perfect but the best we can do for now.
$item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated');
+ if (!empty($act->obj['context'])) {
+ IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1);
+ }
+
IConfig::Set($item, 'activitypub', 'recips', $act->raw_recips);
if (intval($act->sigok)) {
@@ -3015,24 +3149,6 @@ class Activity {
}
$a = new ActivityStreams($n);
-
- logger($a->debug(), LOGGER_DATA);
-
- if (!$a->is_valid()) {
- logger('not a valid activity');
- break;
- }
-
- if (in_array($a->type, ['Add', 'Remove'])
- && is_array($a->obj)
- && array_key_exists('object', $a->obj)
- && array_key_exists('actor', $a->obj)
- && !empty($a->tgt)) {
-
- logger('unsupported collection operation', LOGGER_DEBUG);
- return;
- }
-
if ($a->type === 'Announce' && is_array($a->obj)
&& array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
@@ -3041,6 +3157,13 @@ class Activity {
$a = new ActivityStreams($a->obj);
}
+ logger($a->debug(), LOGGER_DATA);
+
+ if (!$a->is_valid()) {
+ logger('not a valid activity');
+ break;
+ }
+
$item = Activity::decode_note($a);
if (!$item) {
@@ -3648,5 +3771,72 @@ class Activity {
}
}
+ public static function addToCollection($channel, $object, $target, $sourceItem = null, $deliver = true) {
+ if (!isset($channel['xchan_hash'])) {
+ $channel = channelx_by_hash($channel['channel_hash']);
+ }
+
+ $item = ((new Item())
+ ->setUid($channel['channel_id'])
+ ->setVerb('Add')
+ ->setAuthorXchan($channel['channel_hash'])
+ ->setOwnerXchan($channel['channel_hash'])
+ ->setObj($object)
+ ->setObjType($object['type'])
+ ->setParentMid(str_replace('/conversation/','/item/', $target))
+ ->setThrParent(str_replace('/conversation/','/item/', $target))
+ // ->setApproved($object['object']['id'] ?? '')
+ // ->setReplyto(z_root() . '/channel/' . $channel['channel_address'])
+ ->setTgtType('Collection')
+ ->setTarget([
+ 'id' => str_replace('/item/','/conversation/', $target),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $channel['channel_address'],
+ ])
+ );
+ if ($sourceItem) {
+ $item->setSourceXchan($sourceItem['source_xchan'])
+ ->setAllowCid($sourceItem['allow_cid'])
+ ->setAllowGid($sourceItem['allow_gid'])
+ ->setDenyCid($sourceItem['deny_cid'])
+ ->setDenyGid($sourceItem['deny_gid'])
+ ->setPrivate($sourceItem['item_private'])
+ ->setNocomment($sourceItem['item_nocomment'])
+ ->setCommentPolicy($sourceItem['comment_policy'])
+ ->setPublicPolicy($sourceItem['public_policy'])
+ ->setPostopts($sourceItem['postopts']);
+ }
+ $result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false);
+ logger('addToCollection: ' . print_r($result, true));
+ return $result;
+ }
+
+ public static function removeFromCollection($channel, $object, $target, $deliver = true) {
+ if (!isset($channel['xchan_hash'])) {
+ $channel = channelx_by_hash($channel['channel_hash']);
+ }
+
+ $item = ((new Item())
+ ->setUid($channel['channel_id'])
+ ->setVerb('Remove')
+ ->setAuthorXchan($channel['channel_hash'])
+ ->setOwnerXchan($channel['channel_hash'])
+ ->setObj($object)
+ ->setObjType($object['type'])
+ ->setParentMid(str_replace('/conversation/','/item/', $target))
+ ->setThrParent(str_replace('/conversation/','/item/', $target))
+ ->setReplyto(z_root() . '/channel/' . $channel['channel_address'])
+ ->setTgtType('Collection')
+ ->setTarget([
+ 'id' => str_replace('/item/','/conversation/', $target),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $channel['channel_address']
+ ])
+ );
+
+ $result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false);
+ logger('removeFromCollection: ' . print_r($result, true));
+ return $result;
+ }
}
diff --git a/Zotlabs/Lib/BaseObject.php b/Zotlabs/Lib/BaseObject.php
new file mode 100644
index 000000000..7125d34cb
--- /dev/null
+++ b/Zotlabs/Lib/BaseObject.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+use Zotlabs\ActivityStreams\UnhandledElementException;
+
+class BaseObject
+{
+
+ public $string;
+ public $ldContext;
+
+ /**
+ * @param $input
+ * @param $strict
+ * @throws UnhandledElementException if $strict
+ */
+
+ public function __construct($input = null, $strict = false)
+ {
+ if (isset($input)) {
+ if (is_string($input)) {
+ $this->string = $input;
+ }
+ elseif(is_array($input)) {
+ foreach ($input as $key => $value) {
+ $key = ($key === '@context') ? 'ldContext' : $key;
+ if ($strict && !property_exists($this, $key)) {
+ throw new UnhandledElementException("Unhandled element: $key");
+ }
+ $this->{$key} = $value;
+ }
+ }
+ }
+ return $this;
+ }
+
+ public function getDataType($element, $object = null)
+ {
+ $object = $object ?? $this;
+ $type = gettype($object[$element]);
+ if ($type === 'array' && array_is_list($object[$element])) {
+ return 'list';
+ }
+ return $type;
+ }
+
+ public function toArray()
+ {
+ if ($this->string) {
+ return $this->string;
+ }
+ $returnValue = [];
+ foreach ((array) $this as $key => $value) {
+ if (isset($value)) {
+ $key = ($key === 'ldContext') ? '@context' : $key;
+ $returnValue[$key] = (($value instanceof BaseObject) ? $value->toArray() : $value);
+ }
+ }
+ return $returnValue;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLdContext()
+ {
+ return $this->ldContext;
+ }
+
+ /**
+ * @param mixed $ldContext
+ * @return BaseObject
+ */
+ public function setLdContext($ldContext)
+ {
+ $this->ldContext = $ldContext;
+ return $this;
+ }
+}
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index 05134f433..be2305c04 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -1134,6 +1134,7 @@ class Libzot {
}
$message_request = false;
+ $is_collection_operation = false;
$has_data = array_key_exists('data', $env) && $env['data'];
@@ -1141,26 +1142,37 @@ class Libzot {
$AS = null;
+
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
- if (!$AS->is_valid()) {
- logger('Activity rejected: ' . print_r($data, true));
- return;
- }
+ // process add/remove from collection separately, as it requires a target.
+ // use the raw object, as it will not include actor expansion
if (in_array($AS->type, ['Add', 'Remove'])
&& is_array($AS->obj)
&& array_key_exists('object', $AS->obj)
&& array_key_exists('actor', $AS->obj)
&& !empty($AS->tgt)) {
- logger('unsupported collection operation', LOGGER_DEBUG);
- return;
+ logger('relayed collection operation', LOGGER_DEBUG);
+ $is_collection_operation = true;
+
+ $original_id = $AS->id;
+ $original_type = $AS->type;
+
+ $raw_activity = $AS->data;
+
+ $AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
+
+ // Store the original activity id and type for later usage
+ $AS->meta['original_id'] = $original_id;
+ $AS->meta['original_type'] = $original_type;
}
if (is_array($AS->obj)) {
$item = Activity::decode_note($AS);
+
if (!$item) {
logger('Could not decode activity: ' . print_r($AS, true));
return;
@@ -1170,6 +1182,11 @@ class Libzot {
$item = [];
}
+ if (!$AS->is_valid()) {
+ logger('Activity rejected: ' . print_r($data, true));
+ return;
+ }
+
logger($AS->debug(), LOGGER_DATA);
}
@@ -1313,7 +1330,7 @@ class Libzot {
$relay = (($env['type'] === 'response') ? true : false);
- $result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request);
+ $result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request, false, $is_collection_operation);
Activity::init_background_fetch($env['sender']);
}
@@ -1529,7 +1546,7 @@ class Libzot {
* @return array
*/
- static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false) {
+ static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false, $is_collection_operation = false) {
$result = [];
// We've validated the sender. Now make sure that the sender is the owner or author
@@ -1557,6 +1574,14 @@ class Libzot {
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
+ $conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
+
+ if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
+ $DR->update('not a collection activity');
+ $result[] = $DR->get();
+ continue;
+ }
+
if (($act) && ($act->obj) && (!is_array($act->obj))) {
// The initial object fetch failed using the sys channel credentials.
// Try again using the delivery channel credentials.
@@ -1590,6 +1615,8 @@ class Libzot {
*
*/
+
+
if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && !str_starts_with($arr['mid'], z_root())) {
$DR->update('self delivery ignored');
$result[] = $DR->get();
@@ -1838,11 +1865,19 @@ class Libzot {
dbesc($arr['author_xchan'])
);
- // reactions such as like and dislike could have an mid with /activity/ in it.
+ // If we import an add/remove activity ($is_collection_operation) we strip off the
+ // add/remove part and only process the object.
+ // When looking up the item to pass it to the notifier for relay, we need to look up
+ // the original (stripped off) message id which we stored in $act->meta.
+
+ $sql_mid = (($is_collection_operation && $relay && $channel['channel_hash'] === $arr['owner_xchan']) ? $act->meta['original_id'] : $arr['mid']);
+
+ // Reactions such as like and dislike could have an mid with /activity/ in it.
// Check for both forms in order to prevent duplicates.
- $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
- dbesc($arr['mid']),
- dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
+
+ $r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1",
+ dbesc($sql_mid),
+ dbesc(reverse_activity_mid($sql_mid)),
intval($channel['channel_id'])
);
@@ -1871,21 +1906,29 @@ class Libzot {
$DR->update('update ignored');
$result[] = $DR->get();
}
+
+ if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
+ $approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
+ }
+
}
else {
$DR->update('update ignored');
$result[] = $DR->get();
- // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit),
+ // We need this line to ensure wall-to-wall comments and add/remove activities are relayed (by falling through to the relay bit),
// and at the same time not relay any other relayable posts more than once, because to do so is very wasteful.
if (!intval($r[0]['item_origin']))
continue;
}
+
+
}
else {
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
+
// if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered.
$item_source = check_item_source($arr['uid'], $arr);
@@ -1914,10 +1957,15 @@ class Libzot {
}
if (post_is_importable($arr['uid'], $arr, $abook)) {
- $item_result = item_store($arr);
+ $item_result = item_store($arr, addAndSync: false);
+
if ($item_result['success']) {
$item_id = $item_result['item_id'];
+ if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
+ $approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
+ }
+
if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
event_addtocal($item_id, $channel['channel_id']);
}
@@ -1966,6 +2014,10 @@ class Libzot {
if ($relay && $item_id && $stored['item_blocked'] !== ITEM_MODERATED) {
logger('Invoking relay');
Master::Summon(['Notifier', 'relay', intval($item_id)]);
+ if (!empty($approval) && $approval['item_id']) {
+ Master::Summon(['Notifier', 'relay', intval($approval['item_id'])]);
+ }
+
$DR->addto_update('relayed');
$result[] = $DR->get();
}
@@ -2019,12 +2071,7 @@ class Libzot {
$AS = new ActivityStreams($activity);
- if (!$AS->is_valid()) {
- logger('Fetched activity rejected: ' . print_r($activity, true));
- continue;
- }
-
- if ($AS->type === 'Announce' && is_array($AS->obj)
+ if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
&& array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
// Reparse the encapsulated Activity and use that instead
@@ -2032,14 +2079,33 @@ class Libzot {
$AS = new ActivityStreams($AS->obj);
}
+ // process add/remove from collection separately, as it requires a target.
+ // use the raw object, as it will not include actor expansion
if (in_array($AS->type, ['Add', 'Remove'])
&& is_array($AS->obj)
&& array_key_exists('object', $AS->obj)
&& array_key_exists('actor', $AS->obj)
&& !empty($AS->tgt)) {
- logger('unsupported collection operation', LOGGER_DEBUG);
- return;
+ logger('relayed collection operation', LOGGER_DEBUG);
+
+ $is_collection_operation = true;
+
+ $original_id = $AS->id;
+ $original_type = $AS->type;
+
+ $raw_activity = $AS->data;
+
+ $AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
+
+ // Store the original activity id and type for later usage
+ $AS->meta['original_id'] = $original_id;
+ $AS->meta['original_type'] = $original_type;
+ }
+
+ if (!$AS->is_valid()) {
+ logger('Fetched activity rejected: ' . print_r($activity, true));
+ continue;
}
// logger($AS->debug());
@@ -2230,7 +2296,7 @@ class Libzot {
}
- $x = item_store_update($item);
+ $x = item_store_update($item, addAndSync: false);
// If we're updating an event that we've saved locally, we store the item info first
// because event_addtocal will parse the body to get the 'new' event details
@@ -2346,21 +2412,20 @@ class Libzot {
);
}
} else {
- if ($stored['id'] !== $stored['parent']) {
- q(
- "update item set commented = '%s', changed = '%s' where id = %d",
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- intval($stored['parent'])
- );
- }
- }
+ if ($stored['id'] !== $stored['parent']) {
+ q("update item set commented = '%s', changed = '%s' where id = %d",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($stored['parent'])
+ );
+ }
+ }
// Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels
// and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2).
- drop_item($post_id, false, DROPITEM_PHASE1);
+ drop_item($post_id, DROPITEM_PHASE1, uid: $uid);
tag_deliver($uid, $post_id);
}
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index d21d85105..90a3d3fc8 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -544,7 +544,8 @@ class ThreadItem {
'moderate_delete' => t('Delete'),
'rtl' => in_array($item['lang'], rtl_languages()),
'reactions_allowed' => $reactions_allowed,
- 'reaction_str' => [t('Add yours'), t('Remove yours')]
+ 'reaction_str' => [t('Add yours'), t('Remove yours')],
+ 'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection')
);
$arr = array('item' => $item, 'output' => $tmp_item);
diff --git a/Zotlabs/Module/Channel_calendar.php b/Zotlabs/Module/Channel_calendar.php
index 289e3a734..30683404b 100644
--- a/Zotlabs/Module/Channel_calendar.php
+++ b/Zotlabs/Module/Channel_calendar.php
@@ -179,26 +179,14 @@ class Channel_calendar extends Controller {
if ($post_tags)
$datarray['term'] = $post_tags;
- $item_id = event_store_item($datarray, $event);
+ $post = event_store_item($datarray, $event);
- if ($item_id) {
- $r = q("select * from item where id = %d",
- intval($item_id)
- );
- if ($r) {
- xchan_query($r);
- $sync_item = fetch_post_tags($r);
- $z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
- dbesc($r[0]['resource_id']),
- intval($channel['channel_id'])
- );
- if ($z) {
- Libsync::build_sync_packet($channel['channel_id'], array('event_item' => array(encode_item($sync_item[0], true)), 'event' => $z));
- }
- }
+ if (!empty($post['item_id'])) {
+ Master::Summon(['Notifier', 'event', $post['item_id']]);
+ }
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'event', $post['approval_id']]);
}
-
- Master::Summon(array('Notifier', 'event', $item_id));
killme();
@@ -470,13 +458,14 @@ class Channel_calendar extends Controller {
}
else {
// complex deletion that needs to propagate and be performed in phases
- drop_item($i[0]['id'], true, DROPITEM_PHASE1);
+ drop_item($i[0]['id'], DROPITEM_PHASE1);
$complex = true;
}
$ii = q("select * from item where id = %d",
intval($i[0]['id'])
);
+
if ($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
@@ -485,6 +474,9 @@ class Channel_calendar extends Controller {
if ($complex) {
tag_deliver($i[0]['uid'], $i[0]['id']);
+ if (intval($i[0]['item_wall'])) {
+ Master::Summon(['Notifier', 'drop', $i[0]['id']]);
+ }
}
}
}
diff --git a/Zotlabs/Module/Conversation.php b/Zotlabs/Module/Conversation.php
index aa8349f55..c3e6ae5ec 100644
--- a/Zotlabs/Module/Conversation.php
+++ b/Zotlabs/Module/Conversation.php
@@ -16,7 +16,7 @@ class Conversation extends Controller {
public function init() {
- if (ActivityStreams::is_as_request()) {
+ if (ActivityStreams::is_as_request() || Libzot::is_zot_request()) {
$item_id = argv(1);
if (!$item_id) {
@@ -77,7 +77,7 @@ class Conversation extends Controller {
}
}
}
- elseif (Config::get('system', 'require_authenticated_fetch', false)) {
+ elseif (Config::Get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php
index 869de2669..0e07ab71c 100644
--- a/Zotlabs/Module/Impel.php
+++ b/Zotlabs/Module/Impel.php
@@ -164,7 +164,7 @@ class Impel extends \Zotlabs\Web\Controller {
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited'])
- $x = item_store_update($arr,$execflag);
+ $x = item_store_update($arr, $execflag , deliver: false, addAndSync: false);
}
else {
if(($i) && (intval($i[0]['item_deleted']))) {
@@ -175,7 +175,7 @@ class Impel extends \Zotlabs\Web\Controller {
);
}
else
- $x = item_store($arr,$execflag);
+ $x = item_store($arr, $execflag, deliver: false, addAndSync: false);
}
if($x && $x['success']) {
diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php
index 5ace4e72d..7aed6469e 100644
--- a/Zotlabs/Module/Import.php
+++ b/Zotlabs/Module/Import.php
@@ -534,6 +534,7 @@ class Import extends Controller {
if ($api_path) {
$parsed = parse_url($api_path);
unset($parsed['path']);
+ unset($parsed['query']);
// store the import host so we can manually kick off item/file sync later in case anything did not work out
set_pconfig($channel['channel_id'], 'import', 'host', $parsed['host']);
@@ -551,7 +552,7 @@ class Import extends Controller {
$until = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), 'now + 1 day');
//$poll_interval = Config::Get('system', 'poll_interval', 3);
- $page = 0;
+ $page = 0;
Master::Summon(['Content_importer', sprintf('%d', $page), $since, $until, $channel['channel_address'], urlencode($hz_server)]);
Master::Summon(['File_importer', sprintf('%d', $page), $channel['channel_address'], urlencode($hz_server)]);
diff --git a/Zotlabs/Module/Import_progress.php b/Zotlabs/Module/Import_progress.php
index d9b13e8a8..0afb6faed 100644
--- a/Zotlabs/Module/Import_progress.php
+++ b/Zotlabs/Module/Import_progress.php
@@ -29,14 +29,14 @@ class Import_progress extends \Zotlabs\Web\Controller {
$c = PConfig::Get(local_channel(), 'import', 'content_progress');
if ($c) {
- $total_cpages = floor(intval($c['items_total']) / intval($c['items_page']));
+ $total_cpages = round(intval($c['items_total']) / intval($c['items_page']));
if(!$total_cpages) {
- $total_cpages = 1; // because of floor
+ $total_cpages = 1; // because of round
}
$cpage = $c['last_page'] + 1; // because page count start at 0
- $cprogress = intval(floor((intval($cpage) * 100) / $total_cpages));
+ $cprogress = intval(round((intval($cpage) * 100) / $total_cpages));
$ccompleted_str = t('Item sync completed!');
if(argv(1) === 'resume_itemsync' && $cprogress < 100) {
@@ -50,6 +50,7 @@ class Import_progress extends \Zotlabs\Web\Controller {
if ($alive) {
$parsed = parse_url($alive);
unset($parsed['path']);
+ unset($parsed['query']);
$hz_server = unparse_url($parsed);
$since = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), '0001-01-01 00:00');
@@ -79,14 +80,14 @@ class Import_progress extends \Zotlabs\Web\Controller {
$f = PConfig::Get(local_channel(), 'import', 'files_progress');
if ($f) {
- $total_fpages = floor(intval($f['files_total']) / intval($f['files_page']));
+ $total_fpages = round(intval($f['files_total']) / intval($f['files_page']));
if(!$total_fpages) {
$total_fpages = 1;
}
$fpage = $f['last_page'] + 1;
- $fprogress = intval(floor((intval($fpage) * 100) / $total_fpages));
+ $fprogress = intval(round((intval($fpage) * 100) / $total_fpages));
$fcompleted_str = t('File sync completed!');
if(argv(1) === 'resume_filesync' && $fprogress < 100) {
@@ -120,6 +121,7 @@ class Import_progress extends \Zotlabs\Web\Controller {
}
$fcompleted_str = t('File sync completed but no files were found!');
+
}
$fprogress_str = ((intval($fprogress)) ? $fprogress . '%' : $fprogress);
@@ -127,13 +129,15 @@ class Import_progress extends \Zotlabs\Web\Controller {
if(is_ajax()) {
$ret = [
'cprogress' => $cprogress,
- 'fprogress' => $fprogress
+ 'ccompleted_str' => $ccompleted_str,
+ 'fprogress' => $fprogress,
+ 'fcompleted_str' => $fcompleted_str
];
json_return_and_die($ret);
}
- $o = replace_macros(get_markup_template("import_progress.tpl"), [
+ return replace_macros(get_markup_template('import_progress.tpl'), [
'$chtitle_str' => t('Channel clone status'),
'$ctitle_str' => t('Item sync status'),
'$ftitle_str' => t('File sync status'),
@@ -147,8 +151,6 @@ class Import_progress extends \Zotlabs\Web\Controller {
'$resume_str' => t('Resume'),
'$resume_helper_str' => t('Only resume if sync stalled!')
]);
-
- return $o;
}
}
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index fba16fbe1..8ded7c1d7 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -807,18 +807,44 @@ class Item extends Controller {
}
- if ($moderated)
+ if ($moderated) {
$item_blocked = ITEM_MODERATED;
+ }
- if (!strlen($verb))
+ if (!strlen($verb)) {
$verb = 'Create';
+ }
$notify_type = (($parent) ? 'comment-new' : 'wall-new');
$uuid = $uuid ?? $message_id ?? item_message_id();
$mid = $mid ?? z_root() . '/item/' . $uuid;
+
+ // Set the conversation target.
+ if (empty($owner_hash)) {
+ $owner_hash = $owner_xchan['xchan_hash'];
+ }
+
+ if ($owner_hash === $channel['channel_hash']) {
+ $attributedTo = z_root() . '/channel/' . $channel['channel_address'];
+
+ $conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
+ $datarray['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $conversation),
+ 'type' => 'Collection',
+ 'attributedTo' => $attributedTo,
+ ];
+ $datarray['tgt_type'] = 'Collection';
+ }
+ elseif (!empty($parent_item['target'])) {
+ $datarray['target'] = $parent_item['target'];
+ $datarray['tgt_type'] = $parent_item['tgt_type'];
+ }
+
+
+
if ($is_poll) {
$poll = [
'question' => $body,
@@ -1023,6 +1049,7 @@ class Item extends Controller {
$this->add_listeners($datarray);
}
+ /* sync this is done in item_store_update()
if (!$parent) {
$r = q("select * from item where id = %d",
intval($post_id)
@@ -1033,9 +1060,14 @@ class Item extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
}
- if (!$nopush)
- Master::Summon(['Notifier', 'edit_post', $post_id]);
+ */
+ if (!$nopush) {
+ Master::Summon(['Notifier', 'edit_post', $post_id]);
+ if (intval($x['approval_id'])) {
+ Master::Summon(['Notifier', 'edit_post', $x['approval_id']]);
+ }
+ }
if ($api_source)
return ($x);
@@ -1059,6 +1091,7 @@ class Item extends Controller {
}
$post_id = $post['item_id'];
+ $approval_id = $post['approval_id'] ?? 0;
$datarray = $post['item'];
@@ -1133,6 +1166,7 @@ class Item extends Controller {
killme();
}
+ /* sync this is done in item_store_update()
if ($parent || $datarray['item_private'] == 1) {
$r = q("select * from item where id = %d",
intval($post_id)
@@ -1143,6 +1177,7 @@ class Item extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
}
+ */
$datarray['id'] = $post_id;
$datarray['llink'] = z_root() . '/display/' . $datarray['uuid'];
@@ -1153,8 +1188,12 @@ class Item extends Controller {
$nopush = false;
}
- if (!$nopush)
+ if (!$nopush) {
Master::Summon(['Notifier', $notify_type, $post_id]);
+ if ($approval_id) {
+ Master::Summon(['Notifier', $notify_type, $approval_id]);
+ }
+ }
logger('post_complete');
@@ -1209,7 +1248,7 @@ class Item extends Controller {
require_once('include/items.php');
- $i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1",
+ $i = q("select * from item where id = %d limit 1",
intval(argv(2))
);
@@ -1236,7 +1275,6 @@ class Item extends Controller {
$can_delete = true;
}
-
if (!($can_delete || $local_delete)) {
notice(t('Permission denied.') . EOL);
return;
@@ -1252,13 +1290,14 @@ class Item extends Controller {
}
else {
// complex deletion that needs to propagate and be performed in phases
- drop_item($i[0]['id'], true, DROPITEM_PHASE1);
+ drop_item($i[0]['id'], DROPITEM_PHASE1);
$complex = true;
}
$r = q("select * from item where id = %d",
intval($i[0]['id'])
);
+
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
@@ -1267,6 +1306,9 @@ class Item extends Controller {
if ($complex) {
tag_deliver($i[0]['uid'], $i[0]['id']);
+ if (intval($i[0]['item_wall']) || $i[0]['mid'] !== $i[0]['parent_mid']) {
+ Master::Summon(['Notifier', 'drop', $i[0]['id']]);
+ }
}
}
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index d493742e7..2fb3fab83 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -284,7 +284,7 @@ class Like extends Controller {
intval($ch[0]['channel_id'])
);
if ($r)
- drop_item($r[0]['id'], false);
+ drop_item($r[0]['id']);
if ($interactive) {
notice(t('Previous action reversed.') . EOL);
return $o;
@@ -387,17 +387,20 @@ class Like extends Controller {
// already liked it. Drop that item.
require_once('include/items.php');
foreach ($r as $rr) {
- drop_item($rr['id'], false, DROPITEM_PHASE1);
+ drop_item($rr['id'], DROPITEM_PHASE1);
+
// set the changed timestamp on the parent so we'll see the update without a page reload
q("update item set changed = '%s' where id = %d and uid = %d",
dbesc(datetime_convert()),
intval($rr['parent']),
intval($rr['uid'])
);
+
// Prior activity was a duplicate of the one we're submitting, just undo it;
// don't fall through and create another
- if (activity_match($rr['verb'], $activity))
+ if (activity_match($rr['verb'], $activity)) {
$multi_undo = false;
+ }
$d = q("select * from item where id = %d",
intval($rr['id'])
@@ -559,6 +562,7 @@ class Like extends Controller {
$post = item_store($arr);
$post_id = $post['item_id'];
+ $approval_id = $post['approval_id'] ?? 0;
// save the conversation from expiration
@@ -574,6 +578,7 @@ class Like extends Controller {
}
+/* Item sync is now done in item_store()
$r = q("select * from item where id = %d",
intval($post_id)
);
@@ -582,7 +587,7 @@ class Like extends Controller {
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
-
+*/
if ($extended_like) {
$r = q("insert into likes (channel_id,liker,likee,iid,i_mid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s','%s')",
@@ -609,7 +614,10 @@ class Like extends Controller {
}
- Master::Summon(array('Notifier', 'like', $post_id));
+ Master::Summon(['Notifier', 'like', $post_id]);
+ if ($approval_id) {
+ Master::Summon(['Notifier', 'like', $approval_id]);
+ }
if ($interactive) {
notice(t('Action completed.') . EOL);
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
index ed2a1e4f9..2103684ab 100644
--- a/Zotlabs/Module/Moderate.php
+++ b/Zotlabs/Module/Moderate.php
@@ -74,7 +74,7 @@ class Moderate extends \Zotlabs\Web\Controller {
// let the sender know we received their comment but we don't permit spam here.
// Activity::send_rejection_activity(App::get_channel(), $item['author_xchan'], $item);
- drop_item($post_id,false);
+ drop_item($post_id);
notice( t('Item deleted') . EOL);
}
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
index e04b9b257..e1abd242e 100644
--- a/Zotlabs/Module/React.php
+++ b/Zotlabs/Module/React.php
@@ -91,6 +91,9 @@ class React extends Controller {
if ($x['success']) {
$nid = $x['item_id'];
Master::Summon(['Notifier', 'like', $nid]);
+ if (!empty($x['approval_id'])) {
+ Master::Summon(['Notifier', 'like', $x['approval_id']]);
+ }
}
}
diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php
index db0acb6f5..4fefdb4ef 100644
--- a/Zotlabs/Module/Share.php
+++ b/Zotlabs/Module/Share.php
@@ -136,6 +136,7 @@ class Share extends \Zotlabs\Web\Controller {
$post = item_store($arr);
$post_id = $post['item_id'];
+ $approval_id = $post['approval_id'] ?? 0;
$arr['id'] = $post_id;
@@ -143,6 +144,7 @@ class Share extends \Zotlabs\Web\Controller {
// info( t('Post repeated') . EOL);
+/*
$r = q("select * from item where id = %d",
intval($post_id)
);
@@ -151,8 +153,12 @@ class Share extends \Zotlabs\Web\Controller {
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
+*/
Master::Summon([ 'Notifier', 'like', $post_id ]);
+ if ($approval_id) {
+ Master::Summon(['Notifier', 'like', $approval_id]);
+ }
killme();
diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php
index b927ee480..baabee78f 100644
--- a/Zotlabs/Module/Subthread.php
+++ b/Zotlabs/Module/Subthread.php
@@ -159,7 +159,7 @@ class Subthread extends \Zotlabs\Web\Controller {
$arr['deny_cid'] = $item['deny_cid'];
$arr['deny_gid'] = $item['deny_gid'];
- $post = item_store($arr);
+ $post = item_store($arr, deliver: false, addAndSync: false);
$post_id = $post['item_id'];
$arr['id'] = $post_id;
diff --git a/Zotlabs/Module/Tagrm.php b/Zotlabs/Module/Tagrm.php
index a6dc21798..34eaf85b2 100644
--- a/Zotlabs/Module/Tagrm.php
+++ b/Zotlabs/Module/Tagrm.php
@@ -7,141 +7,141 @@ require_once('include/bbcode.php');
class Tagrm extends \Zotlabs\Web\Controller {
function post() {
-
+
if(! local_channel())
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
-
+
+
if((x($_POST,'submit')) && ($_POST['submit'] === t('Cancel')))
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
$tag = ((x($_POST,'tag')) ? trim($_POST['tag']) : '');
$item = ((x($_POST,'item')) ? intval($_POST['item']) : 0 );
-
+
$r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1",
intval($item),
intval(local_channel())
);
-
+
if(! $r)
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
$r = fetch_post_tags($r,true);
-
+
$item = $r[0];
$new_tags = array();
-
+
if($item['term']) {
for($x = 0; $x < count($item['term']); $x ++) {
if($item['term'][$x]['term'] !== hex2bin($tag))
$new_tags[] = $item['term'][$x];
}
}
-
+
if($new_tags)
$item['term'] = $new_tags;
else
unset($item['term']);
-
- item_store_update($item);
-
+
+ item_store_update($item, deliver: false, addAndSync: false);
+
info( t('Tag removed') . EOL );
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
// NOTREACHED
-
+
}
-
-
-
+
+
+
function get() {
-
+
if(! local_channel()) {
goaway(z_root() . '/' . $_SESSION['photo_return']);
// NOTREACHED
}
-
+
// remove tag on the fly if item and tag are provided
if((argc() == 4) && (argv(1) === 'drop') && intval(argv(2))) {
-
+
$item = intval(argv(2));
$tag = argv(3);
-
+
$r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1",
intval($item),
intval(local_channel())
);
-
+
if(! $r)
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
$r = fetch_post_tags($r,true);
-
+
$item = $r[0];
-
+
$new_tags = array();
-
+
if($item['term']) {
for($x = 0; $x < count($item['term']); $x ++) {
if($item['term'][$x]['term'] !== hex2bin($tag))
$new_tags[] = $item['term'][$x];
}
}
-
+
if($new_tags)
$item['term'] = $new_tags;
else
unset($item['term']);
-
- item_store_update($item);
-
+
+ item_store_update($item, deliver: false, addAndSync: false);
+
info( t('Tag removed') . EOL );
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
}
-
+
//if we got only the item print a list of tags to select
if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
-
+
$o = '';
-
+
$item = intval(argv(2));
-
+
$r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1",
intval($item),
intval(local_channel())
);
-
+
if(! $r)
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
$r = fetch_post_tags($r,true);
-
+
if(! count($r[0]['term']))
goaway(z_root() . '/' . $_SESSION['photo_return']);
-
+
$o .= '<h3>' . t('Remove Item Tag') . '</h3>';
-
+
$o .= '<p id="tag-remove-desc">' . t('Select a tag to remove: ') . '</p>';
-
+
$o .= '<form id="tagrm" action="tagrm" method="post" >';
$o .= '<input type="hidden" name="item" value="' . $item . '" />';
$o .= '<ul>';
-
-
+
+
foreach($r[0]['term'] as $x) {
$o .= '<li><input type="checkbox" name="tag" value="' . bin2hex($x['term']) . '" >' . bbcode($x['term']) . '</input></li>';
}
-
+
$o .= '</ul>';
$o .= '<input id="tagrm-submit" type="submit" name="submit" value="' . t('Remove') .'" />';
$o .= '<input id="tagrm-cancel" type="submit" name="submit" value="' . t('Cancel') .'" />';
$o .= '</form>';
-
+
return $o;
-
+
}
-
+
}
-
+
}
diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php
index 06c47f91f..5192e3043 100644
--- a/Zotlabs/Module/Vote.php
+++ b/Zotlabs/Module/Vote.php
@@ -107,10 +107,12 @@ class Vote extends Controller {
retain_item($fetch[0]['id']);
if($x['success']) {
- $itemid = $x['item_id'];
- Master::Summon( [ 'Notifier', 'like', $itemid ] );
+ Master::Summon(['Notifier', 'like', $x['item_id']]);
+ if (!empty($x['approval_id'])) {
+ Master::Summon(['Notifier', 'like', $x['approval_id']]);
+ }
}
-
+/*
$r = q("select * from item where id = %d",
intval($itemid)
);
@@ -119,6 +121,7 @@ class Vote extends Controller {
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
+*/
}
$ret['success'] = true;
diff --git a/boot.php b/boot.php
index 07d19e753..71a112288 100644
--- a/boot.php
+++ b/boot.php
@@ -66,7 +66,7 @@ require_once('include/security.php');
define('PLATFORM_NAME', 'hubzilla');
-define('STD_VERSION', '9.5.1');
+define('STD_VERSION', '9.5.2');
define('ZOT_REVISION', '6.0');
define('DB_UPDATE_VERSION', 1263);
@@ -1538,7 +1538,7 @@ function check_config() {
App::set_baseurl(z_root());
- new DB_Upgrade(DB_UPDATE_VERSION);
+ DB_Upgrade::run(DB_UPDATE_VERSION);
plugins_sync();
diff --git a/include/attach.php b/include/attach.php
index 97750db4b..02b94ddb6 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -1606,8 +1606,7 @@ function attach_drop_photo($channel_id,$resource) {
if($x) {
$stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($x[0]['item_hidden']) ? false : true);
- drop_item($x[0]['id'], $interactive, $stage);
+ drop_item($x[0]['id'], $stage);
}
$r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",
@@ -1636,8 +1635,7 @@ function attach_drop_item($channel_id,$resource) {
if($x) {
$stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($x[0]['item_hidden']) ? false : true);
- drop_item($x[0]['id'], $interactive, $stage);
+ drop_item($x[0]['id'], $stage);
}
}
@@ -1855,8 +1853,6 @@ function pipe_streams($in, $out, $bufsize = 16384) {
}
function attach_store_item($channel, $observer, $file) {
-
-
if(is_string($file)) {
$r = q("SELECT * FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($channel['channel_id']),
@@ -1906,10 +1902,11 @@ function attach_store_item($channel, $observer, $file) {
$post = item_store($arr);
- $item_id = $post['item_id'];
-
- if($item_id) {
- Master::Summon(['Notifier', 'activity', $item_id]);
+ if ($post['success']) {
+ Master::Summon(['Notifier', 'activity', $post['item_id']]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
}
*/
@@ -1919,8 +1916,11 @@ function attach_store_item($channel, $observer, $file) {
}
$stage = (($r[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($r[0]['item_hidden']) ? false : true);
- drop_item($r[0]['id'], $interactive, $stage);
+ drop_item($r[0]['id'], $stage);
+
+ if (empty($r[0]['item_hidden'])) {
+ Master::Summon(['Notifier', 'drop', $i[0]['id']]);
+ }
}
@@ -1945,6 +1945,12 @@ function attach_store_item($channel, $observer, $file) {
$mid = z_root() . '/item/' . $uuid;
+ $target = [
+ 'id' => z_root() . '/conversation/' . $uuid,
+ 'type' => 'Collection',
+ 'attributedTo' => channel_url($channel),
+ ];
+
$arr = []; // Initialize the array of parameters for the post
$arr['aid'] = $channel['channel_account_id'];
$arr['uuid'] = $uuid;
@@ -1965,6 +1971,8 @@ function attach_store_item($channel, $observer, $file) {
$arr['item_thread_top'] = 1;
$arr['item_private'] = (($file['allow_cid'] || $file['allow_gid'] || $file['deny_cid'] || $file['deny_gid']) ? 1 : 0);
$arr['verb'] = 'Create';
+ $arr['target'] = $target;
+ $arr['target_type'] = 'Collection';
$arr['obj_type'] = $type;
$arr['title'] = $file['filename'];
@@ -1982,7 +1990,7 @@ function attach_store_item($channel, $observer, $file) {
}
$body_str = sprintf((($type === 'Image') ? t('%s shared an %s with you') : t('%s shared a %s with you')), '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]', '[zrl=' . $path . ']' . (($type === 'Image') ? t('image') : t('file')) . '[/zrl]');
- $arr['body'] .= $body_str;
+ $arr['body'] .= "\r\n" . $body_str;
$meta = [
'name' => $file['filename'],
@@ -1998,10 +2006,11 @@ function attach_store_item($channel, $observer, $file) {
$post = item_store($arr);
- $item_id = $post['item_id'];
-
- if($item_id) {
- Master::Summon(['Notifier', 'activity', $item_id]);
+ if ($post['success']) {
+ Master::Summon(['Notifier', 'activity', $post['item_id']]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
}
}
diff --git a/include/connections.php b/include/connections.php
index efc531171..7500647b4 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -342,7 +342,7 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
if($r) {
foreach($r as $rr) {
- drop_item($rr['id'],false);
+ drop_item($rr['id']);
}
}
@@ -513,7 +513,7 @@ function remove_abook_items($channel_id, $xchan_hash) {
continue;
}
- drop_item($rr['id'],false);
+ drop_item($rr['id']);
}
}
diff --git a/include/datetime.php b/include/datetime.php
index 9e39fa985..2182d7c43 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -527,7 +527,7 @@ function update_birthdays() {
$z = event_store_event($ev);
if ($z) {
- $item_id = event_store_item($ev, $z);
+ event_store_item($ev, $z, false);
q("update abook set abook_dob = '%s' where abook_id = %d",
dbesc(intval($rr['abook_dob']) + 1 . substr($rr['abook_dob'], 4)),
intval($rr['abook_id'])
diff --git a/include/event.php b/include/event.php
index 2aa9b51f3..2fa1cc4f1 100644
--- a/include/event.php
+++ b/include/event.php
@@ -1070,7 +1070,7 @@ function event_import_ical($ical, $uid) {
logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev);
if($event) {
- $item_id = event_store_item($ev,$event);
+ event_store_item($ev, $event, false);
return true;
}
}
@@ -1205,7 +1205,7 @@ function event_import_ical_task($ical, $uid) {
logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev);
if($event) {
- $item_id = event_store_item($ev,$event);
+ event_store_item($ev, $event, false);
return true;
}
}
@@ -1214,8 +1214,7 @@ function event_import_ical_task($ical, $uid) {
}
-
-function event_store_item($arr, $event) {
+function event_store_item($arr, $event, $deliver = true) {
require_once('include/datetime.php');
require_once('include/items.php');
@@ -1234,7 +1233,7 @@ function event_store_item($arr, $event) {
}
- $item_arr = array();
+ $item_arr = [];
$prefix = '';
// $birthday = false;
@@ -1255,7 +1254,7 @@ function event_store_item($arr, $event) {
$item_arr['comment_policy'] = 'none';
}
- $r = q("SELECT * FROM item WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
+ $r = q("SELECT * FROM item left join xchan on author_xchan = xchan_hash WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
dbesc($event['event_hash']),
intval($arr['uid'])
);
@@ -1292,51 +1291,21 @@ function event_store_item($arr, $event) {
$object = json_encode($x);
- $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
-
- /**
- * @FIXME can only update sig if we have the author's channel on this site
- * Until fixed, set it to nothing so it won't give us signature errors.
- */
- $sig = '';
-
- q("UPDATE item SET title = '%s', body = '%s', obj = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d",
- dbesc($arr['summary']),
- dbesc($prefix . format_event_bbcode($arr)),
- dbesc($object),
- dbesc($arr['allow_cid']),
- dbesc($arr['allow_gid']),
- dbesc($arr['deny_cid']),
- dbesc($arr['deny_gid']),
- dbesc($arr['edited']),
- dbesc($sig),
- intval($r[0]['item_flags']),
- intval($private),
- dbesc('Event'),
- intval($r[0]['id']),
- intval($arr['uid'])
- );
-
- q("delete from term where oid = %d and otype = %d",
- intval($r[0]['id']),
- intval(TERM_OBJ_POST)
- );
-
- if(($arr['term']) && (is_array($arr['term']))) {
- foreach($arr['term'] as $t) {
- q("insert into term (uid,oid,otype,ttype,term,url)
- values(%d,%d,%d,%d,'%s','%s') ",
- intval($arr['uid']),
- intval($r[0]['id']),
- intval(TERM_OBJ_POST),
- intval($t['ttype']),
- dbesc($t['term']),
- dbesc($t['url'])
- );
- }
- }
-
- $item_id = $r[0]['id'];
+ $item_arr['id'] = $r[0]['id'];
+ $item_arr['uid'] = $arr['uid'];
+ $item_arr['obj'] = $object;
+ $item_arr['edited'] = $arr['edited'];
+ $item_arr['allow_cid'] = $arr['allow_cid'];
+ $item_arr['allow_gid'] = $arr['allow_gid'];
+ $item_arr['deny_cid'] = $arr['deny_cid'];
+ $item_arr['deny_gid'] = $arr['deny_gid'];
+ $item_arr['item_private'] = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
+ $item_arr['title'] = $arr['summary'];
+ $item_arr['sig'] = '';
+ $item_arr['body'] = $prefix . format_event_bbcode($arr);
+ $item_arr['term'] = $arr['term'];
+
+ $post = item_store_update($item_arr, deliver: $deliver);
/**
* @hooks event_updated
@@ -1344,14 +1313,10 @@ function event_store_item($arr, $event) {
*/
call_hooks('event_updated', $event['id']);
- return $item_id;
+ return $post;
} else {
- $z = q("select * from channel where channel_id = %d limit 1",
- intval($arr['uid'])
- );
-
- $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
+ $z = channelx_by_n($arr['uid']);
$item_wall = 0;
$item_origin = 0;
@@ -1361,7 +1326,7 @@ function event_store_item($arr, $event) {
$item_arr['id'] = $item['id'];
}
else {
- $wall = (($z[0]['channel_hash'] == $event['event_xchan']) ? true : false);
+ $wall = (($z['channel_hash'] == $event['event_xchan']) ? true : false);
$item_thread_top = 1;
if($wall) {
$item_wall = 1;
@@ -1374,20 +1339,20 @@ function event_store_item($arr, $event) {
$arr['mid'] = z_root() . '/activity/' . $event['event_hash'];
}
- $item_arr['aid'] = $z[0]['channel_account_id'];
+ $item_arr['aid'] = $z['channel_account_id'];
$item_arr['uid'] = $arr['uid'];
$item_arr['uuid'] = $arr['uuid'];
$item_arr['author_xchan'] = $arr['event_xchan'];
$item_arr['mid'] = $arr['mid'];
$item_arr['parent_mid'] = $arr['mid'];
- $item_arr['owner_xchan'] = (($wall) ? $z[0]['channel_hash'] : $arr['event_xchan']);
+ $item_arr['owner_xchan'] = (($wall) ? $z['channel_hash'] : $arr['event_xchan']);
$item_arr['author_xchan'] = $arr['event_xchan'];
$item_arr['title'] = $arr['summary'];
$item_arr['allow_cid'] = $arr['allow_cid'];
$item_arr['allow_gid'] = $arr['allow_gid'];
$item_arr['deny_cid'] = $arr['deny_cid'];
$item_arr['deny_gid'] = $arr['deny_gid'];
- $item_arr['item_private'] = $private;
+ $item_arr['item_private'] = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
$item_arr['verb'] = 'Invite';
$item_arr['item_wall'] = $item_wall;
$item_arr['item_origin'] = $item_origin;
@@ -1452,16 +1417,21 @@ function event_store_item($arr, $event) {
$item_arr['obj'] = json_encode($y);
}
+ $item_arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $item_arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $z['channel_address'],
+ ];
+ $item_arr['tgt_type'] = 'Collection';
+
// propagate the event resource_id so that posts containing it are easily searchable in downstream copies
// of the item which have not stored the actual event. Required for Diaspora event federation as Diaspora
// event_participation messages refer to the event resource_id as a parent, while out own event attendance
// activities refer to the item message_id as the parent.
- set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true);
-
- $res = item_store($item_arr);
+ set_iconfig($item_arr, 'system', 'event_id', $event['event_hash'], true);
- $item_id = $res['item_id'];
+ $post = item_store($item_arr, deliver: $deliver);
/**
* @hooks event_created
@@ -1469,7 +1439,7 @@ function event_store_item($arr, $event) {
*/
call_hooks('event_created', $event['id']);
- return $item_id;
+ return $post;
}
}
diff --git a/include/feedutils.php b/include/feedutils.php
index a50214746..cc57d106c 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -998,7 +998,7 @@ function process_feed_tombstones($feed,$importer,$contact,$pass) {
if(! intval($item['item_deleted'])) {
logger('deleting item ' . $item['id'] . ' mid=' . $item['mid'], LOGGER_DEBUG);
- drop_item($item['id'],false);
+ drop_item($item['id']);
}
}
}
@@ -1181,7 +1181,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
&& $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
- drop_item($r[0]['id'],false);
+ drop_item($r[0]['id']);
}
continue;
}
@@ -1449,7 +1449,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
&& isset($datarray['author_xchan']) && $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
- drop_item($r[0]['id'],false);
+ drop_item($r[0]['id']);
}
continue;
}
diff --git a/include/help.php b/include/help.php
index 0efe90a9f..2358f1289 100644
--- a/include/help.php
+++ b/include/help.php
@@ -156,12 +156,12 @@ function store_doc_file($s) {
if($r) {
$item['id'] = $r[0]['id'];
$item['mid'] = $item['parent_mid'] = $r[0]['mid'];
- $x = item_store_update($item);
+ $x = item_store_update($item, deliver: false, addAndSync: false);
}
else {
$item['uuid'] = item_message_id();
$item['mid'] = $item['parent_mid'] = z_root() . '/item/' . $item['uuid'];
- $x = item_store($item);
+ $x = item_store($item, deliver: false, addAndSync: false);
}
return $x;
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 277b0e640..b799a0c28 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -29,9 +29,6 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
foreach ($list as $oldNode) {
- if ($oldnode == 'li')
- hz_syslog(print_r($oldNode,true));
-
$attr = array();
if ($oldNode->attributes->length)
foreach ($oldNode->attributes as $attribute)
diff --git a/include/import.php b/include/import.php
index 479c2c255..77d35a3e7 100644
--- a/include/import.php
+++ b/include/import.php
@@ -825,13 +825,13 @@ function import_items($channel, $items, $sync = false, $relocate = null) {
if($item['edited'] >= $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store_update($item,$allow_code,$deliver);
+ $item_result = item_store_update($item, $allow_code, $deliver, addAndSync: false);
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store($item,$allow_code,$deliver);
+ $item_result = item_store($item, $allow_code, $deliver, addAndSync: false);
}
// preserve conversations you've been involved in from being expired
@@ -1886,7 +1886,7 @@ function import_webpage_element($element, $channel, $type) {
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited'])
- $x = item_store_update($arr,$execflag);
+ $x = item_store_update($arr, $execflag, deliver: false, addAndSync: false);
}
else {
if(($i) && (intval($i[0]['item_deleted']))) {
@@ -1897,7 +1897,7 @@ function import_webpage_element($element, $channel, $type) {
);
}
else
- $x = item_store($arr,$execflag);
+ $x = item_store($arr, $execflag, deliver: false, addAndSync: false);
}
if($x && $x['success']) {
diff --git a/include/items.php b/include/items.php
index 423d626ad..9ef44e147 100644
--- a/include/items.php
+++ b/include/items.php
@@ -361,7 +361,7 @@ function can_comment_on_post($observer_xchan, $item) {
case 'specific':
case 'contacts':
case '':
- if(local_channel() && get_abconfig(local_channel(), (($item['verb'] === ACTIVITY_SHARE) ? $item['source_xchan'] : $item['owner_xchan']), 'their_perms', 'post_comments')) {
+ if(local_channel() && get_abconfig(local_channel(), $item['owner_xchan'], 'their_perms', 'post_comments')) {
return true;
}
if(intval($item['item_wall']) && perm_is_allowed($item['uid'],$observer_xchan,'post_comments')) {
@@ -431,8 +431,9 @@ function add_source_route($iid, $hash) {
* * \e boolean \b success true or false
* * \e array \b activity the resulting activity if successful
*/
-function post_activity_item($arr, $allow_code = false, $deliver = true) {
+
+function post_activity_item($arr, $allow_code = false, $deliver = true, $channel = null, $observer = null, $addAndSync = true) {
$ret = array('success' => false);
$is_comment = false;
@@ -446,8 +447,13 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
if(! array_key_exists('item_thread_top',$arr) && (! $is_comment))
$arr['item_thread_top'] = 1;
- $channel = App::get_channel();
- $observer = App::get_observer();
+ if (!$channel) {
+ $channel = App::get_channel();
+ }
+
+ if (!$observer) {
+ $observer = App::get_observer();
+ }
$arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']);
$arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']);
@@ -493,6 +499,14 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$arr['plink'] = $arr['mid'];
}
+ if (!$arr['target']) {
+ $arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $channel['channel_address'],
+ ];
+ $arr['tgt_type'] = 'Collection';
+ }
// for the benefit of plugins, we will behave as if this is an API call rather than a normal online post
@@ -509,29 +523,30 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
return $ret;
}
- $post = item_store($arr,$allow_code,$deliver);
-
- if($post['success']) {
- $post_id = $post['item_id'];
- $ret['success'] = true;
- $ret['item_id'] = $post_id;
- $ret['activity'] = $post['item'];
+ $post = item_store($arr, $allow_code, $deliver, $addAndSync);
- /**
- * @hooks post_local_end
- * Called after a local post operation has completed.
- * * \e array - the item returned from item_store()
- */
- call_hooks('post_local_end', $ret['activity']);
- }
- else
+ if (!$post['success']) {
return $ret;
-
- if($post_id && $deliver) {
- Master::Summon(['Notifier','activity', $post_id]);
}
+ $post_id = $post['item_id'];
$ret['success'] = true;
+ $ret['item_id'] = $post_id;
+ $ret['activity'] = $post['item'];
+
+ /**
+ * @hooks post_local_end
+ * Called after a local post operation has completed.
+ * * \e array - the item returned from item_store()
+ */
+ call_hooks('post_local_end', $ret['activity']);
+
+ if($post_id && $deliver) {
+ Master::Summon(['Notifier', 'activity', $post_id]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
+ }
return $ret;
}
@@ -1594,7 +1609,7 @@ function item_json_encapsulate($arr, $k) {
* * \e boolean \b success
* * \e int \b item_id
*/
-function item_store($arr, $allow_exec = false, $deliver = true) {
+function item_store($arr, $allow_exec = false, $deliver = true, $addAndSync = true) {
$d = [
'item' => $arr,
@@ -1882,7 +1897,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['item_private'] = 0;
if(in_array($arr['obj_type'], ['Note','Answer']) && $r[0]['obj_type'] === 'Question' && intval($r[0]['item_wall'])) {
- Activity::update_poll($r[0]['id'], $arr);
+ Activity::update_poll($r[0], $arr);
}
}
@@ -2052,6 +2067,13 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
Master::Summon([ 'Cache_embeds', $current_post ]);
}
+ $ret['success'] = true;
+ $ret['item_id'] = $current_post;
+
+ if ($addAndSync) {
+ $ret = addToCollectionAndSync($ret);
+ }
+
// If _creating_ a deleted item, don't propagate it further or send out notifications.
// We need to store the item details just in case the delete came in before the original post,
// so that we have an item in the DB that's marked deleted and won't store a fresh post
@@ -2062,9 +2084,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
tag_deliver($arr['uid'],$current_post);
}
- $ret['success'] = true;
- $ret['item_id'] = $current_post;
-
return $ret;
}
@@ -2077,7 +2096,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
* @param boolean $deliver (optional) default true
* @return array
*/
-function item_store_update($arr, $allow_exec = false, $deliver = true) {
+function item_store_update($arr, $allow_exec = false, $deliver = true, $addAndSync = true) {
$d = [
'item' => $arr,
@@ -2390,17 +2409,19 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
Master::Summon([ 'Cache_embeds', $orig_post_id ]);
}
+ $ret['success'] = true;
+ $ret['item_id'] = $orig_post_id;
-
+ if ($addAndSync) {
+ $ret = addToCollectionAndSync($ret);
+ }
if($deliver) {
- send_status_notifications($orig_post_id,$arr);
+ // don't send notify_comment for edits
+ // send_status_notifications($orig_post_id,$arr);
tag_deliver($uid,$orig_post_id);
}
- $ret['success'] = true;
- $ret['item_id'] = $orig_post_id;
-
return $ret;
}
@@ -3101,6 +3122,11 @@ function i_am_mentioned($channel, $item, $check_groups = false) {
*/
function start_delivery_chain($channel, $item, $item_id, $parent, $group = false, $edit = false) {
+ if ($item['author_xchan'] === $channel['channel_hash'] && in_array($item['verb'], ['Add', 'Remove'])) {
+ logger('delivery chain already started');
+ return;
+ }
+
$sourced = check_item_source($channel['channel_id'],$item);
if($sourced) {
@@ -3147,7 +3173,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$item['thr_parent'] = $item['mid'];
$item['llink'] = z_root() . '/display/' . $item['uuid'];
}
-
+/*
$r = q("UPDATE item SET author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s' WHERE id = %d",
dbesc($item['author_xchan']),
dbesc($item['mid']),
@@ -3156,7 +3182,108 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
dbesc($item['llink']),
intval($item_id)
);
+*/
+ }
+
+ hz_syslog('gothere');
+ // sourced
+
+ $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
+
+ $new_public_policy = map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true);
+
+ if((! $private) && $new_public_policy)
+ $private = 1;
+
+ $item_wall = 1;
+ $item_origin = (($item['item_deleted']) ? 0 : 1); // item_origin for deleted items is set to 0 in delete_imported_item() to prevent looping. In this case we probably should not set it back to 1 here.
+ $item_uplink = 0;
+ $item_nocomment = 0;
+
+ $flag_bits = $item['item_flags'];
+
+ // maintain the original source, which will be the original item owner and was stored in source_xchan
+ // when we created the delivery fork
+
+ if($parent) {
+ $r = q("update item set source_xchan = '%s' where id = %d",
+ dbesc($parent['source_xchan']),
+ intval($item_id)
+ );
+ }
+ else {
+ $item_uplink = (($item['item_rss']) ? 0 : 1); // Do not set item_uplink for rss items - we can not send anything to them.
+
+ // if this is an edit, item_store_update() will have already updated the item
+ // with the correct value for source_xchan (by ignoring it). We cannot set to owner_xchan
+ // in this case because owner_xchan will point to the parent of this chain
+ // and not the original sender.
+
+ if(!$edit) {
+ $r = q("update item set source_xchan = owner_xchan where id = %d",
+ intval($item_id)
+ );
+ }
+ }
+
+ // this will not work with item_store_update()
+
+ $r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
+ deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d,
+ author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s' where id = %d",
+ intval($item_uplink),
+ intval($item_nocomment),
+ intval($flag_bits),
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_allow_cid']),
+ dbesc($channel['channel_allow_gid']),
+ dbesc($channel['channel_deny_cid']),
+ dbesc($channel['channel_deny_gid']),
+ intval($private),
+ dbesc($new_public_policy),
+ dbesc(map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'))),
+ dbesc($item['title']),
+ dbesc($item['body']),
+ intval($item_wall),
+ intval($item_origin),
+ dbesc($item['author_xchan']),
+ dbesc($item['mid']),
+ dbesc($item['parent_mid']),
+ dbesc($item['thr_parent']),
+ dbesc($item['llink']),
+ intval($item_id)
+ );
+
+ if($r) {
+ $rr = q("select * from item where id = %d",
+ intval($item_id)
+ );
+
+ if ($rr) {
+
+ // this is hackish but since we can not use item_store_update() here,
+ // we will prepare a similar output to feed to addToCollectionAndSync()
+ $ret['success'] = 1;
+ $ret['item_id'] = $rr[0]['id'];
+ $ret['item'] = $rr[0];
+
+ $result = addToCollectionAndSync($ret);
+
+ Master::Summon(['Notifier', 'tgroup', $result['item_id']]);
+ if ($result['approval_id']) {
+ Master::Summon(['Notifier', 'tgroup', $result['approval_id']]);
+ }
+ }
+ }
+ else {
+ logger('start_delivery_chain: failed to update item');
+ // reset the source xchan to prevent loops
+ $r = q("update item set source_xchan = '' where id = %d",
+ intval($item_id)
+ );
}
+ return;
}
if ($group && (! $parent)) {
@@ -3178,8 +3305,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
if ($r) {
if (intval($item['item_deleted'])) {
- drop_item($r[0]['id'], false, DROPITEM_PHASE1);
- Master::Summon([ 'Notifier', 'drop', $r[0]['id'] ]);
+ drop_item($r[0]['id'], DROPITEM_PHASE1, uid: $r[0]['uid']);
+ Master::Summon(['Notifier', 'drop' ,$r[0]['id']]);
return;
}
$arr['id'] = intval($r[0]['id']);
@@ -3261,8 +3388,15 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
$arr['title'] = $item['title'];
- $arr['tgt_type'] = $item['tgt_type'];
- $arr['target'] = $item['target'];
+// $arr['tgt_type'] = $item['tgt_type'];
+// $arr['target'] = $item['target'];
+
+ $arr['tgt_type'] = 'Collection';
+ $arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => channel_url($channel['channel_address'])
+ ];
$arr['term'] = $item['term'];
@@ -3285,10 +3419,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$post = item_store($arr);
}
- $post_id = $post['item_id'];
+ $post_id = $post['item_id'] ?? 0;
+ $approval_id = $post['approval_id'] ?? 0;
if($post_id) {
Master::Summon([ 'Notifier','tgroup',$post_id ]);
+ if ($approval_id) {
+ Master::Summon(['Notifier', 'tgroup', $approval_id]);
+ }
}
return;
}
@@ -3313,14 +3451,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
if ($edit) {
if (intval($item['item_deleted'])) {
- drop_item($item['id'],false,DROPITEM_PHASE1);
- Master::Summon([ 'Notifier','drop',$item['id'] ]);
+ drop_item($item['id'], DROPITEM_PHASE1, uid: $item['uid']);
+ Master::Summon(['Notifier', 'drop', $item['id']]);
return;
}
return;
}
else {
- $arr['uuid'] = item_message_id();
+ $arr['uuid'] = uuid_from_url($item['mid']);
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
$arr['parent_mid'] = $item['parent_mid'];
//IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid']));
@@ -3364,12 +3502,12 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr['deny_gid'] = $channel['channel_deny_gid'];
$arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
- $post = item_store($arr);
- $post_id = $post['item_id'];
+ $post = item_store($arr, deliver: false, addAndSync: false);
+ $post_id = $post['item_id'] ?? 0;
- if ($post_id) {
- Master::Summon([ 'Notifier','tgroup',$post_id ]);
- }
+ if ($post_id) {
+ Master::Summon(['Notifier', 'tgroup', $post_id]);
+ }
q("update channel set channel_lastpost = '%s' where channel_id = %d",
dbesc(datetime_convert()),
@@ -3379,81 +3517,6 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
return;
}
-
- // Change this copy of the post to a forum head message and deliver to all the tgroup members
- // also reset all the privacy bits to the forum default permissions
-
- $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
- || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
-
- $new_public_policy = map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true);
-
- if((! $private) && $new_public_policy)
- $private = 1;
-
- $item_wall = 1;
- $item_origin = (($item['item_deleted']) ? 0 : 1); // item_origin for deleted items is set to 0 in delete_imported_item() to prevent looping. In this case we probably should not set it back to 1 here.
- $item_uplink = 0;
- $item_nocomment = 0;
-
- $flag_bits = $item['item_flags'];
-
- // maintain the original source, which will be the original item owner and was stored in source_xchan
- // when we created the delivery fork
-
- if($parent) {
- $r = q("update item set source_xchan = '%s' where id = %d",
- dbesc($parent['source_xchan']),
- intval($item_id)
- );
- }
- else {
- $item_uplink = (($item['item_rss']) ? 0 : 1); // Do not set item_uplink for rss items - we can not send anything to them.
-
- // if this is an edit, item_store_update() will have already updated the item
- // with the correct value for source_xchan (by ignoring it). We cannot set to owner_xchan
- // in this case because owner_xchan will point to the parent of this chain
- // and not the original sender.
-
- if(! $edit) {
- $r = q("update item set source_xchan = owner_xchan where id = %d",
- intval($item_id)
- );
- }
- }
-
- $title = $item['title'];
- $body = $item['body'];
-
- $r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
- deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d where id = %d",
- intval($item_uplink),
- intval($item_nocomment),
- intval($flag_bits),
- dbesc($channel['channel_hash']),
- dbesc($channel['channel_allow_cid']),
- dbesc($channel['channel_allow_gid']),
- dbesc($channel['channel_deny_cid']),
- dbesc($channel['channel_deny_gid']),
- intval($private),
- dbesc($new_public_policy),
- dbesc(map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'))),
- dbesc($title),
- dbesc($body),
- intval($item_wall),
- intval($item_origin),
- intval($item_id)
- );
-
- if($r)
- Master::Summon([ 'Notifier','tgroup',$item_id ]);
- else {
- logger('start_delivery_chain: failed to update item');
- // reset the source xchan to prevent loops
- $r = q("update item set source_xchan = '' where id = %d",
- intval($item_id)
- );
- }
}
/**
@@ -3792,7 +3855,7 @@ function item_expire($uid,$days,$comment_days = 7) {
if ($r) {
foreach ($r as $item) {
- drop_item($item['id'], false);
+ drop_item($item['id'], expire: true);
}
}
@@ -3805,25 +3868,12 @@ function retain_item($id) {
);
}
-function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
- $uid = 0;
-
- if(! local_channel() && ! remote_channel())
- return;
-
- if(count($items)) {
+function drop_items($items, $stage = DROPITEM_NORMAL, $force = false, $expire = false) {
+ if ($items) {
foreach($items as $item) {
- $owner = drop_item($item,$interactive,$stage);
- if($owner && ! $uid)
- $uid = $owner;
+ drop_item($item, $stage, $force, expire: $expire);
}
}
-
- // multiple threads may have been deleted, send an expire notification
-
- if($uid) {
- Master::Summon([ 'Notifier','expire',$uid ]);
- }
}
@@ -3836,7 +3886,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
// $stage = 1 => set deleted flag on the item and perform intial notifications
// $stage = 2 => perform low level delete at a later stage
-function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
+function drop_item($id, $stage = DROPITEM_NORMAL, $force = false, $uid = 0, $observer_hash = '', $expire = false, $recurse = false) {
// locate item to be deleted
@@ -3844,33 +3894,48 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
intval($id)
);
- if((! $r) || (intval($r[0]['item_deleted']) && ($stage === DROPITEM_NORMAL))) {
- if(! $interactive)
- return 0;
- notice( t('Item not found.') . EOL);
- //goaway(z_root() . '/' . $_SESSION['return_url']);
+ if(!$r || (intval($r[0]['item_deleted']) && $stage === DROPITEM_NORMAL)) {
+ return false;
}
$item = $r[0];
- $ok_to_delete = false;
+ if(!$recurse) {
+ drop_related($item, $stage, $force, $uid, $observer_hash, $expire);
+ }
- // system deletion
- if(! $interactive)
- $ok_to_delete = true;
+ $ok_to_delete = false;
// admin deletion
- if(is_site_admin())
+ if(is_site_admin()) {
$ok_to_delete = true;
+ }
// owner deletion
- if(local_channel() && local_channel() == $item['uid'])
+ if(local_channel() && local_channel() == $item['uid']) {
$ok_to_delete = true;
+ }
+
+ // remote delete when nobody is authenticated (called from Libzot)
+ if ($uid && intval($uid) === intval($item['uid'])) {
+ $ok_to_delete = true;
+ }
// author deletion
- $observer = App::get_observer();
- if($observer && $observer['xchan_hash'] && ($observer['xchan_hash'] === $item['author_xchan']))
+ if ($observer_hash) {
+ $observer = ['xchan_hash' => $observer_hash];
+ }
+ else {
+ $observer = App::get_observer();
+ }
+
+ if (isset($observer['xchan_hash']) && $observer['xchan_hash'] === $item['author_xchan']) {
$ok_to_delete = true;
+ }
+
+ if (isset($observer['xchan_hash']) && $observer['xchan_hash'] === $item['owner_xchan']) {
+ $ok_to_delete = true;
+ }
if($ok_to_delete) {
@@ -3883,9 +3948,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
$arr = [
'item' => $item,
- 'interactive' => $interactive,
'stage' => $stage
];
+
/**
* @hooks drop_item
* Called when an 'item' is removed.
@@ -3908,30 +3973,95 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
delete_item_lowlevel($item, $stage);
}
- if(! $interactive)
- return 1;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- // send the notification upstream/downstream as the case may be
- // only send notifications to others if this is the owner's wall item.
- // This isn't optimal. We somehow need to pass to this function whether or not
- // to call the notifier, or we need to call the notifier from the calling function.
- // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only
- // set if we know we're going to send delete notifications out to others.
+// If somebody deletes a 'Create' activity, find any associated 'Add/Collection'
+// activity and delete it. And vice versa.
- if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) {
- Master::Summon([ 'Notifier','drop',$notify_id ]);
+function drop_related($item, $stage = DROPITEM_NORMAL, $force = false, $uid = 0, $observer_hash = '', $expire = false, $recurse = false) {
+ $allRelated = q("select * from item where parent_mid = '%s' and uid = %d",
+ dbesc($item['parent_mid']),
+ intval($item['uid'])
+ );
+ if (! $allRelated) {
+ return;
+ }
+ if ($item['verb'] === 'Add' && $item['tgt_type'] === 'Collection') {
+ if (is_array($item['obj'])) {
+ $thisItem = $item['obj'];
+ }
+ else {
+ $thisItem = json_decode($item['obj'], true);
+ }
+ if (isset($thisItem['object']['id'])) {
+ $targetMid = $thisItem['object']['id'];
+ }
+ if (!$targetMid) {
+ return;
+ }
+ foreach ($allRelated as $related) {
+ if ($related['mid'] === $targetMid) {
+ drop_item($related['id'], $stage, $force, $uid, $observer_hash, $expire, recurse: true);
+ break;
+ }
}
- //goaway(z_root() . '/' . $_SESSION['return_url']);
}
else {
- if(! $interactive)
- return 0;
- notice( t('Permission denied.') . EOL);
- //goaway(z_root() . '/' . $_SESSION['return_url']);
+ foreach ($allRelated as $related) {
+ if ($related['verb'] === 'Add' && str_contains($related['tgt_type'], 'Collection')) {
+ $thisItem = json_decode($related['obj'], true);
+ if (isset($thisItem['id']) && $thisItem['id'] === str_replace('/item/', '/activity/', $item['mid'])) {
+ drop_item($related['id'], $stage, $force, $uid, $observer_hash, $expire, recurse: true);
+ break;
+ }
+ }
+ }
}
}
+
+function find_related($item) {
+ $allRelated = q("select * from item where parent_mid = '%s' and uid = %d",
+ dbesc($item['parent_mid']),
+ intval($item['uid'])
+ );
+ if (! $allRelated) {
+ return false;
+ }
+ if ($item['verb'] === 'Add' && $item['tgt_type'] === 'Collection') {
+ $thisItem = json_decode($item['obj'],true);
+ if (is_array($thisItem)) {
+ $targetMid = $thisItem['object']['id'];
+ }
+ if (!$targetMid) {
+ return false;
+ }
+ foreach ($allRelated as $related) {
+ if ($related['mid'] === $targetMid) {
+ return $related;
+ }
+ }
+ }
+ else {
+ foreach ($allRelated as $related) {
+ if ($related['verb'] === 'Add' && str_contains($related['tgt_type'], 'Collection')) {
+ $thisItem = json_decode($related['obj'], true);
+ if (isset($thisItem['object']['id']) && $thisItem['object']['id'] === $item['mid']) {
+ return $related;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
/**
* @warning This function does not check for permission and does not send
* notifications and does not check recursion.
@@ -5094,7 +5224,7 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
* which will allow you to interact with it.
*/
-function copy_of_pubitem($channel,$mid) {
+function copy_of_pubitem($channel, $mid) {
$result = null;
$syschan = get_sys_channel();
@@ -5130,9 +5260,10 @@ function copy_of_pubitem($channel,$mid) {
$rv['item_wall'] = 0;
$rv['item_origin'] = 0;
- $x = item_store($rv);
+ $x = item_store($rv, deliver: false, addAndSync: false);
if($x['item_id'] && $x['item']['mid'] === $mid) {
$result = $x['item'];
+ sync_an_item($channel['channel_id'], $x['item_id']);
}
}
@@ -5140,3 +5271,69 @@ function copy_of_pubitem($channel,$mid) {
return $result;
}
+
+function addToCollectionAndSync($ret) {
+ if (!$ret['success']) {
+ return $ret;
+ }
+
+ $channel = channelx_by_n($ret['item']['uid']);
+ if ($channel && $channel['channel_hash'] === $ret['item']['owner_xchan']) {
+ $items = [$ret['item']];
+
+ if ((int)$items[0]['item_blocked'] === ITEM_MODERATED
+ || (int)$items[0]['item_unpublished'] || (int)$items[0]['item_delayed']) {
+ return $ret;
+ }
+
+ xchan_query($items);
+ $items = fetch_post_tags($items);
+ $sync_items = [];
+ $sync_items[] = encode_item($items[0], true);
+
+ if (!in_array($ret['item']['verb'], ['Add', 'Remove'])) {
+
+ $new_obj = Activity::build_packet(Activity::encode_activity($items[0]), $channel, false);
+ $approval = Activity::addToCollection($channel, $new_obj, $ret['item']['parent_mid'], $ret['item'], deliver: false);
+
+ if ($approval['success']) {
+ $ret['approval_id'] = $approval['item_id'];
+ $ret['approval'] = $approval['activity'];
+ $add_items = [$approval['activity']];
+ xchan_query($add_items);
+ $add_items = fetch_post_tags($add_items);
+ $sync_items[] = encode_item($add_items[0], true);
+ }
+ }
+
+ $resource_type = $ret['item']['resource_type'];
+
+ if ($resource_type === 'event') {
+ $z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
+ dbesc($ret['item']['resource_id']),
+ intval($channel['channel_id'])
+ );
+
+ if ($z) {
+ Libsync::build_sync_packet($channel['channel_id'], ['event_item' => $sync_items, 'event' => $z]);
+ }
+ }
+ elseif ($resource_type === 'photo') {
+ // reserved for future use, currently handled in the photo upload workflow
+ }
+ else {
+ Libsync::build_sync_packet($ret['item']['uid'], ['item' => $sync_items]);
+ }
+ }
+
+ return $ret;
+}
+
+function reverse_activity_mid($string) {
+ return str_replace(z_root() . '/activity/', z_root() . '/item/', $string);
+}
+
+function set_activity_mid($string) {
+ return str_replace(z_root() . '/item/', z_root() . '/activity/', $string);
+}
+
diff --git a/include/network.php b/include/network.php
index b3a3d715c..0a78c144b 100644
--- a/include/network.php
+++ b/include/network.php
@@ -1488,7 +1488,7 @@ function do_delivery($deliveries, $force = false) {
$interval = Config::Get('queueworker', 'queue_interval', 500000);
- $deliveries_per_process = intval(Config::Get('system','delivery_batch_count'));
+// $deliveries_per_process = intval(Config::Get('system','delivery_batch_count'));
if($deliveries_per_process <= 0)
$deliveries_per_process = 1;
diff --git a/include/photos.php b/include/photos.php
index 85c97d1fd..390754f39 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -7,6 +7,7 @@
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Config;
+use Zotlabs\Daemon\Master;
require_once('include/permissions.php');
require_once('include/items.php');
@@ -405,7 +406,7 @@ function photo_upload($channel, $observer, $args) {
}
}
- $attribution = (($visitor) ? $visitor : $channel['xchan_url']);
+ $attribution = (($visitor) ? $visitor : channel_url($channel));
//// Create item object
$object = [
@@ -438,13 +439,13 @@ function photo_upload($channel, $observer, $args) {
else {
$object['to'] = Activity::map_acl(array_merge($ac, ['item_private' => 1 - intval($public)]));
}
-
+/*
$target = [
'type' => 'orderedCollection',
'name' => ((strlen($album)) ? $album : '/'),
'id' => z_root() . '/album/' . $channel['channel_address'] . ((isset($args['directory']['hash'])) ? '/' . $args['directory']['hash'] : EMPTY_STR)
];
-
+*/
// Create item container
if (isset($args['item'])) {
foreach ($args['item'] as $i) {
@@ -453,6 +454,11 @@ function photo_upload($channel, $observer, $args) {
$force = false;
if ($item['mid'] === $item['parent_mid']) {
+ $target = [
+ 'id' => str_replace('/item/', '/conversation/', $item['mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => $attribution,
+ ];
$item['body'] = $summary;
$item['mimetype'] = 'text/bbcode';
@@ -460,10 +466,10 @@ function photo_upload($channel, $observer, $args) {
$object['id'] = $item['mid'];
$object['diaspora:guid'] = $item['uuid'];
- $item['obj'] = json_encode($object);
+ $item['obj'] = $object;
- $item['tgt_type'] = 'orderedCollection';
- $item['target'] = json_encode($target);
+ $item['tgt_type'] = 'Collection';
+ $item['target'] = $target;
if ($post_tags) {
$arr['term'] = $post_tags;
}
@@ -477,15 +483,23 @@ function photo_upload($channel, $observer, $args) {
if (($item['edited'] > $r[0]['edited']) || $force) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- item_store_update($item, false, $deliver);
+ $result = item_store_update($item, deliver: $deliver);
continue;
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- item_store($item, false, $deliver);
+ $result = item_store($item, deliver: $deliver);
}
+
+ if ($result['success'] && $visible && $deliver) {
+ Master::Summon(['Notifier', 'wall-new', $result['item_id']]);
+ if (!empty($result['approval_id'])) {
+ Master::Summon(['Notifier', 'wall-new', $result['approval_id']]);
+ }
+ }
+
}
}
else {
@@ -496,6 +510,12 @@ function photo_upload($channel, $observer, $args) {
$object['id'] = $mid;
$object['diaspora:guid'] = $uuid;
+ $target = [
+ 'id' => z_root() . '/conversation/' . $uuid,
+ 'type' => 'Collection',
+ 'attributedTo' => $attribution,
+ ];
+
$arr = [
'aid' => $account_id,
'uid' => $channel_id,
@@ -514,9 +534,9 @@ function photo_upload($channel, $observer, $args) {
'deny_gid' => $ac['deny_gid'],
'verb' => 'Create',
'obj_type' => 'Image',
- 'obj' => json_encode($object),
- 'tgt_type' => 'orderedCollection',
- 'target' => json_encode($target),
+ 'obj' => $object,
+ 'tgt_type' => 'Collection',
+ 'target' => $target,
'item_wall' => $visible,
'item_origin' => 1,
'item_thread_top' => 1,
@@ -541,14 +561,19 @@ function photo_upload($channel, $observer, $args) {
// linked item from leaking into the feed when somebody has a channel with read_stream restrictions.
$arr['public_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'], 'view_stream'), true);
- if ($arr['public_policy'])
+
+ if ($arr['public_policy']) {
$arr['item_private'] = 1;
+ }
- $result = item_store($arr, false, $deliver);
- $item_id = $result['item_id'];
+ $result = item_store($arr, deliver: $deliver);
- if ($visible && $deliver)
- Zotlabs\Daemon\Master::Summon(['Notifier', 'wall-new', $item_id]);
+ if ($result['success'] && $visible && $deliver) {
+ Master::Summon(['Notifier', 'wall-new', $result['item_id']]);
+ if (!empty($result['approval_id'])) {
+ Master::Summon(['Notifier', 'wall-new', $result['approval_id']]);
+ }
+ }
}
$ret['success'] = true;
@@ -911,7 +936,7 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
. '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['imgscale'] . '[/zmg]'
. '[/zrl]';
- $result = item_store($arr);
+ $result = item_store($arr, deliver: false, addAndSync: true);
$item_id = $result['item_id'];
return $item_id;
diff --git a/view/css/conversation.css b/view/css/conversation.css
index 491cee92e..fb26c7e3f 100644
--- a/view/css/conversation.css
+++ b/view/css/conversation.css
@@ -96,10 +96,6 @@
/* conv_item */
-.wall-item-head-new {
- border-top: 0.2rem solid var(--bs-primary);
-}
-
.wall-item-wrapper {
margin-left: .75rem;
}
diff --git a/view/js/mod_import_progress.js b/view/js/mod_import_progress.js
index 7aed56365..11b324862 100644
--- a/view/js/mod_import_progress.js
+++ b/view/js/mod_import_progress.js
@@ -30,6 +30,9 @@ $(document).ready(function() {
$('#cprogress-bar').css('width', '0%');
}
+ $('#cprogress-completed span').html(data.ccompleted_str);
+
+
// files
if (typeof data.fprogress == 'number') {
$('#fprogress-label').html(data.fprogress + '%');
@@ -50,5 +53,8 @@ $(document).ready(function() {
$('#fprogress-label').html(data.fprogress);
$('#fprogress-bar').css('width', '0%');
}
+
+ $('#fprogress-completed span').html(data.fcompleted_str);
+
}
});
diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css
index 12f5e1bad..85f5939f8 100644
--- a/view/theme/redbasic/css/style.css
+++ b/view/theme/redbasic/css/style.css
@@ -1144,12 +1144,20 @@ a .drop-icons:hover {
.generic-content-wrapper {
background-color: var(--bs-body-bg);
- border: 1px solid var(--bs-border-color);
+ border: 1px solid var(--bs-light-border-subtle);
border-radius: var(--bs-border-radius);
margin-bottom: 1.5rem;
font-size: 1.1rem;
}
+.generic-content-wrapper.is-contained {
+ border: 1px solid var(--bs-primary-border-subtle);
+}
+
+.generic-content-wrapper.is-new {
+ border-top: 2px solid var(--bs-primary);
+}
+
.section-title-wrapper {
padding: 7px 10px;
background-color: var(--bs-tertiary-bg);
diff --git a/view/tpl/conv_item.tpl b/view/tpl/conv_item.tpl
index 96e30f42d..74e06d6ac 100644
--- a/view/tpl/conv_item.tpl
+++ b/view/tpl/conv_item.tpl
@@ -4,7 +4,7 @@
</div>
<div id="collapsed-comments-{{$item.id}}" class="collapsed-comments" style="display: none;">
{{/if}}
- <div id="thread-wrapper-{{$item.id}}" class="thread-wrapper{{if $item.toplevel}} {{$item.toplevel}} generic-content-wrapper h-entry {{else}} u-comment h-cite{{/if}} clearfix" data-b64mids='{{$item.mids}}'>
+ <div id="thread-wrapper-{{$item.id}}" class="thread-wrapper{{if $item.toplevel}} {{$item.toplevel}} generic-content-wrapper h-entry {{else}} u-comment h-cite{{/if}} clearfix{{if $item.is_contained}} is-contained{{/if}}{{if $item.is_new && !$item.event && !$item.photo && !$item.title && !$item.is_comment}} is-new{{/if}}" data-b64mids='{{$item.mids}}'>
<a name="item_{{$item.id}}" ></a>
<div class="wall-item-outside-wrapper{{if $item.is_comment}} comment{{/if}}{{if $item.previewing}} preview{{/if}}" id="wall-item-outside-wrapper-{{$item.id}}" >
<div class="rounded wall-item-content-wrapper{{if $item.is_comment}} comment{{/if}}" id="wall-item-content-wrapper-{{$item.id}}">
@@ -26,7 +26,7 @@
<hr class="m-0">
{{/if}}
{{/if}}
- <div class="p-2 wall-item-head{{if !$item.title && !$item.event && !$item.photo}} rounded-top{{/if}}{{if $item.is_new && !$item.event && !$item.is_comment}} wall-item-head-new{{/if}} clearfix">
+ <div class="p-2 wall-item-head{{if !$item.title && !$item.event && !$item.photo}} rounded-top{{/if}} clearfix">
<div class="lh-sm text-end float-end">
<div class="wall-item-ago opacity-75" id="wall-item-ago-{{$item.id}}">
{{if $item.location}}
@@ -127,7 +127,7 @@
{{foreach $response.list as $liker}}
{{$liker}}
{{/foreach}}
- </ul>
+ </ul>
</div>
<div class="modal-footer clear">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{{$item.modal_dismiss}}</button>
@@ -138,9 +138,7 @@
{{else}}
<div class="dropdown-menu">
{{if $item.reactions_allowed && !($verb === 'announce' && $item.my_responses.$verb)}} {{** undo announce is not yet supported **}}
- <div class="dropdown-item">
- <a href="#" class="text-reset" onclick="{{$response.button.onclick}}({{$item.id}},'{{$verb}}'); return false;">{{if $item.my_responses.$verb}}- {{$item.reaction_str.1}}{{else}}+ {{$item.reaction_str.0}}{{/if}}</a>
- </div>
+ <a href="#" class="text-reset dropdown-item" onclick="{{$response.button.onclick}}({{$item.id}},'{{$verb}}'); return false;">{{if $item.my_responses.$verb}}- {{$item.reaction_str.1}}{{else}}+ {{$item.reaction_str.0}}{{/if}}</a>
<div class="dropdown-divider"></div>
{{/if}}
{{foreach $response.list as $liker}}{{$liker}}{{/foreach}}
@@ -257,7 +255,7 @@
{{/foreach}}
{{/if}}
{{if $item.comment}}
- <div id="wall-item-comment-wrapper-{{$item.id}}" class="p-2 wall-item-comment-wrapper{{if $item.children}} wall-item-comment-wrapper-wc{{/if}}" >
+ <div id="wall-item-comment-wrapper-{{$item.id}}" class="p-2 rounded wall-item-comment-wrapper{{if $item.children}} wall-item-comment-wrapper-wc{{/if}}">
{{$item.comment}}
</div>
{{/if}}
diff --git a/view/tpl/conv_list.tpl b/view/tpl/conv_list.tpl
index a54a52369..41880029f 100644
--- a/view/tpl/conv_list.tpl
+++ b/view/tpl/conv_list.tpl
@@ -1,7 +1,7 @@
- <div id="thread-wrapper-{{$item.id}}" class="thread-wrapper{{if $item.toplevel}} {{$item.toplevel}} generic-content-wrapper h-entry {{else}} u-comment h-cite {{/if}}" data-b64mids='{{$item.mids}}'>
+ <div id="thread-wrapper-{{$item.id}}" class="thread-wrapper{{if $item.toplevel}} {{$item.toplevel}} generic-content-wrapper h-entry {{else}} u-comment h-cite{{/if}} clearfix{{if $item.is_contained}} is-contained{{/if}}{{if $item.is_new && !$item.event && !$item.title && !$item.is_comment}} is-new{{/if}}" data-b64mids='{{$item.mids}}'>
<a name="item_{{$item.id}}" ></a>
<div class="wall-item-outside-wrapper{{if $item.is_comment}} comment{{/if}}{{if $item.previewing}} preview{{/if}}" id="wall-item-outside-wrapper-{{$item.id}}" >
- <div class="clearfix wall-item-content-wrapper{{if $item.is_comment}} comment{{/if}}" id="wall-item-content-wrapper-{{$item.id}}">
+ <div class="rounded clearfix wall-item-content-wrapper{{if $item.is_comment}} comment{{/if}}" id="wall-item-content-wrapper-{{$item.id}}">
{{if $item.photo}}
<div class="wall-photo-item" id="wall-photo-item-{{$item.id}}">
{{$item.photo}}