diff options
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; @@ -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}} |