aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/ActivityStreams/ASObject.php776
-rw-r--r--Zotlabs/ActivityStreams/Activity.php122
-rw-r--r--Zotlabs/ActivityStreams/Actor.php428
-rw-r--r--Zotlabs/ActivityStreams/AssertionMethod.php87
-rw-r--r--Zotlabs/ActivityStreams/Collection.php124
-rw-r--r--Zotlabs/ActivityStreams/CollectionPage.php73
-rw-r--r--Zotlabs/ActivityStreams/IntransitiveActivity.php104
-rw-r--r--Zotlabs/ActivityStreams/Link.php183
-rw-r--r--Zotlabs/ActivityStreams/OrderedCollection.php8
-rw-r--r--Zotlabs/ActivityStreams/OrderedCollectionPage.php92
-rw-r--r--Zotlabs/ActivityStreams/Place.php125
-rw-r--r--Zotlabs/ActivityStreams/Profile.php29
-rw-r--r--Zotlabs/ActivityStreams/PublicKey.php68
-rw-r--r--Zotlabs/ActivityStreams/Question.php67
-rw-r--r--Zotlabs/ActivityStreams/Relationship.php67
-rw-r--r--Zotlabs/ActivityStreams/Signature.php65
-rw-r--r--Zotlabs/ActivityStreams/Tombstone.php48
-rw-r--r--Zotlabs/ActivityStreams/UnhandledElementException.php8
-rw-r--r--Zotlabs/Daemon/Cache_embeds.php15
-rw-r--r--Zotlabs/Daemon/Channel_purge.php2
-rw-r--r--Zotlabs/Daemon/Content_importer.php12
-rw-r--r--Zotlabs/Daemon/Cron.php58
-rw-r--r--Zotlabs/Daemon/Expire.php4
-rw-r--r--Zotlabs/Daemon/File_importer.php8
-rw-r--r--Zotlabs/Daemon/Importdoc.php21
-rw-r--r--Zotlabs/Daemon/Notifier.php43
-rw-r--r--Zotlabs/Entity/Account.php352
-rw-r--r--Zotlabs/Entity/Channel.php714
-rw-r--r--Zotlabs/Entity/Item.php1498
-rw-r--r--Zotlabs/Lib/Activity.php774
-rw-r--r--Zotlabs/Lib/ActivityStreams.php2
-rw-r--r--Zotlabs/Lib/Apps.php2
-rw-r--r--Zotlabs/Lib/BaseObject.php80
-rw-r--r--Zotlabs/Lib/Chatroom.php2
-rw-r--r--Zotlabs/Lib/Connect.php8
-rw-r--r--Zotlabs/Lib/DB_Upgrade.php31
-rw-r--r--Zotlabs/Lib/DReport.php10
-rw-r--r--Zotlabs/Lib/Enotify.php83
-rw-r--r--Zotlabs/Lib/IConfig.php6
-rw-r--r--Zotlabs/Lib/JcsEddsa2022.php25
-rw-r--r--Zotlabs/Lib/JcsEddsa2022SignException.php15
-rw-r--r--Zotlabs/Lib/Libsync.php2
-rw-r--r--Zotlabs/Lib/Libzot.php170
-rw-r--r--Zotlabs/Lib/Mailer.php86
-rw-r--r--Zotlabs/Lib/MessageFilter.php154
-rw-r--r--Zotlabs/Lib/SuperCurl.php127
-rw-r--r--Zotlabs/Lib/Text.php9
-rw-r--r--Zotlabs/Lib/ThreadItem.php229
-rw-r--r--Zotlabs/Lib/ThreadStream.php9
-rw-r--r--Zotlabs/Lib/Traits/HelpHelperTrait.php2
-rw-r--r--Zotlabs/Module/Achievements.php44
-rw-r--r--Zotlabs/Module/Acl.php16
-rw-r--r--Zotlabs/Module/Activity.php7
-rw-r--r--Zotlabs/Module/Admin/Account_edit.php11
-rw-r--r--Zotlabs/Module/Admin/Accounts.php258
-rw-r--r--Zotlabs/Module/Admin/Addons.php285
-rw-r--r--Zotlabs/Module/Admin/Features.php5
-rw-r--r--Zotlabs/Module/Admin/Site.php3
-rw-r--r--Zotlabs/Module/Admin/Themes.php2
-rw-r--r--Zotlabs/Module/Api.php3
-rw-r--r--Zotlabs/Module/Apporder.php4
-rw-r--r--Zotlabs/Module/Apps.php4
-rw-r--r--Zotlabs/Module/Attach_edit.php5
-rw-r--r--Zotlabs/Module/Authorize.php9
-rw-r--r--Zotlabs/Module/Authtest.php4
-rw-r--r--Zotlabs/Module/Changeaddr.php40
-rw-r--r--Zotlabs/Module/Channel.php62
-rw-r--r--Zotlabs/Module/Channel_calendar.php30
-rw-r--r--Zotlabs/Module/Chatsvc.php2
-rw-r--r--Zotlabs/Module/Cloud.php37
-rw-r--r--Zotlabs/Module/Conversation.php13
-rw-r--r--Zotlabs/Module/Cover_photo.php9
-rw-r--r--Zotlabs/Module/Dav.php1
-rw-r--r--Zotlabs/Module/Display.php34
-rw-r--r--Zotlabs/Module/Dreport.php8
-rw-r--r--Zotlabs/Module/Editpost.php1
-rw-r--r--Zotlabs/Module/Embedphotos.php8
-rw-r--r--Zotlabs/Module/Fbrowser.php2
-rw-r--r--Zotlabs/Module/File_upload.php67
-rw-r--r--Zotlabs/Module/Filer.php63
-rw-r--r--Zotlabs/Module/Go.php4
-rw-r--r--Zotlabs/Module/Help.php6
-rw-r--r--Zotlabs/Module/Home.php29
-rw-r--r--Zotlabs/Module/Hq.php15
-rw-r--r--Zotlabs/Module/Id.php6
-rw-r--r--Zotlabs/Module/Impel.php4
-rw-r--r--Zotlabs/Module/Import.php3
-rw-r--r--Zotlabs/Module/Import_progress.php20
-rw-r--r--Zotlabs/Module/Invite.php54
-rw-r--r--Zotlabs/Module/Item.php740
-rw-r--r--Zotlabs/Module/Lang.php16
-rw-r--r--Zotlabs/Module/Like.php58
-rw-r--r--Zotlabs/Module/Login.php22
-rw-r--r--Zotlabs/Module/Magic.php66
-rw-r--r--Zotlabs/Module/Mitem.php30
-rw-r--r--Zotlabs/Module/Moderate.php6
-rw-r--r--Zotlabs/Module/Network.php73
-rw-r--r--Zotlabs/Module/Notify.php4
-rw-r--r--Zotlabs/Module/OAuth2TestVehicle.php8
-rw-r--r--Zotlabs/Module/Oauth.php12
-rw-r--r--Zotlabs/Module/Oauth2.php12
-rw-r--r--Zotlabs/Module/Oep.php1
-rw-r--r--Zotlabs/Module/Owa.php186
-rw-r--r--Zotlabs/Module/Page.php4
-rw-r--r--Zotlabs/Module/Pdledit.php2
-rw-r--r--Zotlabs/Module/Permcat.php4
-rw-r--r--Zotlabs/Module/Photos.php34
-rw-r--r--Zotlabs/Module/Pin.php5
-rw-r--r--Zotlabs/Module/Profperm.php2
-rw-r--r--Zotlabs/Module/Pubstream.php21
-rw-r--r--Zotlabs/Module/React.php3
-rw-r--r--Zotlabs/Module/Regate.php4
-rw-r--r--Zotlabs/Module/Removeaccount.php20
-rw-r--r--Zotlabs/Module/Removeme.php6
-rw-r--r--Zotlabs/Module/Request.php89
-rw-r--r--Zotlabs/Module/Rmagic.php4
-rw-r--r--Zotlabs/Module/Search_ac.php7
-rw-r--r--Zotlabs/Module/Settings/Account.php4
-rw-r--r--Zotlabs/Module/Settings/Calendar.php5
-rw-r--r--Zotlabs/Module/Settings/Channel_home.php5
-rw-r--r--Zotlabs/Module/Settings/Connections.php5
-rw-r--r--Zotlabs/Module/Settings/Conversation.php2
-rw-r--r--Zotlabs/Module/Settings/Directory.php5
-rw-r--r--Zotlabs/Module/Settings/Display.php9
-rw-r--r--Zotlabs/Module/Settings/Editor.php5
-rw-r--r--Zotlabs/Module/Settings/Events.php5
-rw-r--r--Zotlabs/Module/Settings/Features.php7
-rw-r--r--Zotlabs/Module/Settings/Manage.php5
-rw-r--r--Zotlabs/Module/Settings/Network.php5
-rw-r--r--Zotlabs/Module/Settings/Photos.php5
-rw-r--r--Zotlabs/Module/Settings/Profiles.php5
-rw-r--r--Zotlabs/Module/Setup.php5
-rw-r--r--Zotlabs/Module/Share.php6
-rw-r--r--Zotlabs/Module/Snap.php20
-rw-r--r--Zotlabs/Module/Sse.php3
-rw-r--r--Zotlabs/Module/Sse_bs.php170
-rw-r--r--Zotlabs/Module/Subthread.php2
-rw-r--r--Zotlabs/Module/Tagger.php6
-rw-r--r--Zotlabs/Module/Tagrm.php98
-rw-r--r--Zotlabs/Module/Thing.php46
-rw-r--r--Zotlabs/Module/Viewsrc.php32
-rw-r--r--Zotlabs/Module/Vote.php9
-rw-r--r--Zotlabs/Module/Wall_attach.php9
-rw-r--r--Zotlabs/Module/Webfinger.php14
-rw-r--r--Zotlabs/Module/Webpages.php5
-rw-r--r--Zotlabs/Module/Xref.php26
-rw-r--r--Zotlabs/Module/Zot_probe.php12
-rw-r--r--Zotlabs/Photo/PhotoGd.php15
-rw-r--r--Zotlabs/Render/SmartyInterface.php10
-rw-r--r--Zotlabs/Render/Theme.php15
-rw-r--r--Zotlabs/Storage/Browser.php9
-rw-r--r--Zotlabs/Storage/GitRepo.php159
-rw-r--r--Zotlabs/Thumbs/Epubthumb.php183
-rw-r--r--Zotlabs/Update/_1007.php4
-rw-r--r--Zotlabs/Update/_1151.php4
-rw-r--r--Zotlabs/Web/HTTPSig.php46
-rw-r--r--Zotlabs/Web/HttpMeta.php13
-rw-r--r--Zotlabs/Web/Router.php91
-rw-r--r--Zotlabs/Web/Session.php2
-rw-r--r--Zotlabs/Web/WebServer.php92
-rw-r--r--Zotlabs/Widget/Activity.php2
-rw-r--r--Zotlabs/Widget/Activity_order.php42
-rw-r--r--Zotlabs/Widget/Album.php11
-rw-r--r--Zotlabs/Widget/Channel_activities.php10
-rw-r--r--Zotlabs/Widget/Item.php2
-rw-r--r--Zotlabs/Widget/Messages.php79
-rw-r--r--Zotlabs/Widget/Notifications.php52
-rw-r--r--Zotlabs/Widget/Pinned.php98
-rw-r--r--Zotlabs/Widget/Portfolio.php10
-rw-r--r--Zotlabs/Widget/Tagcloud.php3
-rw-r--r--Zotlabs/Widget/Tasklist.php2
-rw-r--r--Zotlabs/Zot6/Zot6Handler.php10
172 files changed, 8234 insertions, 2909 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/Cache_embeds.php b/Zotlabs/Daemon/Cache_embeds.php
index d5adfcc59..99b1c7ac0 100644
--- a/Zotlabs/Daemon/Cache_embeds.php
+++ b/Zotlabs/Daemon/Cache_embeds.php
@@ -6,23 +6,28 @@ class Cache_embeds {
static public function run($argc,$argv) {
- if(! $argc == 2)
+ if(!$argc == 2) {
return;
+ }
- $c = q("select body from item where id = %d ",
- dbesc(intval($argv[1]))
+ $c = q("select uid, aid, body, item_private from item where uuid = '%s'",
+ dbesc($argv[1])
);
- if(! $c)
+ if(!$c) {
return;
+ }
$item = $c[0];
// bbcode conversion by default processes embeds that aren't already cached.
// Ignore the returned html output.
-
bbcode($item['body']);
+ // photocache addon hook to prefetch one copy of public item images for the sys channel
+ call_hooks('cache_prefetch_hook', $item);
+
return;
}
+
}
diff --git a/Zotlabs/Daemon/Channel_purge.php b/Zotlabs/Daemon/Channel_purge.php
index 9fceb0fb9..7286a791a 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'], uid: $channel_id);
}
}
} while ($r);
diff --git a/Zotlabs/Daemon/Content_importer.php b/Zotlabs/Daemon/Content_importer.php
index 67f1c8e80..b98a1f10d 100644
--- a/Zotlabs/Daemon/Content_importer.php
+++ b/Zotlabs/Daemon/Content_importer.php
@@ -38,7 +38,13 @@ class Content_importer {
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
- $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]);
+ $redirects = 0;
+ $x = z_fetch_url(
+ $hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,
+ false,
+ $redirects,
+ [ 'headers' => $headers ]
+ );
// logger('item fetch: ' . print_r($x,true));
@@ -47,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 d2c863572..131abe2e1 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -69,18 +69,18 @@ class Cron {
// expire any expired items
- $r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
+ $r = q("select id, uid, item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
and item_deleted = 0 ",
db_utcnow()
);
+
if ($r) {
- require_once('include/items.php');
foreach ($r as $rr) {
- drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
+ // pass uid of the message for permission check as we are running as a daemon process with no session.
+ 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']]);
-
if ($interval) {
usleep($interval);
}
@@ -125,14 +125,15 @@ class Cron {
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
- db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
+ db_quoteinterval(Config::Get('system', 'default_expire_days', 30) . ' DAY')
);
if ($r) {
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
- db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
+ db_quoteinterval(Config::Get('system', 'default_expire_days', 30) . ' DAY')
);
+
foreach ($r as $rr) {
$file = dbunescbin($rr['content']);
if (is_file($file)) {
@@ -147,40 +148,29 @@ class Cron {
// (time travel posts). Restrict to items that have come of age in the last
// couple of days to limit the query to something reasonable.
- $r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
+ $r = q("select * from item where item_delayed = 1 and created <= %s and created > '%s' ",
db_utcnow(),
dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days'))
);
- if ($r) {
- foreach ($r as $rr) {
- $x = q("update item set item_delayed = 0 where id = %d",
- intval($rr['id'])
- );
- if ($x) {
- $z = q("select * from item where id = %d",
- intval($rr['id'])
- );
- if ($z) {
- xchan_query($z);
- $sync_item = fetch_post_tags($z);
- Libsync::build_sync_packet($sync_item[0]['uid'],
- [
- 'item' => [encode_item($sync_item[0], true)]
- ]
- );
- }
- Master::Summon(array('Notifier', 'wall-new', $rr['id']));
- if ($interval) {
- usleep($interval);
+ if ($r) {
+ xchan_query($r);
+ $items = fetch_post_tags($r);
+ foreach ($items as $item) {
+ $item['item_delayed'] = 0;
+ $post = item_store_update($item);
+
+ if($post['success']) {
+ Master::Summon(['Notifier', 'wall-new', $post['item_id']]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'wall-new', $post['approval_id']]);
}
}
- }
- }
-
- require_once('include/attach.php');
- attach_upgrade();
-
+ if ($interval) {
+ usleep($interval);
+ }
+ }
+ }
// once daily run birthday_updates and then expire in background
// FIXME: add birthday updates, both locally and for xprof for use
diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php
index ad52a6b71..dae585578 100644
--- a/Zotlabs/Daemon/Expire.php
+++ b/Zotlabs/Daemon/Expire.php
@@ -23,13 +23,13 @@ class Expire {
// perform final cleanup on previously delete items
- $r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
+ $r = q("select id, uid from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('10 DAY')
);
if ($r) {
foreach ($r as $rr) {
- drop_item($rr['id'], false, DROPITEM_PHASE2);
+ drop_item($rr['id'], DROPITEM_PHASE2, uid: $rr['uid']);
}
}
diff --git a/Zotlabs/Daemon/File_importer.php b/Zotlabs/Daemon/File_importer.php
index 7067e152d..1ddab60f0 100644
--- a/Zotlabs/Daemon/File_importer.php
+++ b/Zotlabs/Daemon/File_importer.php
@@ -38,7 +38,13 @@ class File_importer {
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512');
// TODO: implement total count
- $x = z_fetch_url($hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
+ $redirects = 0;
+ $x = z_fetch_url(
+ $hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page,
+ false,
+ $redirects,
+ [ 'headers' => $headers ]
+ );
// logger('file fetch: ' . print_r($x,true));
if(! $x['success']) {
diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php
index c5a81e50c..de571848e 100644
--- a/Zotlabs/Daemon/Importdoc.php
+++ b/Zotlabs/Daemon/Importdoc.php
@@ -11,6 +11,21 @@ class Importdoc {
self::update_docs_dir('doc/*');
+ $sys = get_sys_channel();
+
+ // remove old files that weren't updated (indicates they were most likely deleted).
+ $i = q("select id from item where uid = %d and item_type = 5 and edited < %s - INTERVAL %s",
+ intval($sys['channel_id']),
+ db_utcnow(),
+ db_quoteinterval('14 DAY')
+ );
+
+ if ($i) {
+ foreach ($i as $iv) {
+ drop_item($iv['id'], uid: $sys['channel_id']);
+ }
+ }
+
return;
}
@@ -18,9 +33,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') {
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 20134b8fe..9fdb1defb 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -241,11 +241,6 @@ class Notifier {
$target_item = $r[0];
- if (in_array($target_item['author']['xchan_network'], ['rss', 'anon', 'token'])) {
- logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
- return;
- }
-
if (intval($target_item['item_deleted'])) {
logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
}
@@ -268,22 +263,9 @@ class Notifier {
}
- // Check for non published items, but allow an exclusion for transmitting hidden file activities
-
- if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
- intval($target_item['item_blocked']) || intval($target_item['item_hidden'])) {
- logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
- return;
- }
-
- // follow/unfollow is for internal use only
- if (in_array($target_item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
- logger('not fowarding follow/unfollow note activity');
- return;
- }
-
- if (strpos($target_item['postopts'], 'nodeliver') !== false) {
- logger('notifier: target item is undeliverable', LOGGER_DEBUG);
+ if (!item_forwardable($target_item)) {
+ //hz_syslog(print_r($target_item,true));
+ logger('notifier: target item not forwardable', LOGGER_DEBUG);
return;
}
@@ -299,7 +281,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'];
}
@@ -341,7 +323,13 @@ class Notifier {
self::$encoded_item = json_decode($m, true);
}
else {
- self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
+ $activity = Activity::encode_activity($target_item);
+
+ if (!$activity) {
+ return;
+ }
+
+ self::$encoded_item = Activity::build_packet($activity, self::$channel, false);
}
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
@@ -358,6 +346,10 @@ class Notifier {
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
+ if (self::$channel['channel_hash'] === $target_item['owner_xchan']) {
+ $relay_to_owner = false;
+ }
+
// $cmd === 'relay' indicates the owner is sending it to the original recipients
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
@@ -374,7 +366,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;
@@ -389,7 +380,7 @@ class Notifier {
logger('normal (downstream) distribution', LOGGER_DEBUG);
}
- if ($parent_item && $parent_item['item_private'] !== $target_item['item_private']) {
+ if (($parent_item && $parent_item['item_private'] !== $target_item['item_private']) || (intval($target_item['item_restrict']) & 1)) {
logger('conversation privacy mismatch - downstream delivery prevented');
return;
}
@@ -589,8 +580,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..76ff8b150
--- /dev/null
+++ b/Zotlabs/Entity/Item.php
@@ -0,0 +1,1498 @@
+<?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 getMimetype()
+ {
+ return $this->mimetype;
+ }
+
+ /**
+ * @param mixed $mimetype
+ * @return Item
+ */
+ public function setMimetype($mimetype)
+ {
+ $this->mimetype = $mimetype;
+ 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 1ea42acd3..296129ea2 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -8,10 +8,12 @@ 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');
require_once('include/items.php');
+require_once('include/markdown.php');
class Activity {
@@ -67,10 +69,10 @@ class Activity {
if ($j) {
xchan_query($j, true);
$items = fetch_post_tags($j);
- }
- if ($items) {
- return self::encode_item(array_shift($items));
+ if ($items) {
+ return self::encode_item(array_shift($items));
+ }
}
return null;
@@ -164,7 +166,7 @@ class Activity {
}
else {
logger('fetch failed: ' . $url);
- logger($x['body']);
+ logger(print_r($x, true), LOGGER_DEBUG);
}
@@ -503,15 +505,21 @@ class Activity {
$ret['diaspora:guid'] = $i['uuid'];
$images = [];
+ $audios = [];
+ $videos = [];
+
$has_images = preg_match_all('/\[[zi]mg(.*?)](.*?)\[/ism', $i['body'], $images, PREG_SET_ORDER);
+ $has_audios = preg_match_all('/\[zaudio](.*?)\[/ism', $i['body'], $audios, PREG_SET_ORDER);
+ $has_videos = preg_match_all('/\[zvideo](.*?)\[/ism', $i['body'], $videos, PREG_SET_ORDER);
// provide ocap access token for private media.
// set this for descendants even if the current item is not private
// because it may have been relayed from a private item.
$token = IConfig::Get($i, 'ocap', 'relay');
+ $matches_processed = [];
+
if ($token && $has_images) {
- $matches_processed = [];
for ($n = 0; $n < count($images); $n++) {
$match = $images[$n];
if (str_starts_with($match[1], '=http') && str_contains($match[1], z_root() . '/photo/') && !in_array($match[1], $matches_processed)) {
@@ -526,6 +534,28 @@ class Activity {
}
}
+ if ($token && $has_audios) {
+ for ($n = 0; $n < count($audios); $n++) {
+ $match = $audios[$n];
+ if (str_contains($match[1], z_root() . '/attach/') && !in_array($match[1], $matches_processed)) {
+ $i['body'] = str_replace($match[1], $match[1] . '?token=' . $token, $i['body']);
+ $audios[$n][1] = $match[1] . '?token=' . $token;
+ $matches_processed[] = $match[1];
+ }
+ }
+ }
+
+ if ($token && $has_videos) {
+ for ($n = 0; $n < count($videos); $n++) {
+ $match = $videos[$n];
+ if (str_contains($match[1], z_root() . '/attach/') && !in_array($match[1], $matches_processed)) {
+ $i['body'] = str_replace($match[1], $match[1] . '?token=' . $token, $i['body']);
+ $videos[$n][1] = $match[1] . '?token=' . $token;
+ $matches_processed[] = $match[1];
+ }
+ }
+ }
+
if ($i['title'])
$ret['name'] = unescape_tags($i['title']);
@@ -551,14 +581,12 @@ class Activity {
}
}
- if (intval($i['item_wall'])) {
- $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'], 'post_comments'));
- }
-
if (intval($i['item_private']) === 2) {
$ret['directMessage'] = true;
}
+ $ret['commentPolicy'] = (($i['item_wall']) ? map_scope(PermissionLimits::Get($i['uid'], 'post_comments')) : '');
+
if (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) {
if ($ret['commentPolicy']) {
$ret['commentPolicy'] .= ' ';
@@ -570,6 +598,26 @@ 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['contextHistory'] = $cnv;
+ }
+ $ret['context'] = $cnv;
}
if ($i['mimetype'] === 'text/bbcode') {
@@ -589,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;
}
@@ -596,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];
}
@@ -627,7 +694,7 @@ class Activity {
if (is_array($t) && !array_key_exists('type', $t))
$t['type'] = 'Hashtag';
- if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t)) && array_key_exists('name', $t)) {
+ if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t) || isset($t['icon']['url'])) && array_key_exists('name', $t)) {
switch ($t['type']) {
case 'Hashtag':
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
@@ -642,7 +709,7 @@ class Activity {
break;
case 'Emoji':
- $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
+ $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'] ?? $t['icon']['url'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
break;
default:
@@ -694,6 +761,8 @@ class Activity {
$ret = [];
+ $token = IConfig::Get($item, 'ocap', 'relay');
+
if (!$iconfig && array_key_exists('attach', $item)) {
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
if ($atts) {
@@ -702,11 +771,17 @@ class Activity {
continue;
}
- if (isset($att['type']) && strpos($att['type'], 'image')) {
- $ret[] = ['type' => 'Image', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href']];
+ if (str_starts_with($att['type'], 'image')) {
+ $ret[] = ['type' => 'Image', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
+ }
+ elseif (str_starts_with($att['type'], 'audio')) {
+ $ret[] = ['type' => 'Audio', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
+ }
+ elseif (str_starts_with($att['type'], 'video')) {
+ $ret[] = ['type' => 'Video', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
}
else {
- $ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'name' => $att['title'], 'href' => $att['href']];
+ $ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'name' => $att['title'], 'href' => $att['href'] . (($token) ? '?token=' . $token : '')];
}
}
}
@@ -727,7 +802,7 @@ class Activity {
$ret = [];
- if (isset($item['attachment'])) {
+ if (isset($item['attachment']) && is_array($item['attachment'])) {
$ptr = $item['attachment'];
if (!array_key_exists(0, $ptr)) {
$ptr = [$ptr];
@@ -777,6 +852,8 @@ class Activity {
$entry['type'] = $att['mediaType'];
} elseif (array_key_exists('type', $att) && $att['type'] === 'Image') {
$entry['type'] = 'image/jpeg';
+ } elseif (array_key_exists('type', $att) && $att['type'] === 'Link') {
+ $entry['type'] = 'text/uri-list';
}
if (array_key_exists('name', $att) && $att['name']) {
$entry['name'] = html2plain(purify_html($att['name']), 256);
@@ -807,12 +884,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';
@@ -846,36 +943,8 @@ class Activity {
}
- if ($ret['type'] === 'emojiReaction') {
- // There may not be an object for these items for legacy reasons - it should be the conversation parent.
- $p = q("select * from item where mid = '%s' and uid = %d",
- dbesc($i['parent_mid']),
- intval($i['uid'])
- );
- if ($p) {
- xchan_query($p, true);
- $p = fetch_post_tags($p);
- $i['obj'] = self::encode_item($p[0]);
-
- // convert to zot6 emoji reaction encoding which uses the target object to indicate the
- // specific emoji instead of overloading the verb or type.
-
- $im = explode('#', $i['verb']);
- if ($im && count($im) > 1)
- $emoji = $im[1];
- if (preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
- $ln = $match[2];
- }
-
- $i['tgt_type'] = 'Image';
-
- $i['target'] = [
- 'type' => 'Image',
- 'name' => $emoji,
- 'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
- ];
-
- }
+ if ($ret['type'] === 'EmojiReact') {
+ $ret['content'] = $i['body'];
}
if (strpos($i['mid'], z_root() . '/item/') !== false) {
@@ -890,15 +959,15 @@ class Activity {
$ret['diaspora:guid'] = $i['uuid'];
- if (isset($i['title']) && $i['title'])
- $ret['name'] = html2plain(bbcode($i['title'], ['cache' => true]));
+ if (!empty($i['title']))
+ $ret['name'] = html2plain(bbcode($i['title']));
- if (isset($i['summary']) && $i['summary'])
- $ret['summary'] = bbcode($i['summary'], ['cache' => true]);
+ if (!empty($i['summary']))
+ $ret['summary'] = bbcode($i['summary']);
if ($ret['type'] === 'Announce') {
$tmp = preg_replace('/\[share(.*?)\[\/share\]/ism', EMPTY_STR, $i['body']);
- $ret['content'] = bbcode($tmp, ['cache' => true]);
+ $ret['content'] = bbcode($tmp);
$ret['source'] = [
'content' => $i['body'],
'mediaType' => 'text/bbcode'
@@ -914,7 +983,7 @@ class Activity {
}
}
- if (isset($i['app']) && $i['app']) {
+ if (!empty($i['app'])) {
$ret['generator'] = ['type' => 'Application', 'name' => $i['app']];
}
if (!empty($i['location']) || !empty($i['coord'])) {
@@ -935,9 +1004,29 @@ 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['contextHistory'] = $cnv;
+ }
+ $ret['context'] = $cnv;
}
$actor = self::encode_person($i['author'], false);
@@ -946,7 +1035,7 @@ class Activity {
else
return [];
- if (isset($i['obj']) && $i['obj']) {
+ if (!empty($i['obj'])) {
if (!is_array($i['obj'])) {
$i['obj'] = json_decode($i['obj'], true);
}
@@ -974,7 +1063,7 @@ class Activity {
$ret['type'] = 'Invite';
}
- if (isset($i['target']) && $i['target']) {
+ if (!empty($i['target'])) {
if (!is_array($i['target'])) {
$i['target'] = json_decode($i['target'], true);
}
@@ -985,12 +1074,10 @@ class Activity {
return [];
}
-/* this should not be needed
$t = self::encode_taxonomy($i);
if ($t) {
$ret['tag'] = $t;
}
-*/
$a = self::encode_attachment($i, true);
if ($a) {
@@ -1001,7 +1088,6 @@ class Activity {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
}
-
$hookinfo = [
'item' => $i,
'encoded' => $ret
@@ -1010,6 +1096,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.
@@ -1253,81 +1340,6 @@ class Activity {
// return false;
}
- static function activity_decode_mapper($verb) {
-
- $acts = [
- 'http://activitystrea.ms/schema/1.0/post' => 'Create',
- // 'http://activitystrea.ms/schema/1.0/share' => 'Announce',
- 'http://activitystrea.ms/schema/1.0/update' => 'Update',
- 'http://activitystrea.ms/schema/1.0/like' => 'Like',
- 'http://activitystrea.ms/schema/1.0/favorite' => 'Like',
- 'http://purl.org/zot/activity/dislike' => 'Dislike',
- // 'http://activitystrea.ms/schema/1.0/tag' => 'Add',
- 'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
- 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
- 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow',
- 'http://purl.org/zot/activity/attendyes' => 'Accept',
- 'http://purl.org/zot/activity/attendno' => 'Reject',
- 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
- 'Announce' => 'Announce',
- 'Invite' => 'Invite',
- 'Delete' => 'Delete',
- 'Undo' => 'Undo',
- 'Add' => 'Add',
- 'Remove' => 'Remove'
- ];
-
- call_hooks('activity_decode_mapper', $acts);
-
- foreach ($acts as $k => $v) {
- if ($verb === $v) {
- return $k;
- }
- }
-
- logger('Unmapped activity: ' . $verb);
- return 'Create';
-
- }
-
- static function activity_obj_decode_mapper($obj) {
-
- $objs = [
- 'http://activitystrea.ms/schema/1.0/note' => 'Note',
- 'http://activitystrea.ms/schema/1.0/note' => 'Article',
- 'http://activitystrea.ms/schema/1.0/comment' => 'Note',
- 'http://activitystrea.ms/schema/1.0/person' => 'Person',
- 'http://purl.org/zot/activity/profile' => 'Profile',
- 'http://activitystrea.ms/schema/1.0/photo' => 'Image',
- 'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon',
- 'http://activitystrea.ms/schema/1.0/event' => 'Event',
- 'http://purl.org/zot/activity/location' => 'Place',
- 'http://purl.org/zot/activity/chessgame' => 'Game',
- 'http://purl.org/zot/activity/tagterm' => 'zot:Tag',
- 'http://purl.org/zot/activity/thing' => 'Object',
- 'http://purl.org/zot/activity/file' => 'zot:File',
- 'http://purl.org/zot/activity/mood' => 'zot:Mood',
- 'Invite' => 'Invite',
- 'Question' => 'Question',
- 'Document' => 'Document',
- 'Audio' => 'Audio',
- 'Video' => 'Video',
- 'Delete' => 'Delete',
- 'Undo' => 'Undo'
- ];
-
- call_hooks('activity_obj_decode_mapper', $objs);
-
- foreach ($objs as $k => $v) {
- if ($obj === $v) {
- return $k;
- }
- }
-
- logger('Unmapped activity object: ' . $obj);
- return 'Note';
- }
-
static function activity_obj_mapper($obj) {
$objs = [
@@ -1606,9 +1618,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']);
@@ -1676,9 +1688,9 @@ class Activity {
return;
}
- $name = $person_obj['name'] ?? '';
+ $name = ((isset($person_obj['name'])) ? escape_tags($person_obj['name']) : '');
if (!$name) {
- $name = $person_obj['preferredUsername'] ?? '';
+ $name = ((isset($person_obj['preferredUsername'])) ? escape_tags($person_obj['preferredUsername']) : '');
}
if (!$name) {
$name = t('Unknown');
@@ -1687,13 +1699,11 @@ class Activity {
$webfinger_addr = ((isset($person_obj['webfinger'])) ? str_replace('acct:', '', $person_obj['webfinger']) : '');
$hostname = '';
$baseurl = '';
- $site_url = '';
$m = parse_url($url);
if ($m) {
- $hostname = $m['host'];
- $baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
- $site_url = $m['scheme'] . '://' . $m['host'];
+ $hostname = unparse_url($m, ['host']);
+ $baseurl = unparse_url($m, ['scheme', 'host', 'port']);
}
if (!$webfinger_addr && !empty($person_obj['preferredUsername']) && $hostname) {
@@ -1795,7 +1805,7 @@ class Activity {
q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s'",
dbesc(datetime_convert()),
- dbesc($site_url)
+ dbesc($baseurl)
);
// update existing xchan record
@@ -1906,129 +1916,173 @@ 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;
- }
+ $edited = datetime_convert();
+ $i[0]['edited'] = $edited;
+
+ // 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($edited)
+ );
+ 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) {
@@ -2064,35 +2118,25 @@ class Activity {
$s['owner_xchan'] = $act->actor['id'];
$s['author_xchan'] = $act->actor['id'];
- $content = [];
+ $s['mid'] = self::getMessageID($act);
- if (is_array($act->obj)) {
- $content = self::get_content($act->obj);
+ if (!$s['mid']) {
+ return false;
}
- $s['mid'] = $act->objprop('id');
+ $s['uuid'] = self::getUUID($act);
- if (!$s['mid'] && is_string($act->obj)) {
- $s['mid'] = $act->obj;
+ if (!$s['uuid']) {
+ // If we have not found anything useful, create an uuid v5 from the mid
+ $s['uuid'] = uuid_from_url($s['mid']);
}
- // pleroma fetched activities
- if (!$s['mid'] && isset($act->obj['data']['id'])) {
- $s['mid'] = $act->obj['data']['id'];
- }
-
- if ($act->objprop('type') === 'Profile') {
- $s['mid'] = $act->id;
- }
+ $content = [];
- if (!$s['mid']) {
- return false;
+ if (is_array($act->obj)) {
+ $content = self::get_content($act->obj);
}
- // Friendica sends the diaspora guid in a nonstandard field via AP
- // If no uuid is provided we will create an uuid v5 from the mid
- $s['uuid'] = (($act->objprop('diaspora:guid')) ?: uuid_from_url($s['mid']));
-
$s['parent_mid'] = $act->parent_id;
if (array_key_exists('published', $act->data)) {
@@ -2131,23 +2175,8 @@ class Activity {
$response_activity = true;
- $s['mid'] = $act->id;
- $s['uuid'] = ((!empty($act->data['diaspora:guid'])) ? $act->data['diaspora:guid'] : uuid_from_url($s['mid']));
-
$s['parent_mid'] = $act->objprop('id') ?: $act->obj;
-/*
- if ($act->objprop('inReplyTo')) {
- $s['parent_mid'] = $act->objprop('inReplyTo');
- }
-
- $s['thr_parent'] = $act->objprop('id') ?: $act->obj;
-
- if (empty($s['parent_mid']) || empty($s['thr_parent'])) {
- logger('response activity without parent_mid or thr_parent');
- return;
- }
-*/
// over-ride the object timestamp with the activity
if (isset($act->data['published'])) {
@@ -2158,9 +2187,9 @@ class Activity {
$s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']);
}
- $obj_actor = $act->objprop('actor') ?: $act->get_actor('attributedTo', $act->obj);
+ $obj_actor = is_array($act->objprop('actor')) ? $act->objprop('actor') : $act->get_actor('attributedTo', $act->obj);
- if (!isset($obj_actor['id'])) {
+ if (empty($obj_actor['id'])) {
return false;
}
@@ -2196,12 +2225,8 @@ class Activity {
$content['content'] = sprintf(t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
}
- // TODO: Deprecated
- if ($act->type === 'emojiReaction') {
- $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';');
- }
-
if (in_array($act->type, ['EmojiReact'])) {
+
// Pleroma reactions
$t = trim(self::get_textfield($act->data, 'content'));
@@ -2225,6 +2250,8 @@ class Activity {
if ($s['mid'] === $s['parent_mid']) {
$s['item_thread_top'] = 1;
+ $s['item_nocomment'] = 0;
+ $s['comments_closed'] = NULL_DATE;
// it is a parent node - decode the comment policy info if present
if ($act->objprop('commentPolicy')) {
@@ -2232,7 +2259,7 @@ class Activity {
if ($until !== false) {
$s['comments_closed'] = datetime_convert('UTC', 'UTC', substr($act->obj['commentPolicy'], $until + 6));
if ($s['comments_closed'] < datetime_convert()) {
- $s['nocomment'] = true;
+ $s['item_nocomment'] = 1;
}
}
@@ -2249,10 +2276,15 @@ class Activity {
if (!array_key_exists('edited', $s))
$s['edited'] = $s['created'];
- $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name'));
- $s['summary'] = self::bb_content($content, 'summary');
+ $s['title'] = (($response_activity) ? EMPTY_STR : html2plain($content['name']));
+ $s['summary'] = (($content['summary'] !== $content['content']) ? html2plain($content['summary']) : '');
$s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content'));
+ // peertube quirks
+ if ($act->objprop('mediaType') === 'text/markdown') {
+ $s['body'] = markdown_to_bb($act->objprop('content'));
+ }
+
if ($act->objprop('quoteUrl')) {
$quote_bbcode = self::get_quote_bbcode($act->obj['quoteUrl']);
@@ -2284,6 +2316,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);
@@ -2374,7 +2416,8 @@ class Activity {
}
}
- $tag = (($poster) ? '[video poster=&quot;' . $poster . '&quot;]' : '[video]' );
+ $tag = (($poster) ? '[video poster=\'' . $poster . '\']' : '[video]' );
+
$ptr = null;
if ($act->objprop('url')) {
@@ -2589,6 +2632,7 @@ class Activity {
}
}
+
if (!$ap_rawmsg && array_key_exists('signed', $raw_arr)) {
// zap
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
@@ -2622,8 +2666,7 @@ class Activity {
return $hookinfo['s'];
}
-
- static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false) {
+ static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false, $is_collection_operation = false) {
$is_sys_channel = is_sys_channel($channel['channel_id']);
$is_child_node = false;
$parent = null;
@@ -2654,6 +2697,8 @@ class Activity {
}
$allowed = false;
+ $relay = false;
+
$permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel, $item));
if ($is_child_node) {
@@ -2680,13 +2725,22 @@ class Activity {
return;
}
+ $relay = $channel['channel_hash'] === $parent[0]['owner_xchan'];
+
+ if (str_contains($parent[0]['tgt_type'], 'Collection') && !$relay && !$is_collection_operation) {
+ logger('not a collection activity');
+ return;
+ }
+
if ($parent[0]['obj_type'] === 'Question') {
if (in_array($item['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $item['title'] && (!$item['body'])) {
$item['obj_type'] = 'Answer';
+ $item['item_hidden'] = 1;
}
}
if ($parent[0]['item_wall']) {
+
// set the owner to the owner of the parent
$item['owner_xchan'] = $parent[0]['owner_xchan'];
@@ -2867,6 +2921,13 @@ 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['contextHistory'])) {
+ IConfig::Set($item, 'activitypub', 'context', $act->obj['contextHistory'], 1);
+ }
+ elseif (!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)) {
@@ -2898,7 +2959,7 @@ class Activity {
if (intval($parent[0]['item_private']) === 0) {
if (intval($item['item_private'])) {
- $item['item_restrict'] = $item['item_restrict'] | 1;
+ $item['item_restrict'] = ((isset($item['item_restrict'])) ? $item['item_restrict'] | 1 : 1);
$item['allow_cid'] = '<' . $channel['channel_hash'] . '>';
$item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = '';
}
@@ -2915,7 +2976,7 @@ class Activity {
}
}
}
-
+/*
if (isset($item['term']) && !PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) {
foreach ($item['term'] as $t) {
if ($t['ttype'] === TERM_EMOJI) {
@@ -2929,6 +2990,7 @@ class Activity {
}
}
}
+*/
// TODO: not implemented
// self::rewrite_mentions($item);
@@ -2937,17 +2999,42 @@ class Activity {
dbesc($item['mid']),
intval($item['uid'])
);
+
if ($r) {
if ($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
- $x = item_store_update($item);
+ $x = item_store_update($item, deliver: false);
}
else {
return;
}
}
else {
- $x = item_store($item);
+ $x = item_store($item, deliver: false, addAndSync: false);
+ }
+
+ if ($x['success']) {
+ if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$is_collection_operation) {
+ $approval = Activity::addToCollection($channel, $act->data, $x['item']['parent_mid'], $x['item'], deliver: false);
+ }
+
+ if (check_item_source($channel['channel_id'], $x['item']) && in_array($x['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
+ event_addtocal($x['item_id'], $channel['channel_id']);
+ }
+
+ tag_deliver($channel['channel_id'], $x['item_id']);
+
+ if ($relay && $is_child_node) {
+ // We are the owner of this conversation, so send all received comments back downstream
+ Master::Summon(['Notifier', 'comment-import', $x['item_id']]);
+ if (!empty($approval['item_id'])) {
+ Master::Summon(['Notifier', 'comment-import', $approval['item_id']]);
+ }
+ }
+
+ send_status_notifications($x['item_id'], $x['item']);
+
+ sync_an_item($channel['channel_id'], $x['item_id']);
}
if ($fetch_parents && $parent && !intval($parent[0]['item_private'])) {
@@ -2974,28 +3061,6 @@ class Activity {
}
}
}
-
- if ($x['success']) {
-
- if (check_item_source($channel['channel_id'], $x['item']) && in_array($x['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
- event_addtocal($x['item_id'], $channel['channel_id']);
- }
-
- if ($is_child_node) {
- if ($item['owner_xchan'] === $channel['channel_hash']) {
- // We are the owner of this conversation, so send all received comments back downstream
- Master::Summon(['Notifier', 'comment-import', $x['item_id']]);
- }
- $r = q("select * from item where id = %d limit 1",
- intval($x['item_id'])
- );
- if ($r) {
- send_status_notifications($x['item_id'], $r[0]);
- }
- }
- sync_an_item($channel['channel_id'], $x['item_id']);
- }
-
}
/**
@@ -3285,10 +3350,10 @@ class Activity {
if (array_key_exists('startTime', $act) && strpos($act['startTime'], -1, 1) === 'Z') {
$adjust = true;
$event['adjust'] = 1;
- $event['dtstart'] = datetime_convert('UTC', 'UTC', $event['startTime'] . (($adjust) ? '' : 'Z'));
+ $event['dtstart'] = datetime_convert('UTC', 'UTC', $act['startTime'] . (($adjust) ? '' : 'Z'));
}
if (array_key_exists('endTime', $act)) {
- $event['dtend'] = datetime_convert('UTC', 'UTC', $event['endTime'] . (($adjust) ? '' : 'Z'));
+ $event['dtend'] = datetime_convert('UTC', 'UTC', $act['endTime'] . (($adjust) ? '' : 'Z'));
}
else {
$event['nofinish'] = true;
@@ -3574,6 +3639,8 @@ class Activity {
return [
'zot' => z_root() . '/apschema#',
+
+ 'contextHistory' => 'https://w3id.org/fep/171b/contextHistory',
'schema' => 'http://schema.org#',
'ostatus' => 'http://ostatus.org#',
'diaspora' => 'https://diasporafoundation.org/ns/',
@@ -3597,7 +3664,6 @@ class Activity {
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'Hashtag' => 'as:Hashtag'
-
];
}
@@ -3676,5 +3742,111 @@ 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))
+ ->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'])
+ ->setRestrict($sourceItem['item_restrict'])
+ ->setHidden($sourceItem['item_hidden'])
+ ->setDelayed($sourceItem['item_delayed'])
+ ->setUnpublished($sourceItem['item_unpublished'])
+ ->setBlocked($sourceItem['item_blocked'])
+ ->setType($sourceItem['item_type'])
+ ->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;
+ }
+
+
+ /**
+ * @brief Retrieves message ID from activity object.
+ * @param object $act Activity object
+ * @return string Message ID or empty string if not found
+ */
+ public static function getMessageID($act): string
+ {
+ if (ActivityStreams::is_response_activity($act->type) || $act->objprop('type') === 'Profile') {
+ return $act->id;
+ }
+
+ return $act->objprop('id', null)
+ ?? (is_string($act->obj) ? $act->obj : null)
+ ?? '';
+ }
+
+ /**
+ * @brief Retrieves the UUID from an activity object.
+ * @param object $act Activity object
+ * @return string UUID or empty string if not found
+ */
+ public static function getUUID($act): string
+ {
+ if (ActivityStreams::is_response_activity($act->type)) {
+ return $act->data['uuid']
+ ?? $act->data['diaspora:guid']
+ ?? '';
+ }
+
+ return $act->objprop('uuid', null)
+ ?? $act->objprop('diaspora:guid', null)
+ ?? '';
+ }
}
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
index 55a1de5dd..f2b9050e3 100644
--- a/Zotlabs/Lib/ActivityStreams.php
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -529,8 +529,8 @@ class ActivityStreams {
public function checkEddsaSignature() {
$signer = $this->get_property_obj('verificationMethod', $this->sig);
-
$parseUrl = parse_url($signer);
+ $publicKey = null;
if (isset($parseUrl['fragment'])) {
if (str_starts_with($parseUrl['fragment'], 'z6Mk')) {
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 0dc405ea9..337344645 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -341,7 +341,7 @@ class Apps {
'Suggest Channels' => t('Suggest Channels'),
'Login' => t('Login'),
'Channel Manager' => t('Channel Manager'),
- 'Network' => t('Stream'),
+ 'Network' => t('Network'),
'Settings' => t('Settings'),
'Files' => t('Files'),
'Webpages' => t('Webpages'),
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/Chatroom.php b/Zotlabs/Lib/Chatroom.php
index 34853b6ab..ee16d0002 100644
--- a/Zotlabs/Lib/Chatroom.php
+++ b/Zotlabs/Lib/Chatroom.php
@@ -181,7 +181,7 @@ class Chatroom {
}
- function leave($observer_xchan, $room_id, $client) {
+ public static function leave($observer_xchan, $room_id, $client) {
if(! $room_id || ! $observer_xchan)
return;
diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php
index b8e7a5c4e..9f6d077b4 100644
--- a/Zotlabs/Lib/Connect.php
+++ b/Zotlabs/Lib/Connect.php
@@ -24,10 +24,16 @@ class Connect {
$uid = $channel['channel_id'];
- if (strpos($url,'@') === false && strpos($url,'/') === false) {
+ // If we get just a channel name and it is not an URL turn it into a local webbie
+ if (!str_contains($url, '@') && strpos($url,'/') === false) {
$url = $url . '@' . App::get_hostname();
}
+ // Remove a possible leading @
+ if (str_starts_with($url, '@')) {
+ $url = ltrim($url, '@');
+ }
+
$result = [ 'success' => false, 'message' => '' ];
$my_perms = false;
diff --git a/Zotlabs/Lib/DB_Upgrade.php b/Zotlabs/Lib/DB_Upgrade.php
index 981c354a4..e11c2eb10 100644
--- a/Zotlabs/Lib/DB_Upgrade.php
+++ b/Zotlabs/Lib/DB_Upgrade.php
@@ -1,18 +1,35 @@
<?php
+/**
+ * A class to handle database schema upgrades.
+ *
+ * SPDX-FileCopyrightText: 2024 Hubzilla Community
+ * SPDX-FileContributor: Harald Eilertsen
+ *
+ * SPDX-License-Identifier: MIT
+ */
namespace Zotlabs\Lib;
use Zotlabs\Lib\Config;
+/**
+ * Upgrade the database schema if necessary.
+ *
+ * Compares the currently active database schema version with the version
+ * required for this version of Hubzilla, and performs the upgrade if needed.
+ *
+ * If the difference consists of more than one revision of the schema, each of
+ * the intermediate upgrades are performed in turn.
+ */
class DB_Upgrade {
- public $config_name = '';
- public $func_prefix = '';
-
- function __construct($db_revision) {
-
- $this->config_name = 'db_version';
- $this->func_prefix = '_';
+ /**
+ * Check the installed and required schema versions and perform the upgrade
+ * if necessary.
+ *
+ * @param int $db_version The required DB schema version.
+ */
+ public static function run(int $db_revision): void {
$build = Config::Get('system', 'db_version', 0);
if(! intval($build))
diff --git a/Zotlabs/Lib/DReport.php b/Zotlabs/Lib/DReport.php
index ac8e0d377..99bb05293 100644
--- a/Zotlabs/Lib/DReport.php
+++ b/Zotlabs/Lib/DReport.php
@@ -35,7 +35,7 @@ class DReport {
}
function addto_update($status) {
- $this->status = $this->status . ' ' . $status;
+ $this->status = $this->status . ', ' . $status;
}
@@ -89,8 +89,14 @@ class DReport {
if(array_key_exists('reject',$dr) && intval($dr['reject']))
return false;
- if(! ($dr['sender']))
+ if (!$dr['sender']) {
return false;
+ }
+
+ // do not store dismissed create activities
+ if ($dr['status'] === 'not a collection activity') {
+ return false;
+ }
// Is the sender one of our channels?
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 121ad9b09..6d5e249ef 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -95,8 +95,8 @@ class Enotify {
if (array_key_exists('verb', $params['item'])) {
// localize_item() alters the original item so make a copy first
$i = $params['item'];
- logger('calling localize');
- localize_item($i);
+ // logger('calling localize');
+ // localize_item($i);
$title = $i['title'];
$body = $i['body'];
$private = (($i['item_private']) || intval($i['item_obscured']));
@@ -131,9 +131,9 @@ class Enotify {
logger('notification: mail');
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
- $preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
+ $preamble = sprintf( t('%1$s sent you a new private message at %2$s'), $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
- $sitelink = t('Please visit %s to view and/or reply to your direct messages.');
+ $sitelink = t('Please visit %s to view and/or reply to your private messages.');
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/hq/' . gen_link_id($params['item']['mid']) . '">' . $sitename . '</a>');
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
@@ -146,7 +146,7 @@ class Enotify {
$itemlink = $params['link'];
- $action = (($moderated) ? t('requested to comment on') : t('commented on'));
+ $action = (($moderated) ? t('requested to post in') : t('posted in'));
if(array_key_exists('item',$params)) {
@@ -164,8 +164,8 @@ class Enotify {
if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE]))
$action = (($moderated) ? t('requested to dislike') : t('disliked'));
- if(activity_match($params['verb'], ACTIVITY_SHARE))
- $action = t('repeated');
+ if(activity_match($params['verb'], [ACTIVITY_SHARE]))
+ $action = (($moderated) ? t('requested to repeat') : t('repeated'));
}
@@ -213,28 +213,36 @@ class Enotify {
//$possess_desc = str_replace('<!item_type!>',$possess_desc);
// "a post"
- $dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
+ $dest_str = sprintf(
+ t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
$action,
$itemlink,
- $item_post_type);
+ $item_post_type
+ );
// "George Bull's post"
- if($p)
- $dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
+ if($p) {
+ $dest_str = sprintf(
+ t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
$action,
$itemlink,
- $p[0]['author']['xchan_name'],
- $item_post_type);
+ $parent_item['author']['xchan_name'],
+ $item_post_type
+ );
+ }
// "your post"
- if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
- $dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
+ if ($parent_item['owner']['xchan_hash'] === $recip['channel_hash'] && intval($parent_item['item_wall'])) {
+ $dest_str = sprintf(
+ t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
$action,
$itemlink,
- $item_post_type);
+ $item_post_type
+ );
+ }
// Some mail softwares relies on subject field for threading.
// So, we cannot have different subjects for notifications of the same thread.
@@ -263,7 +271,7 @@ class Enotify {
$itemlink = $params['link'];
- if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
+ if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce']))) {
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
logger('notification: not a visible activity. Ignoring.');
pop_lang();
@@ -308,7 +316,6 @@ class Enotify {
$item_post_type = item_post_type($p[0]);
// $private = $p[0]['item_private'];
$parent_id = $p[0]['id'];
-
$parent_item = $p[0];
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
@@ -320,14 +327,18 @@ class Enotify {
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
+ if(activity_match($params['item']['verb'], [ACTIVITY_SHARE]))
+ $verb = (($moderated) ? t('requested to repeat') : t('repeated'));
+
// "your post"
- if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
+ if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
$verb,
$itemlink,
$item_post_type
);
+ }
else {
pop_lang();
return;
@@ -406,6 +417,7 @@ class Enotify {
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSHARE) {
+ $itemlink = $params['link'];
$subject = sprintf( t('[$Projectname:Notify] %s tagged your post') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s tagged your post at %2$s'),$sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s tagged [zrl=%2$s]your post[/zrl]') ,
@@ -415,7 +427,6 @@ class Enotify {
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
- $itemlink = $params['link'];
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_INTRO) {
@@ -433,6 +444,7 @@ class Enotify {
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_SUGGEST) {
+ $itemlink = $params['link'];
$subject = sprintf( t('[$Projectname:Notify] Friend suggestion received'));
$preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a friend suggestion[/zrl] for %2$s from %3$s.'),
@@ -447,7 +459,6 @@ class Enotify {
$sitelink = t('Please visit %s to approve or reject the suggestion.');
$tsitelink = sprintf( $sitelink, $siteurl );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
- $itemlink = $params['link'];
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
@@ -500,9 +511,14 @@ class Enotify {
*/
+ $hash = ((in_array($params['verb'], ['Create', 'Update'])) ? $params['item']['uuid'] : $params['item']['thr_parent_uuid']);
+
+ if (!$hash) {
+ $hash = new_uuid();
+ }
$datarray = [];
- $datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
+ $datarray['hash'] = $hash;
$datarray['sender_hash'] = $sender['xchan_hash'];
$datarray['xname'] = $sender['xchan_name'];
$datarray['url'] = $sender['xchan_url'];
@@ -561,8 +577,9 @@ class Enotify {
dbesc($datarray['otype'])
);
- $r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
+ $r = q("select id from notify where hash = '%s' and link = '%s' and ntype = %d and uid = %d limit 1",
dbesc($datarray['hash']),
+ dbesc($itemlink),
intval($datarray['ntype']),
intval($recip['channel_id'])
);
@@ -595,7 +612,7 @@ class Enotify {
// send email notification if notification preferences permit
- require_once('bbcode.php');
+ require_once('include/bbcode.php');
if ((intval($recip['channel_notifyflags']) & intval($params['type'])) || $params['type'] == NOTIFY_SYSTEM) {
logger('notification: sending notification email');
@@ -840,8 +857,8 @@ class Enotify {
}
else {
$itemem_text = (($item['item_thread_top'])
- ? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
- : (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
+ ? (($item['obj_type'] === 'Question') ? t('started a poll') : t('started a conversation'))
+ : (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('posted in %s\'s conversation'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
);
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
@@ -853,12 +870,7 @@ class Enotify {
if($item['edited'] > $item['created']) {
$edit = true;
- if($item['item_thread_top']) {
- $itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
- }
- else {
- $itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
- }
+ $itemem_text = sprintf( t('edited a message dated %s'), relative_date($item['created']));
}
@@ -878,7 +890,7 @@ class Enotify {
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
- 'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
+ 'b64mid' => ((in_array($item['verb'] , ['Like', 'Dislike', 'Announce']) && !empty($item['thr_parent_uuid'])) ? $item['thr_parent_uuid'] : $item['uuid'] ?? ''),
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => bbcode(escape_tags($itemem_text)),
@@ -898,14 +910,13 @@ class Enotify {
}
static public function format_notify($tt) {
-
$message = trim(strip_tags(bbcode($tt['msg'])));
if(strpos($message, $tt['xname']) === 0)
$message = substr($message, strlen($tt['xname']) + 1);
$x = [
- 'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
+ 'notify_link' => (($tt['ntype'] === NOTIFY_INTRO) ? z_root() . '/notify/view/' . $tt['id'] : $tt['link']),
'name' => $tt['xname'],
'url' => $tt['url'],
'photo' => $tt['photo'],
@@ -917,11 +928,9 @@ class Enotify {
];
return $x;
-
}
static public function format_intros($rr) {
-
return [
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
'name' => $rr['xchan_name'],
diff --git a/Zotlabs/Lib/IConfig.php b/Zotlabs/Lib/IConfig.php
index 74c1107f0..3540c2b24 100644
--- a/Zotlabs/Lib/IConfig.php
+++ b/Zotlabs/Lib/IConfig.php
@@ -13,6 +13,7 @@ class IConfig {
static public function Get(&$item, $family, $key, $default = false) {
$is_item = false;
+ $iid = null;
if(is_array($item)) {
$is_item = true;
@@ -27,12 +28,13 @@ class IConfig {
elseif(intval($item))
$iid = $item;
- if(! $iid)
+ if (!$iid)
return $default;
+
if(is_array($item) && array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
foreach($item['iconfig'] as $c) {
- if($c['iid'] == $iid && $c['cat'] == $family && $c['k'] == $key)
+ if (isset($c['iid']) && $c['iid'] == $iid && isset($c['cat']) && $c['cat'] == $family && isset($c['k']) && $c['k'] == $key)
return $c['v'];
}
}
diff --git a/Zotlabs/Lib/JcsEddsa2022.php b/Zotlabs/Lib/JcsEddsa2022.php
index 14f16c94b..c56f093af 100644
--- a/Zotlabs/Lib/JcsEddsa2022.php
+++ b/Zotlabs/Lib/JcsEddsa2022.php
@@ -7,11 +7,28 @@ use StephenHill\Base58;
class JcsEddsa2022 {
- public function __construct() {
- return $this;
- }
-
+ /**
+ * Sign arbitrary data with the keys of the provided channel.
+ *
+ * @param $data The data to be signed.
+ * @param array $channel A channel as an array of key/value pairs.
+ *
+ * @return An array with the following fields:
+ * - `type`: The type of signature, always `DataIntegrityProof`.
+ * - `cryptosuite`: The cryptographic algorithm used, always `eddsa-jcs-2022`.
+ * - `created`: The UTC date and timestamp when the signature was created.
+ * - `verificationMethod`: The channel URL and the public key separated by a `#`.
+ * - `proofPurpose`: The purpose of the signature, always `assertionMethod`.
+ * - `proofValue`: The signature itself.
+ *
+ * @throws JcsEddsa2022SignatureException if the channel is missing, or
+ * don't have valid keys.
+ */
public function sign($data, $channel): array {
+ if (!is_array($channel) || !isset($channel['channel_epubkey'], $channel['channel_eprvkey'])) {
+ throw new JcsEddsa2022SignException('Invalid or missing channel provided.');
+ }
+
$base58 = new Base58();
$pubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
$options = [
diff --git a/Zotlabs/Lib/JcsEddsa2022SignException.php b/Zotlabs/Lib/JcsEddsa2022SignException.php
new file mode 100644
index 000000000..81d02d631
--- /dev/null
+++ b/Zotlabs/Lib/JcsEddsa2022SignException.php
@@ -0,0 +1,15 @@
+<?php
+/*
+ * SPDX-FileCopyrightText: 2025 The Hubzilla Community
+ * SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+namespace Zotlabs\Lib;
+
+use Exception;
+
+class JcsEddsa2022SignException extends Exception
+{
+}
diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php
index a7e33ba6b..c6b149738 100644
--- a/Zotlabs/Lib/Libsync.php
+++ b/Zotlabs/Lib/Libsync.php
@@ -885,7 +885,7 @@ class Libsync {
dbesc($t)
);
- q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s'",
+ q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s' and hubloc_network = 'zot6'",
dbesc($r[0]['hubloc_url']),
dbesc($r[0]['hubloc_sitekey'])
);
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index bc944c97c..d2d696356 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -655,6 +655,11 @@ class Libzot {
return $ret;
}
+ if (empty($arr['primary_location']['address'])) {
+ logger('Empty primary location address: ' . print_r($arr, true), LOGGER_DEBUG);
+ return $ret;
+ }
+
/**
* @hooks import_xchan
* Called when processing the result of zot_finger() to store the result
@@ -1134,6 +1139,7 @@ class Libzot {
}
$message_request = false;
+ $is_collection_operation = false;
$has_data = array_key_exists('data', $env) && $env['data'];
@@ -1141,15 +1147,33 @@ 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 data 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('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']);
}
+
if (is_array($AS->obj)) {
$item = Activity::decode_note($AS);
+
if (!$item) {
logger('Could not decode activity: ' . print_r($AS, true));
return;
@@ -1158,6 +1182,12 @@ class Libzot {
else {
$item = [];
}
+
+ if (!$AS->is_valid()) {
+ logger('Activity rejected: ' . print_r($data, true));
+ return;
+ }
+
logger($AS->debug(), LOGGER_DATA);
}
@@ -1198,7 +1228,6 @@ class Libzot {
logger('public post');
-
// Public post. look for any site members who are or may be accepting posts from this sender
// and who are allowed to see them based on the sender's permissions
// @fixme;
@@ -1265,25 +1294,6 @@ class Libzot {
$item['item_private'] = 1;
}
- if ($item['mid'] === $item['parent_mid']) {
- if (is_array($AS->obj) && array_key_exists('commentPolicy', $AS->obj)) {
- $p = strstr($AS->obj['commentPolicy'], 'until=');
- if ($p !== false) {
- $comments_closed_at = datetime_convert('UTC', 'UTC', substr($p, 6));
- if ($comments_closed_at === $item['created']) {
- $item['item_nocomment'] = 1;
- }
- else {
- $item['comments_closed'] = $comments_closed_at;
- $aritemr['comment_policy'] = trim(str_replace($p, '', $AS->obj['commentPolicy']));
- }
- }
- else {
- $item['comment_policy'] = $AS->obj['commentPolicy'];
- }
- }
- }
-
if (!empty($AS->meta['hubloc']) || $AS->sigok) {
$item['item_verified'] = true;
}
@@ -1301,7 +1311,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']);
}
@@ -1517,7 +1527,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
@@ -1532,6 +1542,7 @@ class Libzot {
$local_public = $public;
$item_result = null;
+ $parent = null;
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
@@ -1545,6 +1556,14 @@ class Libzot {
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
+ $conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
+
+ if (isset($arr['tgt_type']) && 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.
@@ -1578,6 +1597,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();
@@ -1624,22 +1645,24 @@ class Libzot {
if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) {
$local_public = true;
- $r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1",
- dbesc($sender)
- );
- // don't import sys channel posts from selfcensored authors
- if ($r && (intval($r[0]['xchan_selfcensored']))) {
+ $incl = Config::Get('system','pubstream_incl');
+ $excl = Config::Get('system','pubstream_excl');
+
+ if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) {
$local_public = false;
continue;
}
- $incl = Config::Get('system','pubstream_incl');
- $excl = Config::Get('system','pubstream_excl');
+ $r = q("select xchan_selfcensored, xchan_censored from xchan where xchan_hash = '%s'",
+ dbesc($sender)
+ );
- if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) {
+ // don't import sys channel posts from selfcensored or censored authors
+ if ($r && ($r[0]['xchan_selfcensored'] || $r[0]['xchan_censored'])) {
$local_public = false;
continue;
}
+
}
$tag_delivery = tgroup_check($channel['channel_id'], $arr);
@@ -1701,6 +1724,7 @@ class Libzot {
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
if (in_array($arr['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $arr['title'] && (!$arr['body'])) {
$arr['obj_type'] = 'Answer';
+ $arr['item_hidden'] = 1;
}
}
@@ -1826,11 +1850,12 @@ class Libzot {
dbesc($arr['author_xchan'])
);
- // reactions such as like and dislike could have an mid with /activity/ in it.
+ // 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",
+
+ $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'])),
+ dbesc(reverse_activity_mid($arr['mid'])),
intval($channel['channel_id'])
);
@@ -1859,21 +1884,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);
@@ -1902,10 +1935,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']);
}
@@ -1948,14 +1986,18 @@ class Libzot {
if ((is_array($stored)) && ($stored['id'] != $stored['parent'])
&& ($stored['author_xchan'] === $channel['channel_hash'])) {
- retain_item($stored['item']['parent']);
+ retain_item($stored['parent']);
}
- if ($relay && $item_id && $stored['item_blocked'] !== ITEM_MODERATED) {
+ if ($relay && $item_id && item_forwardable($stored)) {
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();
+ $result = [$DR->get()];
}
}
@@ -2006,6 +2048,7 @@ class Libzot {
foreach ($items as $activity) {
$AS = new ActivityStreams($activity);
+
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)
@@ -2014,6 +2057,30 @@ 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('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']);
+
+ // 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;
@@ -2207,7 +2274,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
@@ -2323,21 +2390,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/Mailer.php b/Zotlabs/Lib/Mailer.php
new file mode 100644
index 000000000..ca2d84d0d
--- /dev/null
+++ b/Zotlabs/Lib/Mailer.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Mailer class for sending emails from Hubzilla.
+ *
+ * SPDX-FileCopyrightText: 2024 Hubzilla Community
+ * SPDX-FileContributor: Harald Eilertsen
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+namespace Zotlabs\Lib;
+
+use App;
+
+/**
+ * A class for sending emails.
+ *
+ * Based on the previous `z_mail` function, but adaped and made more
+ * robust and usable as a class.
+ */
+class Mailer {
+
+ public function __construct(private array $params = []) {
+ }
+
+ public function deliver(): bool {
+
+ if(empty($this->params['fromEmail'])) {
+ $this->params['fromEmail'] = Config::Get('system','from_email');
+ if(empty($this->params['fromEmail'])) {
+ $this->params['fromEmail'] = 'Administrator@' . App::get_hostname();
+ }
+ }
+
+ if(empty($this->params['fromName'])) {
+ $this->params['fromName'] = Config::Get('system','from_email_name');
+ if(empty($this->params['fromName'])) {
+ $this->params['fromName'] = System::get_site_name();
+ }
+ }
+
+ if(empty($this->params['replyTo'])) {
+ $this->params['replyTo'] = Config::Get('system','reply_address');
+ if(empty($this->params['replyTo'])) {
+ $this->params['replyTo'] = 'noreply@' . App::get_hostname();
+ }
+ }
+
+ if (!isset($this->params['additionalMailHeader'])) {
+ $this->params['additionalMailHeader'] = '';
+ }
+
+ $this->params['sent'] = false;
+ $this->params['result'] = false;
+
+ /**
+ * @hooks email_send
+ * * \e params @see z_mail()
+ */
+ call_hooks('email_send', $this->params);
+
+ if($this->params['sent']) {
+ logger('notification: z_mail returns ' . (($this->params['result']) ? 'success' : 'failure'), LOGGER_DEBUG);
+ return $this->params['result'];
+ }
+
+ $fromName = email_header_encode(html_entity_decode($this->params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
+ $messageSubject = email_header_encode(html_entity_decode($this->params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
+
+ $messageHeader =
+ $this->params['additionalMailHeader'] .
+ "From: $fromName <{$this->params['fromEmail']}>" . PHP_EOL .
+ "Reply-To: $fromName <{$this->params['replyTo']}>" . PHP_EOL .
+ "Content-Type: text/plain; charset=UTF-8";
+
+ // send the message
+ $res = mail(
+ $this->params['toEmail'], // send to address
+ $messageSubject, // subject
+ $this->params['textVersion'],
+ $messageHeader // message headers
+ );
+ logger('notification: z_mail returns ' . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
+ return $res;
+ }
+}
diff --git a/Zotlabs/Lib/MessageFilter.php b/Zotlabs/Lib/MessageFilter.php
index e7382c0d5..3f2db88c3 100644
--- a/Zotlabs/Lib/MessageFilter.php
+++ b/Zotlabs/Lib/MessageFilter.php
@@ -8,17 +8,18 @@ class MessageFilter {
public static function evaluate($item, $incl, $excl) {
- $text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
- $text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
+ $text = prepare_text($item['body'], ((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
+ $text = html2plain((!empty($item['title'])) ? $item['title'] . ' ' . $text : $text);
$lang = null;
-
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
$lang = detect_language($text);
}
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
+ $until = null;
+
// exclude always has priority
$exclude = (($excl) ? explode("\n", $excl) : null);
@@ -41,7 +42,13 @@ class MessageFilter {
return false;
}
}
- elseif (substr($word, 0, 1) === '#' && $tags) {
+ elseif (str_starts_with($word, 'until=')) {
+ $until = strtotime(trim(substr($word, 6)));
+ if ($until > strtotime($item['created'] . ' UTC')) {
+ return false;
+ }
+ }
+ elseif (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
@@ -89,7 +96,13 @@ class MessageFilter {
return true;
}
}
- elseif (substr($word, 0, 1) === '#' && $tags) {
+ elseif (str_starts_with($word, 'until=')) {
+ $until = strtotime(trim(substr($word, 6)));
+ if ($until > strtotime($item['created'] . ' UTC')) {
+ return true;
+ }
+ }
+ elseif (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
@@ -124,9 +137,7 @@ class MessageFilter {
/**
- * @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
- *
- * This is extensible. The first version of variable testing supports tests of the forms:
+ * Evaluate a conditional expression with support for AND (&&) and OR (||) operators.
*
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
* - ?foo == baz which will check if item.foo is the string 'baz';
@@ -143,103 +154,110 @@ class MessageFilter {
*
* The values 0, '', an empty array, and an unset value will all evaluate to false.
*
- * @param string $s
- * @param array $item
- * @return bool
+ * @param string $s The condition string to evaluate.
+ * @param array $item The associative array providing variable values.
+ * @return bool True if the condition is met, false otherwise.
*/
- public static function test_condition($s,$item) {
+ public static function test_condition($s, $item) {
+ $s = trim($s);
- if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if (stripos($x, trim($matches[2])) !== false) {
- return true;
+ // Handle OR (||)
+ // Split on '||' not inside quotes
+ $or_parts = preg_split('/\s*\|\|\s*/', $s);
+ if (count($or_parts) > 1) {
+ foreach ($or_parts as $part) {
+ if (self::test_condition(ltrim($part, '?+'), $item)) {
+ return true;
+ }
}
return false;
}
- if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x == trim($matches[2])) {
- return true;
+ // Handle AND (&&)
+ // Split on '&&' not inside quotes
+ $and_parts = preg_split('/\s*\&\&\s*/', $s);
+ if (count($and_parts) > 1) {
+ foreach ($and_parts as $part) {
+ if (!self::test_condition(ltrim($part, '?+'), $item)) {
+ return false;
+ }
}
- return false;
+ return true;
+ }
+
+ // Basic checks
+
+ // Contains substring (case-insensitive)
+ if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return (stripos($x, trim($matches[2])) !== false);
+ }
+
+ // Equality
+ if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x == trim($matches[2]));
}
+ // Inequality
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x != trim($matches[2])) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x != trim($matches[2]));
}
+ // Greater than or equal
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x >= trim($matches[2])) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x >= trim($matches[2]));
}
+ // Less than or equal
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x <= trim($matches[2])) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x <= trim($matches[2]));
}
+ // Greater than
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x > trim($matches[2])) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x > trim($matches[2]));
}
- if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x < trim($matches[2])) {
- return true;
- }
- return false;
+ // Less than
+ if (preg_match('/(.*?)\s\<\s(.*?)$/', $s, $matches)) {
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return ($x < trim($matches[2]));
}
- if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if (is_array($x) && in_array(trim($matches[2]), $x)) {
- return true;
- }
- return false;
+ // Array contains value
+ if (preg_match('/(.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return (is_array($x) && in_array(trim($matches[2]), $x));
}
+ // Array contains key
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return (is_array($x) && array_key_exists(trim($matches[2]), $x));
}
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
+ // Falsy check
if (preg_match('/\!(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if (!$x) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return !$x;
}
+ // Truthy check (default)
if (preg_match('/(.*?)$/', $s, $matches)) {
- $x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
- if ($x) {
- return true;
- }
- return false;
+ $x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
+ return (bool)$x;
}
+ // If no conditions matched, return false
return false;
}
+
}
diff --git a/Zotlabs/Lib/SuperCurl.php b/Zotlabs/Lib/SuperCurl.php
deleted file mode 100644
index 462a62b36..000000000
--- a/Zotlabs/Lib/SuperCurl.php
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-
-namespace Zotlabs\Lib;
-
-/**
- * @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
- * these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
- * and set lots of CURL options (many of which stay the same from one call to the next).
- */
-
-
-
-
-class SuperCurl {
-
-
- private $auth;
- private $url;
-
- private $curlopt = array();
-
- private $headers = null;
- public $filepos = 0;
- public $filehandle = 0;
- public $request_data = '';
-
- private $request_method = 'GET';
- private $upload = false;
- private $cookies = false;
-
-
- private function set_data($s) {
- $this->request_data = $s;
- $this->filepos = 0;
- }
-
- public function curl_read($ch,$fh,$size) {
-
- if($this->filepos < 0) {
- unset($fh);
- return '';
- }
-
- $s = substr($this->request_data,$this->filepos,$size);
-
- if(strlen($s) < $size)
- $this->filepos = (-1);
- else
- $this->filepos = $this->filepos + $size;
-
- return $s;
- }
-
-
- public function __construct($opts = array()) {
- $this->set($opts);
- }
-
- private function set($opts = array()) {
- if($opts) {
- foreach($opts as $k => $v) {
- switch($k) {
- case 'http_auth':
- $this->auth = $v;
- break;
- case 'magicauth':
- // currently experimental
- $this->magicauth = $v;
- \Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
- break;
- case 'custom':
- $this->request_method = $v;
- break;
- case 'url':
- $this->url = $v;
- break;
- case 'data':
- $this->set_data($v);
- if($v) {
- $this->upload = true;
- }
- else {
- $this->upload = false;
- }
- break;
- case 'headers':
- $this->headers = $v;
- break;
- default:
- $this->curlopts[$k] = $v;
- break;
- }
- }
- }
- }
-
- function exec() {
- $opts = $this->curlopts;
- $url = $this->url;
- if($this->auth)
- $opts['http_auth'] = $this->auth;
- if($this->magicauth) {
- $opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
- $opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
- $opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
- $c = channelx_by_n($this->magicauth);
- if($c)
- $url = zid($this->url,channel_reddress($c));
- }
- if($this->custom)
- $opts['custom'] = $this->custom;
- if($this->headers)
- $opts['headers'] = $this->headers;
- if($this->upload) {
- $opts['upload'] = true;
- $opts['infile'] = $this->filehandle;
- $opts['infilesize'] = strlen($this->request_data);
- $opts['readfunc'] = [ $this, 'curl_read' ] ;
- }
-
- $recurse = 0;
- return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
-
- }
-
-
-}
diff --git a/Zotlabs/Lib/Text.php b/Zotlabs/Lib/Text.php
index f593f9dd6..4a962670a 100644
--- a/Zotlabs/Lib/Text.php
+++ b/Zotlabs/Lib/Text.php
@@ -21,4 +21,13 @@ class Text {
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
}
+ public static function rawurlencode_parts(string $string): string {
+ if (!$string) {
+ return EMPTY_STR;
+ }
+
+ return implode('/', array_map('rawurlencode', explode('/', $string)));
+ }
+
+
}
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 60a314da0..46fe6d815 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -4,8 +4,6 @@ namespace Zotlabs\Lib;
use App;
use Zotlabs\Access\AccessList;
-use Zotlabs\Lib\Apps;
-use Zotlabs\Lib\Config;
require_once('include/text.php');
@@ -26,6 +24,7 @@ class ThreadItem {
private $parent = null;
private $conversation = null;
private $redirect_url = null;
+ private $owner_addr = '';
private $owner_url = '';
private $owner_photo = '';
private $owner_name = '';
@@ -35,14 +34,12 @@ class ThreadItem {
private $channel = null;
private $display_mode = 'normal';
private $reload = '';
- private $mid_uuid_map = [];
-
public function __construct($data) {
$this->data = $data;
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
- $this->threaded = Config::Get('system','thread_allow');
+ $this->threaded = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
// Prepare the children
if(isset($data['children'])) {
@@ -65,8 +62,6 @@ class ThreadItem {
unset($this->data['children']);
}
-
-
// allow a site to configure the order and content of the reaction emoji list
if($this->toplevel) {
$x = Config::Get('system','reactions');
@@ -84,7 +79,7 @@ class ThreadItem {
* _ false on failure
*/
- public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) {
+ public function get_template_data($thread_level=1, $conv_flags = []) {
$result = [];
$item = $this->get_data();
@@ -103,6 +98,8 @@ class ThreadItem {
$conv = $this->get_conversation();
$observer = $conv->get_observer();
+ $conv->mid_uuid_map[$item['mid']] = $item['uuid'];
+
$acl = new AccessList([]);
$acl->set($item);
@@ -114,7 +111,7 @@ class ThreadItem {
$locktype = intval($item['item_private']);
if ($locktype === 2) {
- $lock = t('Direct message');
+ $lock = t('Private message');
}
// 0 = limited based on public policy
@@ -187,7 +184,7 @@ class ThreadItem {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
}
- $filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
+ $filer = (((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) ? t("Save to Folder") : false);
$profile_avatar = $item['author']['xchan_photo_s'];
$profile_link = chanlink_hash($item['author_xchan']);
@@ -209,9 +206,9 @@ class ThreadItem {
}
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
- $response_verbs[] = 'attendyes';
- $response_verbs[] = 'attendno';
- $response_verbs[] = 'attendmaybe';
+ $response_verbs[] = 'accept';
+ $response_verbs[] = 'reject';
+ $response_verbs[] = 'tentativeaccept';
if($this->is_commentable() && $observer) {
$isevent = true;
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
@@ -222,56 +219,8 @@ class ThreadItem {
$response_verbs[] = 'answer';
}
- if (!feature_enabled($conv->get_profile_owner(),'dislike')) {
- unset($conv_responses['dislike']);
- }
-
- $responses = get_responses($conv_responses,$response_verbs,$this,$item);
-
- $my_responses = [];
- foreach($response_verbs as $v) {
- $my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
- }
-
-/*
-
- $like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
- $like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
- if (($like_list) && (count($like_list) > MAX_LIKERS)) {
- $like_list_part = array_slice($like_list, 0, MAX_LIKERS);
- array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
- } else {
- $like_list_part = '';
- }
- $like_button_label = tt('Like','Likes',$like_count,'noun');
-
- $repeat_count = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid']] : '');
- $repeat_list = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid'] . '-l'] : '');
- if (($repeat_list) && (count($repeat_list) > MAX_LIKERS)) {
- $repeat_list_part = array_slice($repeat_list, 0, MAX_LIKERS);
- array_push($repeat_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#repeatModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
- } else {
- $repeat_list_part = '';
- }
- $repeat_button_label = tt('Repeat','Repeats',$repeat_count,'noun');
-
- $showdislike = '';
- if (feature_enabled($conv->get_profile_owner(),'dislike')) {
- $dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
- $dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
- $dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
- if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
- $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
- array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
- } else {
- $dislike_list_part = '';
- }
-
- $showdislike = ((x($conv_responses['dislike'],$item['mid'])) ? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
- }
-
- $showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
-*/
+ $response_verbs[] = 'comment';
+ $responses = get_responses($response_verbs, $item);
/*
* We should avoid doing this all the time, but it depends on the conversation mode
@@ -281,7 +230,13 @@ class ThreadItem {
$this->check_wall_to_wall();
+ $children = $this->get_children();
+ $children_count = count($children);
+
if($this->is_toplevel()) {
+ $conv->comments_total = $responses['comment']['count'] ?? 0;
+ $conv->comments_loaded = $children_count;
+
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
$star = [
'toggle' => t("Toggle Star Status"),
@@ -293,7 +248,6 @@ class ThreadItem {
$is_comment = true;
}
-
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
$forged = ((($item['sig']) && (! intval($item['item_verified']))) ? t('Message signature incorrect') : '');
$unverified = '' ; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : '');
@@ -326,15 +280,11 @@ class ThreadItem {
if((in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) && $conv->get_profile_owner() == local_channel())
$has_event = true;
- $like = [];
- $dislike = [];
$reply_to = [];
$reactions_allowed = false;
if($this->is_commentable() && $observer) {
- $like = array( t("I like this \x28toggle\x29"), t("like"));
- $dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
- $reply_to = array( t("Reply to this comment"), t("reply"), t("Reply to"));
+ $reply_to = array( t("Reply to this message"), t("reply"), t("Reply to"));
$reactions_allowed = true;
}
@@ -378,9 +328,8 @@ class ThreadItem {
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
$comment_count_txt = ['label' => sprintf(tt('%d comment', '%d comments', $total_children), $total_children), 'count' => $total_children];
- $list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
- $children = $this->get_children();
+ $list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
$has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false);
@@ -390,14 +339,7 @@ class ThreadItem {
$midb64 = $item['uuid'];
$mids = [ $item['uuid'] ];
- $response_mids = [];
- foreach($response_verbs as $v) {
- if(isset($conv_responses[$v]['mids'][$item['mid']])) {
- $response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
- }
- }
- $mids = array_merge($mids, $response_mids);
$json_mids = json_encode($mids);
// Pinned item processing
@@ -411,11 +353,26 @@ class ThreadItem {
$contact = App::$contacts[$item['author_xchan']];
}
+ $blog_mode = $this->get_display_mode() === 'list';
+ $load_more = false;
+ $load_more_title = '';
+ $comments_total_percent = 0;
+ if (($conv->comments_total > $conv->comments_loaded) || ($blog_mode && $conv->comments_total > 3)) {
+ // provide a load more comments button
+ $load_more = true;
+ $load_more_title = sprintf(t('Load the next few of total %d comments'), $conv->comments_total);
+ $comments_total_percent = round(100 * 3 / $conv->comments_total);
+ }
+
+ $expand = '';
+ if ($this->threaded && !empty($item['comment_count'] && !$this->is_toplevel())) {
+ $expand = t('Expand Replies');
+ }
+
$tmp_item = array(
'template' => $this->get_template(),
'mode' => $mode,
'item_type' => intval($item['item_type']),
- //'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
'categories' => $body['categories'],
@@ -424,9 +381,9 @@ class ThreadItem {
'folders' => $body['folders'],
'text' => strip_tags($body['html']),
'id' => $this->get_id(),
+ 'parent' => $item['parent'],
'mid' => $midb64,
'mids' => $json_mids,
- 'parent' => $item['parent'],
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
'isevent' => $isevent,
@@ -450,16 +407,15 @@ class ThreadItem {
'sparkle' => $sparkle,
'title' => $item['title'],
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
- //'ago' => relative_date($item['created']),
'app' => $item['app'],
'str_app' => sprintf( t('from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
- 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
- 'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
- 'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
+ 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created']),
+ 'editedtime' => (($item['edited'] != $item['created']) ? sprintf(t('Last edited %s'), relative_time($item['edited'])) : ''),
+ 'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf(t('Expires %s'), relative_time($item['expires'])) : ''),
'lock' => $lock,
'locktype' => $locktype,
- 'delayed' => $item['item_delayed'],
+ 'delayed' => (($item['item_delayed']) ? sprintf(t('Published %s'), relative_time($item['created'])) : ''),
'privacy_warning' => $privacy_warning,
'verified' => $verified,
'unverified' => $unverified,
@@ -472,6 +428,7 @@ class ThreadItem {
'vote_title' => t('Voting Options'),
'is_comment' => $is_comment,
'is_new' => $is_new,
+ 'owner_addr' => $this->get_owner_addr(),
'owner_url' => $this->get_owner_url(),
'owner_photo' => $this->get_owner_photo(),
'owner_name' => $this->get_owner_name(),
@@ -479,17 +436,16 @@ class ThreadItem {
'event' => $body['event'],
'has_tags' => $has_tags,
'reactions' => $this->reactions,
-// Item toolbar buttons
+ // Item toolbar buttons
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
- 'like' => $like,
- 'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
- 'reply_to' => (((! $this->is_toplevel()) && feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
+ 'reply_to' => ((feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
'top_hint' => t("Go to previous comment"),
'share' => $share,
'embed' => $embed,
'rawmid' => $item['mid'],
+ 'parent_mid' => $item['parent_mid'],
'plink' => get_plink($item),
- 'edpost' => $edpost, // ((feature_enabled($conv->get_profile_owner(),'edit_posts')) ? $edpost : ''),
+ 'edpost' => $edpost,
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
@@ -500,51 +456,50 @@ class ThreadItem {
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'drop' => $drop,
'dropdown_extras' => $dropdown_extras,
-// end toolbar buttons
+ // end toolbar buttons
'unseen_comments' => $unseen_comments,
'comment_count' => $total_children,
'comment_count_txt' => $comment_count_txt,
'list_unseen_txt' => $list_unseen_txt,
'markseen' => t('Mark all comments seen'),
'responses' => $responses,
- 'my_responses' => $my_responses,
- /*
- 'like_count' => $like_count,
- 'like_list' => $like_list,
- 'like_list_part' => $like_list_part,
- 'like_button_label' => $like_button_label,
- 'like_modal_title' => t('Likes','noun'),
-
- 'repeat_count' => $repeat_count,
- 'repeat_list' => $repeat_list,
- 'repeat_list_part' => $repeat_list_part,
- 'repeat_button_label' => $repeat_button_label,
- 'repeat_modal_title' => t('Repeats','noun'),
-
-
- 'dislike_modal_title' => t('Dislikes','noun'),
- 'dislike_count' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''),
- 'dislike_list' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''),
- 'dislike_list_part' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''),
- 'dislike_button_label' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''),
-*/
+ // 'my_responses' => $my_responses,
'modal_dismiss' => t('Close'),
- // 'showlike' => $showlike,
- // 'showdislike' => $showdislike,
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
+ 'comment_hidden' => feature_enabled($conv->get_profile_owner(),'reply_to'),
+ 'no_comment' => (($item['item_thread_top'] && $item['item_nocomment'])? t('Comments disabled') : ''),
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'thread_level' => $thread_level,
'settings' => $settings,
- 'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $mid_uuid_map[$item['thr_parent']] : ''),
+ 'thr_parent_uuid' => (($item['parent_mid'] !== $item['thr_parent'] && isset($conv->mid_uuid_map[$item['thr_parent']])) ? $conv->mid_uuid_map[$item['thr_parent']] : ''),
'contact_id' => (($contact) ? $contact['abook_id'] : ''),
'moderate' => ($item['item_blocked'] == ITEM_MODERATED),
'moderate_approve' => t('Approve'),
'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'),
+ 'observer_activity' => [
+ 'like' => intval($item['observer_like_count'] ?? 0),
+ 'dislike' => intval($item['observer_dislike_count'] ?? 0),
+ 'announce' => intval($item['observer_announce_count'] ?? 0),
+ 'comment' => intval($item['observer_comment_count'] ?? 0),
+ 'accept' => intval($item['observer_accept_count'] ?? 0),
+ 'reject' => intval($item['observer_reject_count'] ?? 0),
+ 'tentativeaccept' => intval($item['observer_tentativeaccept_count'] ?? 0)
+ ],
+ 'threaded' => $this->threaded,
+ 'blog_mode' => $blog_mode,
+ 'collapse_comments' => t('show less'),
+ 'expand_comments' => $this->threaded ? t('show more') : t('show all'),
+ 'load_more' => $load_more,
+ 'load_more_title' => $load_more_title,
+ 'comments_total' => $conv->comments_total,
+ 'comments_total_percent' => $comments_total_percent,
+ 'expand' => $expand
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -553,33 +508,19 @@ class ThreadItem {
$result = $arr['output'];
$result['children'] = array();
- $nb_children = count($children);
- $visible_comments = Config::Get('system','expanded_comments');
- if($visible_comments === false)
- $visible_comments = 3;
+ $visible_comments = 3; // Config::Get('system', 'expanded_comments', 3);
-// needed for scroll to comment from notification but needs more work
-// as we do not want to open all comments unless there is actually an #item_xx anchor
-// and the url fragment is not sent to the server.
-// if(in_array(\App::$module,['display','update_display']))
-// $visible_comments = 99999;
-
- if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
+ if(($this->get_display_mode() === 'normal') && ($children_count > 0)) {
foreach($children as $child) {
- $result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags);
+ $result['children'][] = $child->get_template_data($thread_level + 1, $conv_flags);
}
+
// Collapse
- if(($nb_children > $visible_comments) || ($thread_level > 1)) {
+ if($thread_level === 1 && $children_count > $visible_comments) {
$result['children'][0]['comment_firstcollapsed'] = true;
$result['children'][0]['num_comments'] = $comment_count_txt['label'];
- $result['children'][0]['hide_text'] = t('show all');
- if($thread_level > 1) {
- $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
- }
- else {
- $result['children'][$nb_children - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
- }
+ $result['children'][$children_count - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
}
}
@@ -832,7 +773,7 @@ class ThreadItem {
*/
private function get_comment_box() {
- if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
+ if(!$this->is_toplevel()) {
return '';
}
@@ -868,14 +809,15 @@ class ThreadItem {
'$submit' => t('Submit'),
'$edbold' => t('Bold'),
'$editalic' => t('Italic'),
+ '$edhighlighter' => t('Highlight selected text'),
'$eduline' => t('Underline'),
'$edquote' => t('Quote'),
'$edcode' => t('Code'),
- '$edimg' => t('Image'),
+ '$edimg' => t('Embed (existing) photo from your photo albums'),
'$edatt' => t('Attach/Upload file'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
- '$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
+ '$preview' => t('Preview'),
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
@@ -896,12 +838,13 @@ class ThreadItem {
}
/**
- * Check if we are a wall to wall item and set the relevant properties
+ * Check if we are a wall to wall or announce item and set the relevant properties
*/
protected function check_wall_to_wall() {
$conv = $this->get_conversation();
$this->wall_to_wall = false;
$this->owner_url = '';
+ $this->owner_addr = '';
$this->owner_photo = '';
$this->owner_name = '';
@@ -910,12 +853,14 @@ class ThreadItem {
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
$this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
+ $this->owner_addr = $this->data['owner']['xchan_addr'];
$this->owner_photo = $this->data['owner']['xchan_photo_s'];
$this->owner_name = $this->data['owner']['xchan_name'];
$this->wall_to_wall = true;
}
elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) {
$this->owner_url = chanlink_hash($this->data['source']['xchan_hash']);
+ $this->owner_addr = $this->data['source']['xchan_addr'];
$this->owner_photo = $this->data['source']['xchan_photo_s'];
$this->owner_name = $this->data['source']['xchan_name'];
$this->wall_to_wall = true;
@@ -930,6 +875,10 @@ class ThreadItem {
return $this->owner_url;
}
+ private function get_owner_addr() {
+ return $this->owner_addr;
+ }
+
private function get_owner_photo() {
return $this->owner_photo;
}
diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php
index fb3b6dd9b..1d968fa1a 100644
--- a/Zotlabs/Lib/ThreadStream.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -24,6 +24,10 @@ class ThreadStream {
private $prepared_item = '';
public $reload = '';
private $cipher = 'AES-128-CCM';
+ public $mid_uuid_map = [];
+ public $comments_total = 0;
+ public $comments_loaded = 0;
+
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
@@ -211,16 +215,15 @@ class ThreadStream {
* _ The data requested on success
* _ false on failure
*/
- public function get_template_data($conv_responses, $mid_uuid_map) {
+ public function get_template_data() {
$result = array();
foreach($this->threads as $item) {
-
if(($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
$item_data = $this->prepared_item;
}
else {
- $item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
+ $item_data = $item->get_template_data();
}
if(!$item_data) {
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
diff --git a/Zotlabs/Lib/Traits/HelpHelperTrait.php b/Zotlabs/Lib/Traits/HelpHelperTrait.php
index 63b0eb22e..69b3cc21b 100644
--- a/Zotlabs/Lib/Traits/HelpHelperTrait.php
+++ b/Zotlabs/Lib/Traits/HelpHelperTrait.php
@@ -89,7 +89,7 @@ trait HelpHelperTrait {
);
return bbcode(
- t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developer_guide#Translations for information about how to help.")
+ t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developers_guide#Translations for information about how to help.")
);
}
}
diff --git a/Zotlabs/Module/Achievements.php b/Zotlabs/Module/Achievements.php
index 1529448d3..a16294039 100644
--- a/Zotlabs/Module/Achievements.php
+++ b/Zotlabs/Module/Achievements.php
@@ -8,25 +8,25 @@ class Achievements extends \Zotlabs\Web\Controller {
// This doesn't work, so
if (! is_developer())
return;
-
+
if(argc() > 1)
$which = argv(1);
else {
notice( t('Requested profile is not available.') . EOL );
return;
}
-
+
$profile = 0;
- $profile = argv(1);
+ $profile = argv(1);
profile_load($which,$profile);
-
+
$r = q("select channel_id from channel where channel_address = '%s'",
dbesc($which)
);
if($r) {
$owner = intval($r[0]['channel_id']);
}
-
+
$observer = \App::get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
@@ -34,60 +34,60 @@ class Achievements extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
-
+
$newmembertext = t('Some blurb about what to do when you\'re new here');
-
-
+
+
// By default, all badges are false
$contactbadge = false;
$profilebadge = false;
$keywordsbadge = false;
-
+
// Check number of contacts. Award a badge if over 10
- // We'll figure these out on each page load instead of
+ // We'll figure these out on each page load instead of
// writing them to the DB because that will mean one needs
// to retain their achievements - eg, you can't add
// a bunch of channels just to get your badge, and then
// delete them all again. If these become popular or
// used in profiles or something, we may need to reconsider
// and add a table for this - because this won't scale.
-
+
$r = q("select * from abook where abook_channel = %d",
intval($owner)
);
-
+
if (count($r))
$contacts = count($r);
// We're checking for 11 to adjust for the abook record for self
if ($contacts >= 11)
$contactbadge = true;
-
+
// Check if an about field in the profile has been created.
-
+
$r = q("select * from profile where uid = %d and about <> ''",
intval($owner)
);
-
+
if ($r)
$profilebadge = 1;
-
+
// Check if keywords have been set
-
+
$r = q("select * from profile where uid = %d and keywords <> ''",
intval($owner)
);
-
+
if($r)
$keywordsbadge = 1;
-
+
return replace_macros(get_markup_template("achievements.tpl"), array(
'$newmembertext' => $newmembertext,
'$profilebadge' => $profilebadge,
'$contactbadge' => $contactbadge,
'$keywordsbadge' => $keywordsbadge,
- '$channelsbadge' => $channelsbadge
+ '$channelsbadge' => null,
));
-
+
}
-
+
}
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index 1de7a3d02..cf9278f5e 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -29,11 +29,11 @@ class Acl extends \Zotlabs\Web\Controller {
// logger('mod_acl: ' . print_r($_GET,true),LOGGER_DATA);
- $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
- $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
- $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : '');
- $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : '');
- $noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
+ $start = (!empty($_REQUEST['start']) ? $_REQUEST['start'] : 0);
+ $count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 500);
+ $search = (!empty($_REQUEST['search']) ? $_REQUEST['search'] : '');
+ $type = (!empty($_REQUEST['type']) ? $_REQUEST['type'] : '');
+ $noforums = (!empty($_REQUEST['n']) ? $_REQUEST['n'] : false);
// $type =
@@ -53,7 +53,7 @@ class Acl extends \Zotlabs\Web\Controller {
// List of channels whose connections to also suggest,
// e.g. currently viewed channel or channels mentioned in a post
- $extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
+ $extra_channels = (!empty($_REQUEST['extra_channels']) ? $_REQUEST['extra_channels'] : []);
// The different autocomplete libraries use different names for the search text
// parameter. Internally we'll use $search to represent the search text no matter
@@ -416,7 +416,7 @@ class Acl extends \Zotlabs\Web\Controller {
}
$dirmode = intval(Config::Get('system','directory_mode'));
- $search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
+ $search = ((!empty($_REQUEST['search'])) ? htmlentities($_REQUEST['search'], ENT_COMPAT, 'UTF-8', false) : '');
if(! $search || mb_strlen($search) < 2)
return array();
@@ -446,7 +446,7 @@ class Acl extends \Zotlabs\Web\Controller {
$token = Config::Get('system','realm_token');
- $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
+ $count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 100);
if($url) {
$query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php
index 133312e28..64da2586b 100644
--- a/Zotlabs/Module/Activity.php
+++ b/Zotlabs/Module/Activity.php
@@ -23,14 +23,14 @@ class Activity extends Controller {
if (! $item_id)
http_status_exit(404, 'Not found');
- $portable_id = EMPTY_STR;
+ $portable_id = null;
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
- $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
$i = null;
@@ -166,6 +166,7 @@ class Activity extends Controller {
return;
}
+ $portable_id = null;
$ob_authorize = false;
$item_uid = 0;
@@ -191,7 +192,7 @@ class Activity extends Controller {
dbesc(ACTIVITY_UNFOLLOW)
);
- $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
diff --git a/Zotlabs/Module/Admin/Account_edit.php b/Zotlabs/Module/Admin/Account_edit.php
index 0300fb10c..35a15133f 100644
--- a/Zotlabs/Module/Admin/Account_edit.php
+++ b/Zotlabs/Module/Admin/Account_edit.php
@@ -8,6 +8,11 @@ class Account_edit {
function post() {
+ // Validate CSRF token
+ //
+ // We terminate with a 403 Forbidden status if the check fails.
+ check_form_security_token_ForbiddenOnErr('admin_account_edit', 'security');
+
$account_id = $_REQUEST['aid'];
if(! $account_id)
@@ -18,7 +23,7 @@ class Account_edit {
if($pass1 && $pass2 && ($pass1 === $pass2)) {
$salt = random_string(32);
$password_encoded = hash('whirlpool', $salt . $pass1);
- $r = q("update account set account_salt = '%s', account_password = '%s',
+ $r = q("update account set account_salt = '%s', account_password = '%s',
account_password_changed = '%s' where account_id = %d",
dbesc($salt),
dbesc($password_encoded),
@@ -34,7 +39,7 @@ class Account_edit {
$account_level = 5;
$account_language = trim($_REQUEST['account_language']);
- $r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
+ $r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
where account_id = %d",
dbesc($service_class),
intval($account_level),
@@ -62,8 +67,8 @@ class Account_edit {
return '';
}
-
$a = replace_macros(get_markup_template('admin_account_edit.tpl'), [
+ '$security' => get_form_security_token('admin_account_edit'),
'$account' => $x[0],
'$title' => t('Account Edit'),
'$pass1' => [ 'pass1', t('New Password'), ' ','' ],
diff --git a/Zotlabs/Module/Admin/Accounts.php b/Zotlabs/Module/Admin/Accounts.php
index 6f7cb0311..108231d7d 100644
--- a/Zotlabs/Module/Admin/Accounts.php
+++ b/Zotlabs/Module/Admin/Accounts.php
@@ -6,133 +6,33 @@ use Zotlabs\Lib\Config;
class Accounts {
- /**
- * @brief Handle POST actions on accounts admin page.
- *
- * This function is called when on the admin user/account page the form was
- * submitted to handle multiple operations at once. If one of the icons next
- * to an entry are pressed the function admin_page_accounts() will handle this.
- *
- */
const MYP = 'ZAR'; // ZAR2x
const VERSION = '2.0.0';
- function post() {
+ /**
+ * Handle POST actions on accounts admin page.
+ */
+ public function post() {
- $pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
- $users = ( x($_POST, 'user') ? $_POST['user'] : array() );
- $blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
+ $pending = x($_POST, 'pending') ? $_POST['pending'] : array();
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
- $isajax = is_ajax();
- $rc = 0;
-
- If (!is_site_admin()) {
- if ($isajax) {
- killme();
- exit;
- }
- goaway(z_root() . '/');
- }
-
- if ($isajax) {
- //$debug = print_r($_SESSION[self::MYP],true);
- $zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
- ? $_POST['zardo'] : '';
- // zarat arrives with leading underscore _n
- $zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
- ? substr($_POST['zarat'],1) : '';
- $zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
- ? hex2bin($_POST['zarse']) : '';
-
- if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
-
- //
- if ($zarop == 'd') {
- $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
- intval($_SESSION[self::MYP]['i'][$zarat]),
- dbesc($_SESSION[self::MYP]['h'][$zarat])
- );
- $rc = '×';
- }
- elseif ($zarop == 'a') {
- // approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
- $rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
- . " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
- . " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
- intval($_SESSION[self::MYP]['i'][$zarat]),
- dbesc($_SESSION[self::MYP]['h'][$zarat])
- );
- $rc = 0;
- $rs = q("SELECT * from register WHERE reg_id = %d ",
- intval($_SESSION[self::MYP]['i'][$zarat])
- );
- if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
- // create account
- $rc = 'ok'.$rs[0]['reg_id'];
- $ac = create_account_from_register($rs[0]);
- if ( $ac['success'] ) {
- $rc .= '✔';
-
- $auto_create = Config::Get('system','auto_channel_create',1);
-
- if($auto_create) {
- $reonar = json_decode($rs[0]['reg_stuff'], true);
- // prepare channel creation
- if($reonar['chan.name'])
- set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
-
- if($reonar['chan.did1'])
- set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
-
- $permissions_role = Config::Get('system','default_permissions_role');
- if($permissions_role)
- set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
-
- // create channel
- $new_channel = auto_channel_create($ac['account']['account_id']);
-
- if($new_channel['success']) {
- $rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
- }
- else {
- $rc .= ' c ×';
- }
- }
-
-
- }
- } else {
- $rc='oh ×';
- }
- }
- echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
- }
+ if (is_ajax()) {
+ $this->handle_ajax_request();
killme();
- exit;
}
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
- for ($i = 0; $i < count($users); $i++) {
- // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
- $op = ($blocked[$i]) ? '& ~' : '| ';
- q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
- intval(ACCOUNT_BLOCKED),
- intval($users[$i])
- );
- }
- notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
+ $this->block_unblock_accounts();
}
+
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
- foreach ($users as $uid){
- account_remove($uid, true, false);
- }
- notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
+ $this->delete_accounts();
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
@@ -351,5 +251,143 @@ class Accounts {
return $o;
}
+ private function handle_ajax_request(): void {
+ //$debug = print_r($_SESSION[self::MYP],true);
+ $zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
+ ? $_POST['zardo'] : '';
+ // zarat arrives with leading underscore _n
+ $zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
+ ? substr($_POST['zarat'],1) : '';
+ $zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
+ ? hex2bin($_POST['zarse']) : '';
+
+ if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
+
+ //
+ if ($zarop == 'd') {
+ $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = '×';
+ }
+ elseif ($zarop == 'a') {
+ // approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
+ $rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
+ . " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
+ . " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = 0;
+ $rs = q("SELECT * from register WHERE reg_id = %d ",
+ intval($_SESSION[self::MYP]['i'][$zarat])
+ );
+ if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
+ // create account
+ $rc = 'ok'.$rs[0]['reg_id'];
+ $ac = create_account_from_register($rs[0]);
+ if ( $ac['success'] ) {
+ $rc .= '✔';
+
+ $auto_create = Config::Get('system','auto_channel_create',1);
+
+ if($auto_create) {
+ $reonar = json_decode($rs[0]['reg_stuff'], true);
+ // prepare channel creation
+ if($reonar['chan.name'])
+ set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
+
+ if($reonar['chan.did1'])
+ set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
+
+ $permissions_role = Config::Get('system','default_permissions_role');
+ if($permissions_role)
+ set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
+
+ // create channel
+ $new_channel = auto_channel_create($ac['account']['account_id']);
+
+ if($new_channel['success']) {
+ $rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
+ }
+ else {
+ $rc .= ' c ×';
+ }
+ }
+
+
+ }
+ } else {
+ $rc='oh ×';
+ }
+ }
+ echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
+ }
+ }
+
+ /**
+ * Block or unblock accounts given by the `user` and `blocked` POST params.
+ *
+ * The post params `user` and `blocked` must be present and arrays of equal
+ * lengths. The `user` array should contain account id's or the accounts to
+ * process, and the `blocked` array holds a corresponding boolean value to
+ * indicate that the account at the same offset in the `user` array is or is
+ * not blocked.
+ *
+ * An account that is _not_ blocked will be blocked, and accounts that _are_
+ * blocked will be unblocked.
+ *
+ * @SuppressWarnings(PHPMD.ShortVariable)
+ */
+ private function block_unblock_accounts(): void {
+ if (!isset($_POST['user']) || !isset($_POST['blocked'])) {
+ return;
+ }
+
+ $users = $_POST['user'];
+ $blocked = $_POST['blocked'];
+
+ if (!is_array($users) || !is_array($blocked)) {
+ return;
+ }
+
+ foreach($users as $i => $id) {
+ // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
+ $op = $blocked[$i] ? '& ~' : '| ';
+
+ q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
+ intval(ACCOUNT_BLOCKED),
+ intval($id)
+ );
+ }
+
+ $count = count($users);
+ $fmt = tt("%s account blocked/unblocked", "%s account blocked/unblocked", $count);
+ notice(sprintf($fmt, $count));
+ }
+
+ /**
+ * Delete multiple accounts given by the `user` POST param.
+ */
+ private function delete_accounts(): void {
+ if (!isset($_POST['user'])) {
+ return;
+ }
+
+ $users = $_POST['user'];
+
+ if (!is_array($users)) {
+ return;
+ }
+
+ foreach ($users as $uid){
+ account_remove($uid, true, false);
+ }
+
+ $count = count($users);
+ $fmt = tt("%s account deleted", "%s accounts deleted", $count);
+ notice(sprintf($fmt, $count));
+ }
}
diff --git a/Zotlabs/Module/Admin/Addons.php b/Zotlabs/Module/Admin/Addons.php
index b7cfb651c..0cb173e7c 100644
--- a/Zotlabs/Module/Admin/Addons.php
+++ b/Zotlabs/Module/Admin/Addons.php
@@ -3,9 +3,8 @@
namespace Zotlabs\Module\Admin;
use App;
-use \Zotlabs\Lib\Config;
-use \Zotlabs\Storage\GitRepo;
-use \Michelf\MarkdownExtra;
+use Zotlabs\Lib\Config;
+use Michelf\MarkdownExtra;
class Addons {
@@ -24,227 +23,6 @@ class Addons {
goaway(z_root() . '/admin/addons/' . argv(2) );
}
- elseif(argc() > 2) {
- switch(argv(2)) {
- case 'updaterepo':
- if (array_key_exists('repoName', $_REQUEST)) {
- $repoName = $_REQUEST['repoName'];
- }
- else {
- json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
- }
- $extendDir = 'store/[data]/git/sys/extend';
- $addonDir = $extendDir . '/addon';
- if (!file_exists($extendDir)) {
- if (!mkdir($extendDir, 0770, true)) {
- logger('Error creating extend folder: ' . $extendDir);
- json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
- }
- else {
- if (!symlink(realpath('extend/addon'), $addonDir)) {
- logger('Error creating symlink to addon folder: ' . $addonDir);
- json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
- }
- }
- }
- $repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
- if (!is_dir($repoDir)) {
- logger('Repo directory does not exist: ' . $repoDir);
- json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
- }
- if (!is_writable($repoDir)) {
- logger('Repo directory not writable to web server: ' . $repoDir);
- json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
- }
- $git = new GitRepo('sys', null, false, $repoName, $repoDir);
- try {
- if ($git->pull()) {
- $files = array_diff(scandir($repoDir), array('.', '..'));
- foreach ($files as $file) {
- if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
- $source = '../extend/addon/' . $repoName . '/' . $file;
- $target = realpath('addon/') . '/' . $file;
- unlink($target);
- if (!symlink($source, $target)) {
- logger('Error linking addons to /addon');
- json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
- }
- }
- }
- json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
- } else {
- json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
- }
- } catch (\PHPGit\Exception\GitException $e) {
- json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
- }
- break;
- case 'removerepo':
- if (array_key_exists('repoName', $_REQUEST)) {
- $repoName = $_REQUEST['repoName'];
- } else {
- json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
- }
- $extendDir = 'store/[data]/git/sys/extend';
- $addonDir = $extendDir . '/addon';
- if (!file_exists($extendDir)) {
- if (!mkdir($extendDir, 0770, true)) {
- logger('Error creating extend folder: ' . $extendDir);
- json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
- } else {
- if (!symlink(realpath('extend/addon'), $addonDir)) {
- logger('Error creating symlink to addon folder: ' . $addonDir);
- json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
- }
- }
- }
- $repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
- if (!is_dir($repoDir)) {
- logger('Repo directory does not exist: ' . $repoDir);
- json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
- }
- if (!is_writable($repoDir)) {
- logger('Repo directory not writable to web server: ' . $repoDir);
- json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
- }
- /// @TODO remove directory and unlink /addon/files
- if (rrmdir($repoDir)) {
- json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
- } else {
- json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
- }
- break;
- case 'installrepo':
- if (array_key_exists('repoURL', $_REQUEST)) {
- require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
- $repoURL = $_REQUEST['repoURL'];
- $extendDir = 'store/[data]/git/sys/extend';
- $addonDir = $extendDir . '/addon';
- if (!file_exists($extendDir)) {
- if (!mkdir($extendDir, 0770, true)) {
- logger('Error creating extend folder: ' . $extendDir);
- json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
- } else {
- if (!symlink(realpath('extend/addon'), $addonDir)) {
- logger('Error creating symlink to addon folder: ' . $addonDir);
- json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
- }
- }
- }
- if (!is_writable($extendDir)) {
- logger('Directory not writable to web server: ' . $extendDir);
- json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
- }
- $repoName = null;
- if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
- $repoName = $_REQUEST['repoName'];
- } else {
- $repoName = GitRepo::getRepoNameFromURL($repoURL);
- }
- if (!$repoName) {
- logger('Invalid git repo');
- json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
- }
- $repoDir = $addonDir . '/' . $repoName;
- $tempRepoBaseDir = 'store/[data]/git/sys/temp/';
- $tempAddonDir = $tempRepoBaseDir . $repoName;
-
- if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
- logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
- json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
- }
- rename($tempAddonDir, $repoDir);
-
- if (!is_writable(realpath('addon/'))) {
- logger('/addon directory not writable to web server: ' . $tempAddonDir);
- json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
- }
- $files = array_diff(scandir($repoDir), array('.', '..'));
- foreach ($files as $file) {
- if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
- $source = '../extend/addon/' . $repoName . '/' . $file;
- $target = realpath('addon/') . '/' . $file;
- unlink($target);
- if (!symlink($source, $target)) {
- logger('Error linking addons to /addon');
- json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
- }
- }
- }
- $git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
- $repo = $git->probeRepo();
- json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
- }
- break;
- case 'addrepo':
- if (array_key_exists('repoURL', $_REQUEST)) {
- require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
- $repoURL = $_REQUEST['repoURL'];
- $extendDir = 'store/[data]/git/sys/extend';
- $addonDir = $extendDir . '/addon';
- $tempAddonDir = realpath('store/[data]') . '/git/sys/temp';
- if (!file_exists($extendDir)) {
- if (!mkdir($extendDir, 0770, true)) {
- logger('Error creating extend folder: ' . $extendDir);
- json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
- } else {
- if (!symlink(realpath('extend/addon'), $addonDir)) {
- logger('Error creating symlink to addon folder: ' . $addonDir);
- json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
- }
- }
- }
- if (!is_dir($tempAddonDir)) {
- if (!mkdir($tempAddonDir, 0770, true)) {
- logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
- json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
- }
- }
- $repoName = null;
- if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
- $repoName = $_REQUEST['repoName'];
- } else {
- $repoName = GitRepo::getRepoNameFromURL($repoURL);
- }
- if (!$repoName) {
- logger('Invalid git repo');
- json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
- }
- $repoDir = $tempAddonDir . '/' . $repoName;
- if (!is_writable($tempAddonDir)) {
- logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
- json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
- }
- // clone the repo if new automatically
- $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
-
- $remotes = $git->git->remote();
- $fetchURL = $remotes['origin']['fetch'];
- if ($fetchURL !== $git->url) {
- if (rrmdir($repoDir)) {
- $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
- } else {
- json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
- }
- }
- $repo = $git->probeRepo();
- $repo['readme'] = $repo['manifest'] = null;
- foreach ($git->git->tree('master') as $object) {
- if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
- $repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
- } else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
- $repo['manifest'] = $git->git->cat->blob($object['hash']);
- }
- }
- json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
- } else {
- json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
- }
- break;
- default:
- break;
- }
- }
}
/**
@@ -408,37 +186,6 @@ class Addons {
usort($plugins,'self::plugin_sort');
- $allowManageRepos = false;
- if(is_writable('extend/addon') && is_writable('store/[data]')) {
- $allowManageRepos = true;
- }
-
- $admin_plugins_add_repo_form= replace_macros(
- get_markup_template('admin_plugins_addrepo.tpl'), array(
- '$post' => 'admin/addons/addrepo',
- '$desc' => t('Enter the public git repository URL of the addon repo.'),
- '$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
- '$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
- '$submit' => t('Download Addon Repo')
- )
- );
- $newRepoModalID = random_string(3);
- $newRepoModal = replace_macros(
- get_markup_template('generic_modal.tpl'), array(
- '$id' => $newRepoModalID,
- '$title' => t('Install new repo'),
- '$ok' => t('Install'),
- '$cancel' => t('Cancel')
- )
- );
-
- $reponames = $this->listAddonRepos();
- $addonrepos = [];
- foreach($reponames as $repo) {
- $addonrepos[] = array('name' => $repo, 'description' => '');
- /// @TODO Parse repo info to provide more information about repos
- }
-
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -449,37 +196,9 @@ class Addons {
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_addons'),
- '$allowManageRepos' => $allowManageRepos,
- '$managerepos' => t('Manage Repos'),
- '$installedtitle' => t('Installed Addon Repositories'),
- '$addnewrepotitle' => t('Install a New Addon Repository'),
- '$expandform' => false,
- '$form' => $admin_plugins_add_repo_form,
- '$newRepoModal' => $newRepoModal,
- '$newRepoModalID' => $newRepoModalID,
- '$addonrepos' => $addonrepos,
- '$repoUpdateButton' => t('Update'),
- '$repoBranchButton' => t('Switch branch'),
- '$repoRemoveButton' => t('Remove')
));
}
- function listAddonRepos() {
- $addonrepos = [];
- $addonDir = 'extend/addon/';
- if(is_dir($addonDir)) {
- if ($handle = opendir($addonDir)) {
- while (false !== ($entry = readdir($handle))) {
- if ($entry != "." && $entry != "..") {
- $addonrepos[] = $entry;
- }
- }
- closedir($handle);
- }
- }
- return $addonrepos;
- }
-
static public function plugin_sort($a,$b) {
return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
}
diff --git a/Zotlabs/Module/Admin/Features.php b/Zotlabs/Module/Admin/Features.php
index e0b3a3fd4..eb82ae1ff 100644
--- a/Zotlabs/Module/Admin/Features.php
+++ b/Zotlabs/Module/Admin/Features.php
@@ -59,14 +59,13 @@ class Features {
}
$tpl = get_markup_template("admin_settings_features.tpl");
- $o .= replace_macros($tpl, array(
+
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("admin_manage_features"),
'$title' => t('Manage Additional Features'),
'$features' => $arr,
'$submit' => t('Submit'),
));
-
- return $o;
}
}
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index abc56d298..9ef5dc20f 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -6,6 +6,8 @@ use Zotlabs\Lib\Config;
class Site {
+ private string $eol;
+ private string $joo;
/**
* @brief POST handler for Admin Site Page.
@@ -208,7 +210,6 @@ class Site {
//Config::Set('system','force_queue_threshold', $force_queue);
Config::Set('system','no_community_page', $no_community_page);
- Config::Set('system','no_utf', $no_utf);
Config::Set('system','sse_enabled', $sse_enabled);
diff --git a/Zotlabs/Module/Admin/Themes.php b/Zotlabs/Module/Admin/Themes.php
index 6793f56b1..09fec9725 100644
--- a/Zotlabs/Module/Admin/Themes.php
+++ b/Zotlabs/Module/Admin/Themes.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module\Admin;
-use \Michelf\MarkdownExtra;
+use Michelf\MarkdownExtra;
use Zotlabs\Lib\Config;
/**
diff --git a/Zotlabs/Module/Api.php b/Zotlabs/Module/Api.php
index 8574ae1cd..c3337b501 100644
--- a/Zotlabs/Module/Api.php
+++ b/Zotlabs/Module/Api.php
@@ -108,6 +108,9 @@ class Api extends \Zotlabs\Web\Controller {
echo api_call();
killme();
+
+ // not reached
+ return;
}
function oauth_get_client($request){
diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
index 313c2df50..579ca738c 100644
--- a/Zotlabs/Module/Apporder.php
+++ b/Zotlabs/Module/Apporder.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
-use \Zotlabs\Lib as Zlib;
+use Zotlabs\Lib as Zlib;
class Apporder extends \Zotlabs\Web\Controller {
@@ -25,7 +25,7 @@ class Apporder extends \Zotlabs\Web\Controller {
$syslist[] = Zlib\Apps::app_encode($li);
}
}
-
+
Zlib\Apps::translate_system_apps($syslist);
usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
index a8817111e..97e1b237f 100644
--- a/Zotlabs/Module/Apps.php
+++ b/Zotlabs/Module/Apps.php
@@ -1,8 +1,8 @@
<?php
namespace Zotlabs\Module;
-use \Zotlabs\Lib\Config;
-use \Zotlabs\Lib as Zlib;
+use Zotlabs\Lib\Config;
+use Zotlabs\Lib as Zlib;
class Apps extends \Zotlabs\Web\Controller {
diff --git a/Zotlabs/Module/Attach_edit.php b/Zotlabs/Module/Attach_edit.php
index 5880d8f13..4cde1c168 100644
--- a/Zotlabs/Module/Attach_edit.php
+++ b/Zotlabs/Module/Attach_edit.php
@@ -133,6 +133,11 @@ class Attach_edit extends Controller {
}
$x = attach_move($channel_id, $resource, $newfolder, (($single) ? $newfilename : ''));
+ if (!$x['success']) {
+ notice($x['message'] . EOL);
+ goaway($return_path);
+ }
+
$actions_done .= 'move,';
}
diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php
index c6709f602..b015c3284 100644
--- a/Zotlabs/Module/Authorize.php
+++ b/Zotlabs/Module/Authorize.php
@@ -9,7 +9,7 @@ class Authorize extends \Zotlabs\Web\Controller {
function get() {
if (! local_channel()) {
return login();
- }
+ }
else {
$name = $_REQUEST['client_name'];
@@ -25,7 +25,7 @@ class Authorize extends \Zotlabs\Web\Controller {
$link = (($app['url']) ? '<a style="float: none;" href="' . $app['url'] . '">' . $app['name'] . '</a> ' : $app['name']);
- $o .= replace_macros(get_markup_template('oauth_authorize.tpl'), [
+ return replace_macros(get_markup_template('oauth_authorize.tpl'), [
'$title' => t('Authorize'),
'$authorize' => sprintf( t('Do you authorize the app %s to access your channel data?'), $link ),
'$app' => $app,
@@ -35,7 +35,6 @@ class Authorize extends \Zotlabs\Web\Controller {
'$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''),
'$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : ''),
]);
- return $o;
}
}
@@ -50,7 +49,7 @@ class Authorize extends \Zotlabs\Web\Controller {
// TODO: The automatic client registration protocol below should adhere more
// closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
// at https://tools.ietf.org/html/rfc7591
-
+
// If no client_id was provided, generate a new one.
if (x($_POST, 'client_id')) {
$client_id = $_POST['client_id'];
@@ -67,7 +66,7 @@ class Authorize extends \Zotlabs\Web\Controller {
$request = \OAuth2\Request::createFromGlobals();
$response = new \OAuth2\Response();
- // Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string.
+ // Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string.
$channel = channelx_by_n(local_channel());
$user_id = $channel['channel_id'];
diff --git a/Zotlabs/Module/Authtest.php b/Zotlabs/Module/Authtest.php
index d85af09dc..bf199ccf6 100644
--- a/Zotlabs/Module/Authtest.php
+++ b/Zotlabs/Module/Authtest.php
@@ -7,7 +7,7 @@ class Authtest extends \Zotlabs\Web\Controller {
$auth_success = false;
- $o .= '<h3>Magic-Auth Diagnostic</h3>';
+ $o = '<h3>Magic-Auth Diagnostic</h3>';
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
@@ -27,7 +27,7 @@ class Authtest extends \Zotlabs\Web\Controller {
$_REQUEST['test'] = 1;
$mod = new Magic();
- $x = $mod->init($a);
+ $x = $mod->init();
$o .= 'Local Setup returns: ' . print_r($x,true);
diff --git a/Zotlabs/Module/Changeaddr.php b/Zotlabs/Module/Changeaddr.php
index ed139c9f9..f8a045727 100644
--- a/Zotlabs/Module/Changeaddr.php
+++ b/Zotlabs/Module/Changeaddr.php
@@ -5,30 +5,30 @@ namespace Zotlabs\Module;
class Changeaddr extends \Zotlabs\Web\Controller {
function post() {
-
+
if(! local_channel())
return;
-
+
if($_SESSION['delegate'])
return;
-
+
if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
return;
-
+
if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
return;
-
+
if($_POST['verify'] !== $_SESSION['remove_account_verify'])
return;
-
-
+
+
$account = \App::get_account();
$channel = \App::get_channel();
-
+
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
return;
-
+
if($account['account_password_changed'] > NULL_DATE) {
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
if($account['account_password_changed'] > $d1) {
@@ -36,7 +36,7 @@ class Changeaddr extends \Zotlabs\Web\Controller {
return;
}
}
-
+
$new_address = trim($_POST['newname']);
if($new_address === $channel['channel_address'])
@@ -55,23 +55,23 @@ class Changeaddr extends \Zotlabs\Web\Controller {
channel_change_address($channel,$new_address);
goaway(z_root() . '/changeaddr');
-
+
}
-
-
+
+
function get() {
-
+
if(! local_channel())
goaway(z_root());
-
+
$channel = \App::get_channel();
$hash = random_string();
-
+
$_SESSION['remove_account_verify'] = $hash;
-
+
$tpl = get_markup_template('channel_rename.tpl');
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Change channel nickname/address'),
@@ -80,9 +80,5 @@ class Changeaddr extends \Zotlabs\Web\Controller {
'$newname' => array('newname', t('New channel address'),$channel['channel_address'], ''),
'$submit' => t('Rename Channel')
));
-
- return $o;
-
}
-
}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index f3855b7e8..e35a611d0 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -85,7 +85,7 @@ class Channel extends Controller {
$headers = [
'Content-Type' => 'application/x-zot+json',
'Digest' => HTTPSig::generate_digest_header($data),
- '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
+ 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
];
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel));
@@ -298,12 +298,15 @@ class Channel extends Controller {
$item_normal = item_normal();
$item_normal_update = item_normal_update();
- $sql_extra = item_permissions_sql(App::$profile['profile_uid']);
+ $sql_extra = '';
+ $permission_sql = item_permissions_sql(App::$profile['profile_uid']);
- if (feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (!$mid))
+ $page_mode = 'client';
+
+ $blog_mode = feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && !$mid;
+ if ($blog_mode) {
$page_mode = 'list';
- else
- $page_mode = 'client';
+ }
$abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " ";
@@ -334,8 +337,8 @@ class Channel extends Controller {
if (($update) && (!$load)) {
if ($mid) {
- $r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal_update
- AND item_wall = 1 $simple_update $sql_extra limit 1",
+ $r = q("SELECT *, parent AS item_id from item where $identifier = '%s' and uid = %d $item_normal_update
+ AND item_wall = 1 $simple_update $permission_sql $sql_extra limit 1",
dbesc($mid),
intval(App::$profile['profile_uid'])
);
@@ -346,6 +349,7 @@ class Channel extends Controller {
WHERE uid = %d $item_normal_update
AND item_wall = 1 $simple_update
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $permission_sql
$sql_extra
ORDER BY created DESC",
intval(App::$profile['profile_uid'])
@@ -382,8 +386,8 @@ class Channel extends Controller {
if ($noscript_content || $load) {
if ($mid) {
- $r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal
- AND item_wall = 1 $sql_extra limit 1",
+ $r = q("SELECT *, parent AS item_id from item where $identifier = '%s' and uid = %d $item_normal
+ AND item_wall = 1 $permission_sql $sql_extra limit 1",
dbesc($mid),
intval(App::$profile['profile_uid'])
);
@@ -392,13 +396,18 @@ class Channel extends Controller {
}
}
else {
- $r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item
- left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
- WHERE true and item.uid = %d $item_normal
+ $r = q("SELECT parent AS item_id, $ordering FROM item
+ LEFT JOIN abook ON (item.author_xchan = abook.abook_xchan $abook_uids)
+ WHERE item.uid = %d
+ AND item.id = item.parent
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
- AND item.item_wall = 1 AND item.item_thread_top = 1
- $sql_extra $sql_extra2
- ORDER BY $ordering DESC, item_id $pager_sql ",
+ AND item.item_wall = 1
+ $item_normal
+ $permission_sql
+ $sql_extra
+ $sql_extra2
+ ORDER BY $ordering DESC, item_id
+ $pager_sql",
intval(App::$profile['profile_uid'])
);
}
@@ -408,19 +417,15 @@ class Channel extends Controller {
}
}
if ($r) {
- $parents_str = ids_to_querystr($r, 'item_id');
-
- $r = q("SELECT item.*, item.id AS item_id
- FROM item
- WHERE item.uid = %d $item_normal
- AND item.parent IN ( %s )
- $sql_extra ",
- intval(App::$profile['profile_uid']),
- dbesc($parents_str)
- );
+ $thr_parents = null;
+ if ($mid) {
+ $thr_parents = get_recursive_thr_parents($r[0]);
+ }
- xchan_query($r);
- $items = fetch_post_tags($r, true);
+ $items = items_by_parent_ids($r, $thr_parents, $permission_sql, $blog_mode);
+
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
$items = conv_sort($items, $ordering);
if ($load && $mid && (!count($items))) {
@@ -434,11 +439,8 @@ class Channel extends Controller {
$items = [];
}
-
-
$mode = (($search) ? 'search' : 'channel');
-
if ((!$update) && (!$load)) {
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
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/Chatsvc.php b/Zotlabs/Module/Chatsvc.php
index 2f2784fc4..e9dfb2a4b 100644
--- a/Zotlabs/Module/Chatsvc.php
+++ b/Zotlabs/Module/Chatsvc.php
@@ -4,7 +4,7 @@ namespace Zotlabs\Module;
require_once('include/security.php');
-use \Zotlabs\Lib as Zlib;
+use Zotlabs\Lib as Zlib;
class Chatsvc extends \Zotlabs\Web\Controller {
diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php
index 527b06b3a..f9abd767a 100644
--- a/Zotlabs/Module/Cloud.php
+++ b/Zotlabs/Module/Cloud.php
@@ -7,11 +7,12 @@ namespace Zotlabs\Module;
* Module for accessing the DAV storage area.
*/
+use App;
use Sabre\DAV as SDAV;
-use \Zotlabs\Web\Controller;
-use \Zotlabs\Storage\BasicAuth;
-use \Zotlabs\Storage\Directory;
-use \Zotlabs\Storage\Browser;
+use Zotlabs\Web\Controller;
+use Zotlabs\Storage\BasicAuth;
+use Zotlabs\Storage\Directory;
+use Zotlabs\Storage\Browser;
// composer autoloader for SabreDAV
@@ -32,6 +33,15 @@ class Cloud extends Controller {
*/
function init() {
+ // TODO: why is this required?
+ // if we arrived at this path with any query parameters in the url, build a clean url without
+ // them and redirect.
+
+ $parsed = parse_url(App::$query_string);
+ if (!empty($parsed['query'])) {
+ goaway(z_root() . '/' . $parsed['path']);
+ }
+
if (! is_dir('store'))
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
@@ -44,15 +54,13 @@ class Cloud extends Controller {
if ($which)
profile_load( $which, $profile);
-
-
$auth = new BasicAuth();
$ob_hash = get_observer_hash();
if ($ob_hash) {
if (local_channel()) {
- $channel = \App::get_channel();
+ $channel = App::get_channel();
$auth->setCurrentUser($channel['channel_address']);
$auth->channel_account_id = $channel['channel_account_id'];
$auth->channel_id = $channel['channel_id'];
@@ -63,19 +71,12 @@ class Cloud extends Controller {
$auth->observer = $ob_hash;
}
- // if we arrived at this path with any query parameters in the url, build a clean url without
- // them and redirect.
-
if(! array_key_exists('cloud_sort',$_SESSION)) {
$_SESSION['cloud_sort'] = 'name';
}
$_SESSION['cloud_sort'] = ((isset($_REQUEST['sort']) && $_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']);
- $x = clean_query_string();
- if($x !== \App::$query_string)
- goaway(z_root() . '/' . $x);
-
$rootDirectory = new Directory('/', [], $auth);
// A SabreDAV server-object
@@ -116,16 +117,16 @@ class Cloud extends Controller {
function DAVException($err) {
if($err instanceof \Sabre\DAV\Exception\NotFound) {
- \App::$page['content'] = '<h2>404 Not found</h2>';
+ App::$page['content'] = '<h2>404 Not found</h2>';
}
elseif($err instanceof \Sabre\DAV\Exception\Forbidden) {
- \App::$page['content'] = '<h2>403 Forbidden</h2>';
+ App::$page['content'] = '<h2>403 Forbidden</h2>';
}
elseif($err instanceof \Sabre\DAV\Exception\NotImplemented) {
- goaway(z_root() . '/' . \App::$query_string);
+ goaway(z_root() . '/' . App::$query_string);
}
else {
- \App::$page['content'] = '<h2>Unknown error</h2>';
+ App::$page['content'] = '<h2>Unknown error</h2>';
}
construct_page();
diff --git a/Zotlabs/Module/Conversation.php b/Zotlabs/Module/Conversation.php
index aa8349f55..0a1ba87d1 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) {
@@ -30,14 +30,13 @@ class Conversation extends Controller {
dbesc(ACTIVITY_UNFOLLOW)
);
- $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
$i = null;
// do we have the item (at all)?
- $r = q("select parent_mid from item where mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1",
- dbesc(z_root() . '/item/' . $item_id),
+ $r = q("select parent_mid from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc($item_id)
);
@@ -77,16 +76,16 @@ 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');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
- $sql_extra = item_permissions_sql(0);
-
if (!$i) {
+ $sql_extra = item_permissions_sql(0);
+
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index aa2464ac2..2d2ffd52d 100644
--- a/Zotlabs/Module/Cover_photo.php
+++ b/Zotlabs/Module/Cover_photo.php
@@ -371,7 +371,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$tpl = get_markup_template('cover_photo.tpl');
- $o .= replace_macros($tpl,array(
+ $output = replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850),
@@ -397,15 +397,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
));
- call_hooks('cover_photo_content_end', $o);
+ call_hooks('cover_photo_content_end', $output);
- return $o;
+ return $output;
}
else {
$filename = \App::$data['imagecrop'] . '-3';
$resolution = 3;
$tpl = get_markup_template("cropcover.tpl");
- $o .= replace_macros($tpl,array(
+ return replace_macros($tpl,array(
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-3',
@@ -415,7 +415,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
'$form_security_token' => get_form_security_token("cover_photo"),
'$done' => t('Done Editing')
));
- return $o;
}
}
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index 96fe2c898..5254d436d 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -9,6 +9,7 @@
namespace Zotlabs\Module;
use Sabre\DAV as SDAV;
+use Zotlabs\Lib\Libzot;
use Zotlabs\Storage;
use Zotlabs\Web\HTTPSig;
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 451ddeb1f..094466665 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -212,7 +212,7 @@ class Display extends Controller {
$observer_hash = get_observer_hash();
$item_normal = item_normal();
$item_normal_update = item_normal_update();
- $sql_extra = '';
+ $permission_sql = '';
$r = [];
if($noscript_content || $load) {
@@ -231,7 +231,7 @@ class Display extends Controller {
}
if(!$r) {
- $sql_extra = item_permissions_sql(0, $observer_hash);
+ $permission_sql = item_permissions_sql(0, $observer_hash);
$r = q("SELECT item.id AS item_id FROM item
WHERE ((mid = '%s'
@@ -239,7 +239,7 @@ class Display extends Controller {
AND item.deny_gid = '' AND item_private = 0 )
AND uid IN ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d ))) OR
- (mid = '%s' $sql_extra ))
+ (mid = '%s' $permission_sql ))
$item_normal
limit 1",
dbesc($target_item['parent_mid']),
@@ -269,7 +269,7 @@ class Display extends Controller {
}
if(!$r) {
- $sql_extra = item_permissions_sql(0, $observer_hash);
+ $permission_sql = item_permissions_sql(0, $observer_hash);
$r = q("SELECT item.id as item_id from item
WHERE ((parent_mid = '%s'
@@ -277,7 +277,7 @@ class Display extends Controller {
AND item.deny_gid = '' AND item_private = 0 )
and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d ))) OR
- (parent_mid = '%s' $sql_extra ))
+ (parent_mid = '%s' $permission_sql ))
$item_normal
limit 1",
dbesc($target_item['parent_mid']),
@@ -288,17 +288,12 @@ class Display extends Controller {
}
if($r) {
- $parents_str = ids_to_querystr($r,'item_id');
- if($parents_str) {
- $items = q("SELECT item.*, item.id AS item_id
- FROM item
- WHERE parent in ( %s ) $sql_extra $item_normal ",
- dbesc($parents_str)
- );
- xchan_query($items);
- $items = fetch_post_tags($items,true);
- $items = conv_sort($items,'created');
- }
+ $thr_parents = get_recursive_thr_parents($target_item);
+ $items = items_by_parent_ids($r, $thr_parents, $permission_sql);
+
+ xchan_query($items);
+ $items = fetch_post_tags($items,true);
+ $items = conv_sort($items,'created');
}
else {
$items = array();
@@ -344,7 +339,12 @@ class Display extends Controller {
'$profile_page' => xmlify(z_root() . '/display/' . gen_link_id($target_item['mid'])),
));
- $x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ];
+ $x = [
+ 'xml' => $atom,
+ 'channel' => $channel,
+ 'observer_hash' => $observer_hash,
+ 'params' => [],
+ ];
call_hooks('atom_feed_top',$x);
$atom = $x['xml'];
diff --git a/Zotlabs/Module/Dreport.php b/Zotlabs/Module/Dreport.php
index 5db607545..d1ffb8027 100644
--- a/Zotlabs/Module/Dreport.php
+++ b/Zotlabs/Module/Dreport.php
@@ -19,7 +19,7 @@ class Dreport extends \Zotlabs\Web\Controller {
$table = 'push';
if($mid) {
- $i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
+ $i = q("select * from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
dbesc($mid),
intval($channel['channel_id']),
dbesc($channel['channel_hash']),
@@ -27,6 +27,12 @@ class Dreport extends \Zotlabs\Web\Controller {
);
if($i) {
\Zotlabs\Daemon\Master::Summon([ 'Notifier', 'edit_post', $i[0]['id'] ]);
+
+ $relatedItem = find_related($i[0]);
+ if (isset($relatedItem['id'])) {
+ \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'edit_post', $relatedItem['id'] ]);
+ }
+
}
}
sleep(3);
diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php
index 6f524cdb8..678ceb207 100644
--- a/Zotlabs/Module/Editpost.php
+++ b/Zotlabs/Module/Editpost.php
@@ -86,6 +86,7 @@ class Editpost extends \Zotlabs\Web\Controller {
'bbco_autocomplete'=> 'bbcode',
'return_path' => 'hq',
'button' => t('Submit'),
+ 'disable_comments' => (($itm[0]['item_thread_top']) ? false : true),
'hide_voting' => true,
'hide_future' => true,
'hide_location' => true,
diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php
index ed5b24724..edf2d162a 100644
--- a/Zotlabs/Module/Embedphotos.php
+++ b/Zotlabs/Module/Embedphotos.php
@@ -43,7 +43,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
$arr = explode('/', $href);
$resource_id = array_pop($arr);
$x = self::photolink($resource_id);
- if($x)
+ if($x)
json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id));
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
}
@@ -55,7 +55,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
$output = EMPTY_STR;
if($channel) {
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2);
- $r = q("select mimetype, height, width from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
+ $r = q("select mimetype, filename from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
dbesc($resource),
intval($resolution),
intval($channel['channel_id'])
@@ -63,6 +63,8 @@ class Embedphotos extends \Zotlabs\Web\Controller {
if(! $r)
return $output;
+ $filename = $r[0]['filename'];
+
if($r[0]['mimetype'] === 'image/jpeg')
$ext = '.jpg';
elseif($r[0]['mimetype'] === 'image/png')
@@ -75,7 +77,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
$ext = EMPTY_STR;
$output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' .
- '[zmg=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]';
+ '[zmg=' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . ']' . $filename . '[/zmg][/zrl]' . "\r\n";
return $output;
}
diff --git a/Zotlabs/Module/Fbrowser.php b/Zotlabs/Module/Fbrowser.php
index 3bac81c5a..e8517e095 100644
--- a/Zotlabs/Module/Fbrowser.php
+++ b/Zotlabs/Module/Fbrowser.php
@@ -6,6 +6,8 @@ namespace Zotlabs\Module;
* @author Fabio Comuni <fabrixxm@kirgroup.com>
*/
+use function Zotlabs\Render\template_escape;
+
require_once('include/photo/photo_driver.php');
/**
diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
index 8956ce16f..2586265f8 100644
--- a/Zotlabs/Module/File_upload.php
+++ b/Zotlabs/Module/File_upload.php
@@ -11,39 +11,42 @@ require_once('include/photos.php');
class File_upload extends \Zotlabs\Web\Controller {
function post() {
- logger('file upload: ' . print_r($_REQUEST,true));
+ logger('file upload: ' . print_r($_POST,true));
logger('file upload: ' . print_r($_FILES,true));
- $channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
+ $channel = (($_POST['channick']) ? channelx_by_nick($_POST['channick']) : null);
- if(! $channel) {
+ if (!$channel) {
logger('channel not found');
- killme();
+ is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
}
- $_REQUEST['source'] = 'file_upload';
+ $_POST['source'] = 'file_upload';
if($channel['channel_id'] != local_channel()) {
- $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
- $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']);
- $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
- $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
+ $_POST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
+ $_POST['group_allow'] = expand_acl($channel['channel_allow_gid']);
+ $_POST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
+ $_POST['group_deny'] = expand_acl($channel['channel_deny_gid']);
}
- $_REQUEST['allow_cid'] = ((isset($_REQUEST['contact_allow'])) ? perms2str($_REQUEST['contact_allow']) : '');
- $_REQUEST['allow_gid'] = ((isset($_REQUEST['group_allow'])) ? perms2str($_REQUEST['group_allow']) : '');
- $_REQUEST['deny_cid'] = ((isset($_REQUEST['contact_deny'])) ? perms2str($_REQUEST['contact_deny']) : '');
- $_REQUEST['deny_gid'] = ((isset($_REQUEST['group_deny'])) ? perms2str($_REQUEST['group_deny']) : '');
-
- if(isset($_REQUEST['filename']) && strlen($_REQUEST['filename'])) {
- $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
- if($r['success']) {
- $hash = $r['data']['hash'];
- $sync = attach_export_data($channel,$hash);
- if($sync) {
- Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
- }
- goaway(z_root() . '/' . $_REQUEST['return_url']);
+ $_POST['allow_cid'] = ((isset($_POST['contact_allow'])) ? perms2str($_POST['contact_allow']) : '');
+ $_POST['allow_gid'] = ((isset($_POST['group_allow'])) ? perms2str($_POST['group_allow']) : '');
+ $_POST['deny_cid'] = ((isset($_POST['contact_deny'])) ? perms2str($_POST['contact_deny']) : '');
+ $_POST['deny_gid'] = ((isset($_POST['group_deny'])) ? perms2str($_POST['group_deny']) : '');
+
+ if(isset($_POST['filename']) && strlen($_POST['filename'])) {
+ $r = attach_mkdir($channel, get_observer_hash(), $_POST);
+
+ if (!$r['success']) {
+ notice($r['message'] . EOL);
+ is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
+ }
+
+ $hash = $r['data']['hash'];
+ $sync = attach_export_data($channel,$hash);
+ if ($sync) {
+ Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
}
}
else {
@@ -90,19 +93,19 @@ class File_upload extends \Zotlabs\Web\Controller {
}
}
- $r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
- if($r['success']) {
- $sync = attach_export_data($channel,$r['data']['hash']);
- if($sync)
- Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ $r = attach_store($channel, get_observer_hash(), '', $_POST);
+ if (!$r['success']) {
+ notice($r['message'] . EOL);
+ is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
+ }
+ $sync = attach_export_data($channel,$r['data']['hash']);
+ if ($sync) {
+ Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
}
}
- if(is_ajax())
- killme();
-
- goaway(z_root() . '/' . $_REQUEST['return_url']);
+ is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
}
diff --git a/Zotlabs/Module/Filer.php b/Zotlabs/Module/Filer.php
index c2747e6c2..bf472eb67 100644
--- a/Zotlabs/Module/Filer.php
+++ b/Zotlabs/Module/Filer.php
@@ -1,43 +1,54 @@
<?php
namespace Zotlabs\Module;
-require_once('include/security.php');
-require_once('include/bbcode.php');
-require_once('include/items.php');
-
-
+use App;
class Filer extends \Zotlabs\Web\Controller {
function get() {
-
- if(! local_channel()) {
+
+ if(!local_channel()) {
killme();
}
-
- $term = unxmlify(trim($_GET['term']));
- $item_id = ((\App::$argc > 1) ? intval(\App::$argv[1]) : 0);
-
+
+ $term = unxmlify(trim($_GET['term'] ?? ''));
+ $item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
+
logger('filer: tag ' . $term . ' item ' . $item_id);
-
+
if($item_id && strlen($term)){
+
+ $sys = get_sys_channel();
+
+ $r = q("SELECT * FROM item WHERE (uid = %d OR uid = %d) AND id = %d
+ and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0
+ and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1",
+ intval(local_channel()),
+ intval($sys['channel_id']),
+ intval($item_id)
+ );
+
+ if ($r && $r[0]['uid'] === $sys['channel_id']) {
+ $r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
+ }
+
+ if(!$r) {
+ killme();
+ }
+
+ $item_id = $r[0]['id'];
+
// file item
store_item_tag(local_channel(),$item_id,TERM_OBJ_POST,TERM_FILE,$term,'');
-
+
// protect the entire conversation from periodic expiration
-
- $r = q("select parent from item where id = %d and uid = %d limit 1",
- intval($item_id),
+
+ q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d",
+ dbesc(datetime_convert()),
+ intval($r[0]['parent']),
intval(local_channel())
);
- if($r) {
- $x = q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d",
- dbesc(datetime_convert()),
- intval($r[0]['parent']),
- intval(local_channel())
- );
- }
- }
+ }
else {
$filetags = array();
$r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
@@ -55,10 +66,10 @@ class Filer extends \Zotlabs\Web\Controller {
'$title' => t('Save to Folder'),
'$cancel' => t('Cancel')
));
-
+
echo $o;
}
killme();
}
-
+
}
diff --git a/Zotlabs/Module/Go.php b/Zotlabs/Module/Go.php
index ec528fb1a..77a3ffac6 100644
--- a/Zotlabs/Module/Go.php
+++ b/Zotlabs/Module/Go.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
-use Zorlabs\Lib\Config;
+use Zotlabs\Lib\Config;
class Go extends \Zotlabs\Web\Controller {
@@ -19,7 +19,7 @@ class Go extends \Zotlabs\Web\Controller {
function get() {
if(! local_channel()) {
- notify( t('This page is available only to site members') . EOL);
+ notice( t('This page is available only to site members') . EOL);
}
$channel = \App::get_channel();
diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php
index cacc81607..52e23e4e0 100644
--- a/Zotlabs/Module/Help.php
+++ b/Zotlabs/Module/Help.php
@@ -30,7 +30,7 @@ class Help extends \Zotlabs\Web\Controller {
$this->determine_help_language();
if (empty($_REQUEST['search']) && argc() === 1) {
- goaway("/help/{$this->lang['language']}/about/about");
+ goaway("/help/about");
killme();
}
}
@@ -85,7 +85,7 @@ class Help extends \Zotlabs\Web\Controller {
}
- if(argc() > 2 && argv(argc()-2) === 'assets') {
+ if(argc() > 2 && argv(argc()-2) === 'pic') {
$path = '';
for($x = 1; $x < argc(); $x ++) {
if(strlen($path))
@@ -155,7 +155,7 @@ class Help extends \Zotlabs\Web\Controller {
}
if (empty($args)) {
- goaway("/help/{$this->lang['language']}/about/about");
+ goaway("/help/about/about");
}
// Keep the first remaining arg as the heading slug
diff --git a/Zotlabs/Module/Home.php b/Zotlabs/Module/Home.php
index 691ca1af9..0dec432d0 100644
--- a/Zotlabs/Module/Home.php
+++ b/Zotlabs/Module/Home.php
@@ -24,9 +24,13 @@ class Home extends Controller {
$key = Config::Get('system', 'prvkey');
$ret = json_encode(Libzot::site_info());
- $headers = ['Content-Type' => 'application/x-zot+json', 'Digest' => HTTPSig::generate_digest_header($ret)];
- $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
- $h = HTTPSig::create_sig($headers, $key, z_root());
+ $headers = [
+ 'Content-Type' => 'application/x-zot+json',
+ 'Digest' => HTTPSig::generate_digest_header($ret),
+ 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
+ ];
+
+ $h = HTTPSig::create_sig($headers, $key, z_root());
HTTPSig::set_headers($h);
echo $ret;
@@ -68,9 +72,9 @@ class Home extends Controller {
$o = '';
- if (x($_SESSION, 'theme'))
+ if (isset($_SESSION['theme']))
unset($_SESSION['theme']);
- if (x($_SESSION, 'mobile_theme'))
+ if (isset($_SESSION['mobile_theme']))
unset($_SESSION['mobile_theme']);
$splash = ((argc() > 1 && argv(1) === 'splash') ? true : false);
@@ -100,14 +104,25 @@ class Home extends Controller {
goaway($frontpage);
}
+ $o .= '<div class="generic-content-wrapper">';
+
$sitename = Config::Get('system', 'sitename');
- if ($sitename)
- $o .= '<h1 class="home-welcome">' . sprintf(t('Welcome to %s'), $sitename) . '</h1>';
+ if ($sitename) {
+ $o .= '<div class="section-title-wrapper">';
+ $o .= '<h2 class="">' . sprintf(t('Welcome to %s'), $sitename) . '</h2>';
+ $o .= '</div>';
+
+ }
+
+ $o .= '<div class="section-content-wrapper">';
$loginbox = Config::Get('system', 'login_on_homepage');
if (intval($loginbox) || $loginbox === false)
$o .= login(true);
+ $o .= '</div>';
+ $o .= '</div>';
+
return $o;
}
diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php
index c8e6efe38..241a5101a 100644
--- a/Zotlabs/Module/Hq.php
+++ b/Zotlabs/Module/Hq.php
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Widget\Messages;
+use Zotlabs\Lib\Config;
class Hq extends \Zotlabs\Web\Controller {
@@ -50,12 +51,13 @@ class Hq extends \Zotlabs\Web\Controller {
// select the target item with a bias to our own item
$sql_order = ((local_channel() > $sys['channel_id']) ? 'DESC' : 'ASC');
- $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
+ $r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
intval(local_channel()),
intval($sys['channel_id']),
dbesc($item_hash)
);
+
if($r) {
$target_item = $r[0];
if (intval($target_item['uid']) === intval($sys['channel_id'])) {
@@ -129,7 +131,7 @@ class Hq extends \Zotlabs\Web\Controller {
'$nouveau' => '0',
'$wall' => '0',
'$page' => '1',
- '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
+ '$list' => ((!empty($_REQUEST['list'])) ? intval($_REQUEST['list']) : 0),
'$search' => '',
'$xchan' => '',
'$order' => '',
@@ -145,7 +147,6 @@ class Hq extends \Zotlabs\Web\Controller {
}
if($load && $target_item) {
-
if (!$sys_item) {
$r = q("SELECT item.id AS item_id FROM item
WHERE uid = %d
@@ -199,11 +200,8 @@ class Hq extends \Zotlabs\Web\Controller {
}
if($r) {
- $items = q("SELECT item.*, item.id AS item_id
- FROM item
- WHERE parent = '%s' $item_normal $sql_extra",
- dbesc($r[0]['item_id'])
- );
+ $thr_parents = get_recursive_thr_parents($target_item);
+ $items = items_by_parent_ids($r, $thr_parents);
xchan_query($items,true,(($sys_item) ? local_channel() : 0));
$items = fetch_post_tags($items,true);
@@ -230,6 +228,7 @@ class Hq extends \Zotlabs\Web\Controller {
$options['offset'] = $_REQUEST['offset'] ?? 0;
$options['type'] = $_REQUEST['type'] ?? '';
$options['author'] = ((isset($_REQUEST['author'])) ? urldecode($_REQUEST['author']) : '');
+ $options['file'] = ((isset($_REQUEST['file'])) ? urldecode($_REQUEST['file']) : '');
$ret = Messages::get_messages_page($options);
diff --git a/Zotlabs/Module/Id.php b/Zotlabs/Module/Id.php
index e08568d00..004cad6e7 100644
--- a/Zotlabs/Module/Id.php
+++ b/Zotlabs/Module/Id.php
@@ -6,8 +6,8 @@ namespace Zotlabs\Module;
*
* Controller for responding to x-zot: protocol requests
* x-zot:_jkfRG85nJ-714zn-LW_VbTFW8jSjGAhAydOcJzHxqHkvEHWG2E0RbA_pbch-h4R63RG1YJZifaNzgccoLa3MQ/453c1678-1a79-4af7-ab65-6b012f6cab77
- *
- */
+ *
+ */
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
@@ -104,7 +104,7 @@ class Id extends Controller {
$headers['Content-Type'] = 'application/x-zot+json' ;
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
- $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
+ $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
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/Invite.php b/Zotlabs/Module/Invite.php
index 3e1e98f89..aff0e9340 100644
--- a/Zotlabs/Module/Invite.php
+++ b/Zotlabs/Module/Invite.php
@@ -310,9 +310,9 @@ class Invite extends Controller {
function get() {
- // zai1
+ $channel_id = local_channel();
- if(! local_channel()) {
+ if ($channel_id === false || $channel_id < 1) {
notice( 'ZAI0101E,' . t('Permission denied.') . EOL);
return;
}
@@ -330,15 +330,15 @@ class Invite extends Controller {
return $o;
}
- // invitation_by_user may still not configured, the default 'na' will tell this
- // if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
- $invuser = Config::Get('system','invitation_by_user', 'na');
+ $ihave = $this->count_invites_by_user($channel_id);
- // if the mortal user drives the invitation
- If (! is_site_admin()) {
-
- // when not configured, 4 is the default
- $invuser = ($invuser === 'na') ? 4 : $invuser;
+ if (is_site_admin()) {
+ // Admins have unlimited invites
+ $invuser = '∞';
+ } else {
+ // invitation_by_user may still not configured, the default 'na' will tell this
+ // if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
+ $invuser = Config::Get('system','invitation_by_user', 4);
// a config value 0 disables invitation by users
if (!$invuser) {
@@ -350,12 +350,6 @@ class Invite extends Controller {
notice( 'ZAI0105W,' . t('You have no more invitations available') . EOL);
return '';
}
-
- } else {
- // general deity admin invite limit infinite (theoretical)
- if ($invuser === 'na') Config::Set('system','invitation_by_user', 4);
- // for display only
- $invuser = '∞';
}
// xchan record of the page observer
@@ -394,17 +388,6 @@ class Invite extends Controller {
}
}
- if ($wehave > $invmaxau) {
- if (! is_site_admin()) {
- $feedbk .= 'ZAI0200E,' . t('All users invitation limit exceeded.') . $eol;
- }
- }
-
- // let see how many invites currently used by the user
- $r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d",
- intval(local_channel()));
- $ihave = $r ? $r[0]['n'] : 0;
-
$tpl = get_markup_template('invite.tpl');
$inv_rabots = array(
@@ -420,11 +403,11 @@ class Invite extends Controller {
'field' => array(
'name' => 'expire',
'title' => t('duration up from now'),
- 'value' => ($invexpire_n ? $invexpire_n : 2),
+ 'value' => 2,
'min' => '1',
'max' => '99',
'size' => '2',
- 'default' => ($invexpire_u ? $invexpire_u : 'd')
+ 'default' => 'd',
),
'rabot' => $inv_rabots
)
@@ -583,5 +566,18 @@ class Invite extends Controller {
}
return false;
}
+
+ /**
+ * Find how many invites the given channel is currently using.
+ *
+ * @param int $channel_id The id of the channel
+ *
+ * @return int Number of invites this channel is currently using.
+ */
+ private function count_invites_by_user(int $channel): int {
+ $r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d", $channel);
+
+ return $r ? $r[0]['n'] : 0;
+ }
}
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 5618137a1..83e8d609e 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -44,253 +44,30 @@ class Item extends Controller {
function init() {
if (Libzot::is_zot_request()) {
-
- $item_id = argv(1);
-
- if (!$item_id)
- http_status_exit(404, 'Not found');
-
- $portable_id = EMPTY_STR;
-
- $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
- dbesc(ACTIVITY_FOLLOW),
- dbesc(ACTIVITY_UNFOLLOW)
- );
-
- $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
-
- $i = null;
-
- // do we have the item (at all)?
-
- $r = q("select parent_mid from item where uuid = '%s' $item_normal limit 1",
- dbesc($item_id)
- );
-
- if (!$r) {
- http_status_exit(404, 'Not found');
- }
-
- // process an authenticated fetch
-
- $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR);
- if ($sigdata['portable_id'] && $sigdata['header_valid']) {
- $portable_id = $sigdata['portable_id'];
- if (!check_channelallowed($portable_id)) {
- http_status_exit(403, 'Permission denied');
- }
- if (!check_siteallowed($sigdata['signer'])) {
- http_status_exit(403, 'Permission denied');
- }
- observer_auth($portable_id);
-
- $i = q("select id as item_id, uid from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1",
- dbesc($r[0]['parent_mid']),
- dbesc($portable_id)
- );
- }
- elseif (Config::get('system', 'require_authenticated_fetch', false)) {
- http_status_exit(403, 'Permission denied');
- }
-
- // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
- // with a bias towards those items owned by channels on this site (item_wall = 1)
-
- $sql_extra = item_permissions_sql(0);
-
- if (!$i) {
- $i = q("select id as item_id, uid, item_private from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
- dbesc($r[0]['parent_mid'])
- );
- }
-
- if (!$i) {
- http_status_exit(403, 'Forbidden');
- }
-
- $chan = channelx_by_n($i[0]['uid']);
-
- if (!$chan) {
- http_status_exit(404, 'Not found');
- }
-
- if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) {
- http_status_exit(403, 'Forbidden');
- }
-
- $parents_str = ids_to_querystr($i, 'item_id');
-
- // We won't need to check for privacy mismatches if the verified observer is also owner
- $parent_item_private = ((isset($i[0]['item_private'])) ? " and item_private = " . intval($i[0]['item_private']) . " " : '');
-
- $total = q("SELECT count(*) AS count FROM item WHERE parent = %d $parent_item_private $item_normal ",
- intval($parents_str)
- );
-
- App::set_pager_total($total[0]['count']);
- App::set_pager_itemspage(30);
-
- if (App::$pager['total'] > App::$pager['itemspage']) {
- // let mod conversation handle this request
- App::$query_string = str_replace('item', 'conversation', App::$query_string);
- $i = Activity::paged_collection_init(App::$pager['total'], App::$query_string);
- as_return_and_die($i ,$chan);
- }
- else {
- $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent = %d $parent_item_private $item_normal ORDER BY item.id",
- intval($parents_str)
- );
-
- xchan_query($items, true);
- $items = fetch_post_tags($items, true);
-
- $i = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection', App::$pager['total']);
- }
-
- if ($portable_id && (!intval($items[0]['item_private']))) {
- $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
- intval($items[0]['uid']),
- dbesc($portable_id)
- );
- if (!$c) {
- ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
- }
- }
-
- as_return_and_die($i ,$chan);
+ $this->init_zot_request();
}
if (ActivityStreams::is_as_request()) {
-
- $item_id = argv(1);
- if (!$item_id)
- http_status_exit(404, 'Not found');
-
- $portable_id = EMPTY_STR;
-
- $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
- dbesc(ACTIVITY_FOLLOW),
- dbesc(ACTIVITY_UNFOLLOW)
- );
-
- $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
-
- $i = null;
-
- // do we have the item (at all)?
- // add preferential bias to item owners (item_wall = 1)
-
- $r = q("select * from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
- dbesc($item_id)
- );
-
- if (!$r) {
- http_status_exit(404, 'Not found');
- }
-
- // process an authenticated fetch
-
- $sigdata = HTTPSig::verify(EMPTY_STR);
- if ($sigdata['portable_id'] && $sigdata['header_valid']) {
- $portable_id = $sigdata['portable_id'];
- if (!check_channelallowed($portable_id)) {
- http_status_exit(403, 'Permission denied');
- }
- if (!check_siteallowed($sigdata['signer'])) {
- http_status_exit(403, 'Permission denied');
- }
- observer_auth($portable_id);
-
- $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ",
- dbesc($r[0]['parent_mid']),
- dbesc($portable_id)
- );
- }
- elseif (Config::get('system', 'require_authenticated_fetch', false)) {
- http_status_exit(403, 'Permission denied');
- }
-
- // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
- // with a bias towards those items owned by channels on this site (item_wall = 1)
-
- $sql_extra = item_permissions_sql(0);
-
- if (!$i) {
- $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
- dbesc($r[0]['parent_mid'])
- );
- }
-
- $bear = Activity::token_from_request();
- if ($bear) {
- logger('bear: ' . $bear, LOGGER_DEBUG);
- if (!$i) {
- $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
- dbesc($bear)
- );
- if ($t) {
- $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
- dbesc($item_id),
- intval($t[0]['iid'])
- );
- }
- }
- }
-
- if (!$i) {
- http_status_exit(403, 'Forbidden');
- }
-
- // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it.
-
- xchan_query($r, true);
- $items = fetch_post_tags($r, false);
-
- $chan = channelx_by_n($items[0]['uid']);
-
- if (!$chan)
- http_status_exit(404, 'Not found');
-
- if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream'))
- http_status_exit(403, 'Forbidden');
-
- $i = Activity::encode_item($items[0]);
-
- if (!$i)
- http_status_exit(404, 'Not found');
-
- if ($portable_id && (!intval($items[0]['item_private']))) {
- $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
- intval($items[0]['uid']),
- dbesc($portable_id)
- );
- if (!$c) {
- ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
- }
- }
-
- as_return_and_die($i ,$chan);
-
+ $this->init_as_request();
}
if (argc() > 1 && argv(1) !== 'drop') {
- $x = q("select uid, item_wall, llink, mid, uuid from item where mid = '%s' or mid = '%s' or uuid = '%s'",
- dbesc(z_root() . '/item/' . argv(1)),
- dbesc(z_root() . '/activity/' . argv(1)),
+ $x = q("select uid, item_wall, llink, uuid from item where uuid = '%s' order by item_wall desc",
dbesc(argv(1))
);
+
if ($x) {
- foreach ($x as $xv) {
- if (intval($xv['item_wall'])) {
- $c = channelx_by_n($xv['uid']);
- if ($c) {
- goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $xv['uuid']);
- }
+ if ($x[0]['item_wall']) {
+ $c = channelx_by_n($x[0]['uid']);
+ if ($c) {
+ goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $x[0]['uuid']);
}
}
+
goaway($x[0]['llink']);
}
+
http_status_exit(404, 'Not found');
}
@@ -301,7 +78,7 @@ class Item extends Controller {
// This will change. Figure out who the observer is and whether or not
// they have permission to post here. Else ignore the post.
- if ((!local_channel()) && (!remote_channel()) && (!x($_REQUEST, 'anonname')))
+ if ((!local_channel()) && (!remote_channel()) && (empty($_POST['anonname'])))
return;
$uid = local_channel();
@@ -323,7 +100,6 @@ class Item extends Controller {
$item_deleted = false;
$item_hidden = false;
$item_unpublished = false;
- $item_delayed = false;
$item_pending_remove = false;
$item_blocked = false;
@@ -331,12 +107,13 @@ class Item extends Controller {
* Is this a reply to something?
*/
- $parent = ((x($_REQUEST, 'parent')) ? intval($_REQUEST['parent']) : 0);
- $parent_mid = ((x($_REQUEST, 'parent_mid')) ? trim($_REQUEST['parent_mid']) : '');
- $mode = ((isset($_REQUEST['conv_mode']) && $_REQUEST['conv_mode'] === 'channel') ? 'channel' : 'network');
+ $parent = ((!empty($_POST['parent'])) ? intval($_POST['parent']) : 0);
+ $thr_parent_id = $parent;
+ $parent_mid = ((!empty($_POST['parent_mid'])) ? trim($_POST['parent_mid']) : '');
+ $mode = ((isset($_POST['conv_mode']) && $_POST['conv_mode'] === 'channel') ? 'channel' : 'network');
- $remote_xchan = ((x($_REQUEST, 'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false);
- $r = q("select * from xchan where xchan_hash = '%s' limit 1",
+ $remote_xchan = ((!empty($_POST['remote_xchan'])) ? trim($_POST['remote_xchan']) : false);
+ $r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($remote_xchan)
);
if ($r)
@@ -344,7 +121,7 @@ class Item extends Controller {
else
$remote_xchan = $remote_observer = false;
- $profile_uid = ((x($_REQUEST, 'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
+ $profile_uid = ((!empty($_POST['profile_uid'])) ? intval($_POST['profile_uid']) : 0);
require_once('include/channel.php');
$sys = get_sys_channel();
@@ -354,25 +131,25 @@ class Item extends Controller {
$observer = $sys;
}
- if (x($_REQUEST, 'dropitems')) {
+ if (!empty($_POST['dropitems'])) {
require_once('include/items.php');
- $arr_drop = explode(',', $_REQUEST['dropitems']);
+ $arr_drop = explode(',', $_POST['dropitems']);
drop_items($arr_drop);
$json = ['success' => 1];
echo json_encode($json);
killme();
}
- call_hooks('post_local_start', $_REQUEST);
+ call_hooks('post_local_start', $_POST);
- // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
+ // logger('postvars ' . print_r($_POST,true), LOGGER_DATA);
- $api_source = ((x($_REQUEST, 'api_source') && $_REQUEST['api_source']) ? true : false);
+ $api_source = ((!empty($_POST['api_source'])) ? true : false);
- $consensus = $_REQUEST['consensus'] ?? 0;
- $nocomment = $_REQUEST['nocomment'] ?? 0;
+ $consensus = $_POST['consensus'] ?? 0;
+ $nocomment = $_POST['nocomment'] ?? 0;
- $is_poll = ((isset($_REQUEST['poll_answers'][0]) && $_REQUEST['poll_answers'][0]) && (isset($_REQUEST['poll_answers'][1]) && $_REQUEST['poll_answers'][1]));
+ $is_poll = ((isset($_POST['poll_answers'][0]) && $_POST['poll_answers'][0]) && (isset($_POST['poll_answers'][1]) && $_POST['poll_answers'][1]));
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
@@ -383,42 +160,43 @@ class Item extends Controller {
// If you are unsure, it is prudent (and important) to leave it unset.
- $origin = (($api_source && array_key_exists('origin', $_REQUEST)) ? intval($_REQUEST['origin']) : 1);
+ $origin = (($api_source && array_key_exists('origin', $_POST)) ? intval($_REQU_POSTEST['origin']) : 1);
// To represent message-ids on other networks - this will create an iconfig record
- $namespace = (($api_source && array_key_exists('namespace', $_REQUEST)) ? strip_tags($_REQUEST['namespace']) : '');
- $remote_id = (($api_source && array_key_exists('remote_id', $_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : '');
+ $namespace = (($api_source && array_key_exists('namespace', $_POST)) ? strip_tags($_POST['namespace']) : '');
+ $remote_id = (($api_source && array_key_exists('remote_id', $_POST)) ? strip_tags($_POST['remote_id']) : '');
$owner_hash = null;
- $message_id = ((x($_REQUEST, 'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : null);
- $created = ((x($_REQUEST, 'created')) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['created']) : datetime_convert());
- $post_id = ((x($_REQUEST, 'post_id')) ? intval($_REQUEST['post_id']) : 0);
- $app = ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : '');
- $return_path = ((x($_REQUEST, 'return')) ? $_REQUEST['return'] : '');
- $preview = ((x($_REQUEST, 'preview')) ? intval($_REQUEST['preview']) : 0);
- $categories = ((x($_REQUEST, 'category')) ? escape_tags($_REQUEST['category']) : '');
- $webpage = ((x($_REQUEST, 'webpage')) ? intval($_REQUEST['webpage']) : 0);
- $item_obscured = ((x($_REQUEST, 'obscured')) ? intval($_REQUEST['obscured']) : 0);
- $pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags($_REQUEST['pagetitle']) : '');
- $layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : '');
- $plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
- $obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : 'Note');
+ $message_id = ((!empty($_POST['message_id']) && $api_source) ? strip_tags($_POST['message_id']) : null);
+ $created = ((!empty($_POST['created'])) ? datetime_convert(date_default_timezone_get(), 'UTC', $_POST['created']) : datetime_convert());
+ $post_id = ((!empty($_POST['post_id'])) ? intval($_POST['post_id']) : 0);
+ $app = ((!empty($_POST['source'])) ? strip_tags($_POST['source']) : '');
+ $return_path = ((!empty($_POST['return'])) ? $_POST['return'] : '');
+ $preview = ((!empty($_POST['preview'])) ? intval($_POST['preview']) : 0);
+ $categories = ((!empty($_POST['category'])) ? escape_tags($_POST['category']) : '');
+ $item_type = ((!empty($_POST['webpage'])) ? intval($_POST['webpage']) : ITEM_TYPE_POST);
+ $item_obscured = ((!empty($_POST['obscured'])) ? intval($_POST['obscured']) : 0);
+ $item_delayed = ((!empty($_POST['delayed'])) ? intval($_POST['delayed']) : 0);
+ $pagetitle = ((!empty($_POST['pagetitle'])) ? escape_tags($_POST['pagetitle']) : '');
+ $layout_mid = ((!empty($_POST['layout_mid'])) ? escape_tags($_POST['layout_mid']) : '');
+ $plink = ((!empty($_POST['permalink'])) ? escape_tags($_POST['permalink']) : null);
+ $obj_type = ((!empty($_POST['obj_type'])) ? escape_tags($_POST['obj_type']) : 'Note');
// allow API to bulk load a bunch of imported items with sending out a bunch of posts.
- $nopush = ((x($_REQUEST, 'nopush')) ? intval($_REQUEST['nopush']) : 0);
+ $nopush = ((!empty($_POST['nopush'])) ? intval($_POST['nopush']) : 0);
/*
* Check service class limits
*/
- if ($uid && !(x($_REQUEST, 'parent')) && !(x($_REQUEST, 'post_id'))) {
- $ret = $this->item_check_service_class($uid, (($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false));
+ if ($uid && empty($_POST['parent']) && empty($_POST['post_id'])) {
+ $ret = $this->item_check_service_class($uid, (($_POST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false));
if (!$ret['success']) {
notice(t($ret['message']) . EOL);
if ($api_source)
return (['success' => false, 'message' => 'service class exception']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -430,7 +208,6 @@ class Item extends Controller {
$expires = NULL_DATE;
- $comments_closed = NULL_DATE;
$route = '';
$parent_item = null;
@@ -440,8 +217,8 @@ class Item extends Controller {
if ($parent || $parent_mid) {
- if (!x($_REQUEST, 'type'))
- $_REQUEST['type'] = 'net-comment';
+ if (empty($_POST['type']))
+ $_POST['type'] = 'net-comment';
if ($parent) {
$r = q("SELECT * FROM item WHERE id = %d LIMIT 1",
@@ -477,7 +254,7 @@ class Item extends Controller {
notice(t('Unable to locate original post.') . EOL);
if ($api_source)
return (['success' => false, 'message' => 'invalid post id']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -500,7 +277,7 @@ class Item extends Controller {
if (!$observer) {
$observer = App::get_observer();
if (!$observer) {
- $observer = anon_identity_init($_REQUEST);
+ $observer = anon_identity_init($_POST);
if ($observer) {
$moderated = true;
$remote_xchan = $remote_observer = $observer;
@@ -512,7 +289,7 @@ class Item extends Controller {
notice(t('Permission denied.') . EOL);
if ($api_source)
return (['success' => false, 'message' => 'permission denied']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -531,17 +308,17 @@ class Item extends Controller {
notice(t('Permission denied.') . EOL);
if ($api_source)
return (['success' => false, 'message' => 'permission denied']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
}
else {
- if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], ($webpage) ? 'write_pages' : 'post_wall')) {
+ if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], (intval($item_type) === ITEM_TYPE_POST) ? 'post_wall' : 'write_pages')) {
notice(t('Permission denied.') . EOL);
if ($api_source)
return (['success' => false, 'message' => 'permission denied']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -597,7 +374,7 @@ class Item extends Controller {
logger("mod_item: no channel.");
if ($api_source)
return (['success' => false, 'message' => 'no channel']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -607,6 +384,7 @@ class Item extends Controller {
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($channel['channel_hash'])
);
+
if ($r && count($r)) {
$owner_xchan = $r[0];
}
@@ -614,7 +392,7 @@ class Item extends Controller {
logger("mod_item: no owner.");
if ($api_source)
return (['success' => false, 'message' => 'no owner']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -648,17 +426,21 @@ class Item extends Controller {
$view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream');
$comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments');
- $public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true));
- if ($webpage)
- $public_policy = '';
- if ($public_policy)
+ $public_policy = '';
+
+ if (intval($item_type) === ITEM_TYPE_POST) {
+ $public_policy = ((!empty($_POST['public_policy'])) ? escape_tags($_POST['public_policy']) : map_scope($view_policy, true));
+ }
+
+ if ($public_policy) {
$private = 1;
+ }
if ($orig_post) {
$private = 0;
- // webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
- if ($webpage) {
- $acl->set_from_array($_REQUEST);
+ // Normal conversation items are not allowed to change ACL.
+ if (intval($item_type) !== ITEM_TYPE_POST) {
+ $acl->set_from_array($_POST);
}
else {
$acl->set($orig_post);
@@ -674,10 +456,10 @@ class Item extends Controller {
$coord = $orig_post['coord'];
$verb = $orig_post['verb'];
$app = $orig_post['app'];
- $title = escape_tags(trim($_REQUEST['title']));
- $summary = escape_tags(trim($_REQUEST['summary']));
- $body = trim($_REQUEST['body']);
- $item_flags = $orig_post['item_flags'];
+ $title = escape_tags(trim($_POST['title']));
+ $summary = escape_tags(trim($_POST['summary']));
+ $body = trim($_POST['body']);
+ $item_flags = $orig_post['item_flags'];
$item_origin = $orig_post['item_origin'];
$item_unseen = $orig_post['item_unseen'];
$item_starred = $orig_post['item_starred'];
@@ -691,7 +473,7 @@ class Item extends Controller {
$item_mentionsme = $orig_post['item_mentionsme'];
$item_nocomment = $orig_post['item_nocomment'];
$item_obscured = $orig_post['item_obscured'];
- $item_verified = $orig_post['item_verified'];
+ $item_verified = $orig_post['item_verified'];
$item_retained = $orig_post['item_retained'];
$item_rss = $orig_post['item_rss'];
$item_deleted = $orig_post['item_deleted'];
@@ -710,14 +492,15 @@ class Item extends Controller {
$thr_parent = $orig_post['thr_parent'];
$parent_mid = $orig_post['parent_mid'];
$plink = $orig_post['plink'];
+ $owner_hash = $orig_post['owner_xchan'];
}
else {
if (!$walltowall) {
- if ((array_key_exists('contact_allow', $_REQUEST))
- || (array_key_exists('group_allow', $_REQUEST))
- || (array_key_exists('contact_deny', $_REQUEST))
- || (array_key_exists('group_deny', $_REQUEST))) {
- $acl->set_from_array($_REQUEST);
+ if ((array_key_exists('contact_allow', $_POST))
+ || (array_key_exists('group_allow', $_POST))
+ || (array_key_exists('contact_deny', $_POST))
+ || (array_key_exists('group_deny', $_POST))) {
+ $acl->set_from_array($_POST);
}
elseif (!$api_source) {
@@ -732,16 +515,16 @@ class Item extends Controller {
}
- $location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : '');
- $coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : '');
- $verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : '');
- $title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : '');
- $summary = ((isset($_REQUEST['summary'])) ? escape_tags(trim($_REQUEST['summary'])) : '');
- $body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : '');
- $body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : '');
+ $location = ((isset($_POST['location'])) ? notags(trim($_POST['location'])) : '');
+ $coord = ((isset($_POST['coord'])) ? notags(trim($_POST['coord'])) : '');
+ $verb = ((isset($_POST['verb'])) ? notags(trim($_POST['verb'])) : '');
+ $title = ((isset($_POST['title'])) ? escape_tags(trim($_POST['title'])) : '');
+ $summary = ((isset($_POST['summary'])) ? escape_tags(trim($_POST['summary'])) : '');
+ $body = ((isset($_POST['body'])) ? trim($_POST['body']) : '');
+ $body .= ((isset($_POST['attachment'])) ? trim($_POST['attachment']) : '');
$postopts = '';
- $allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
+ $allow_empty = ((array_key_exists('allow_empty', $_POST)) ? intval($_POST['allow_empty']) : 0);
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
@@ -752,7 +535,7 @@ class Item extends Controller {
$private = intval($parent_item['item_private']);
$public_policy = $parent_item['public_policy'];
$owner_hash = $parent_item['owner_xchan'];
- $webpage = $parent_item['item_type'];
+ $item_type = $parent_item['item_type'];
}
@@ -763,7 +546,7 @@ class Item extends Controller {
info(t('Empty post discarded.') . EOL);
if ($api_source)
return (['success' => false, 'message' => 'no content']);
- if (x($_REQUEST, 'return'))
+ if (!empty($_POST['return']))
goaway(z_root() . "/" . $return_path);
killme();
}
@@ -771,15 +554,15 @@ class Item extends Controller {
if (feature_enabled($profile_uid, 'content_expire')) {
- if (x($_REQUEST, 'expire')) {
- $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']);
+ if (!empty($_POST['expire'])) {
+ $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_POST['expire']);
if ($expires <= datetime_convert())
$expires = NULL_DATE;
}
}
- $mimetype = ((isset($_REQUEST['mimetype'])) ? notags(trim($_REQUEST['mimetype'])) : '');
+ $mimetype = ((isset($_POST['mimetype'])) ? notags(trim($_POST['mimetype'])) : '');
if (!$mimetype)
$mimetype = 'text/bbcode';
@@ -813,7 +596,7 @@ class Item extends Controller {
$is_group = get_pconfig($profile_uid, 'system', 'group_actor');
- if ($is_group && $walltowall && !$walltowall_comment && !$webpage) {
+ if ($is_group && $walltowall && !$walltowall_comment && (intval($item_type) === ITEM_TYPE_POST)) {
$groupww = true;
$str_contact_allow = $owner_xchan['xchan_hash'];
$str_group_allow = '';
@@ -1012,42 +795,65 @@ class Item extends Controller {
}
$item_unseen = ((local_channel() != $profile_uid) ? 1 : 0);
- $item_wall = ((isset($_REQUEST['type']) && ($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment')) ? 1 : 0);
+ $item_wall = ((isset($_POST['type']) && ($_POST['type'] === 'wall' || $_POST['type'] === 'wall-comment')) ? 1 : 0);
$item_origin = (($origin) ? 1 : 0);
$item_consensus = (($consensus) ? 1 : 0);
$item_nocomment = (($nocomment) ? 1 : 0);
+ $comments_closed = (($nocomment) ? $comments_closed : NULL_DATE);
// determine if this is a wall post
+ if (in_array($item_type, [ITEM_TYPE_POST, ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE])) {
+ $item_wall = 1;
+ }
+
if ($parent) {
$item_wall = $parent_item['item_wall'];
}
- else {
- if (!$webpage) {
- $item_wall = 1;
- }
- }
-
- 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;
+
+ if (empty($owner_hash)) {
+ $owner_hash = $owner_xchan['xchan_hash'];
+ }
+
+ // Set the conversation target.
+ 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,
- 'answers' => $_REQUEST['poll_answers'],
- 'multiple_answers' => $_REQUEST['poll_multiple_answers'],
- 'expire_value' => $_REQUEST['poll_expire_value'],
- 'expire_unit' => $_REQUEST['poll_expire_unit']
+ 'answers' => $_POST['poll_answers'],
+ 'multiple_answers' => $_POST['poll_multiple_answers'],
+ 'expire_value' => $_POST['poll_expire_value'],
+ 'expire_unit' => $_POST['poll_expire_unit']
];
$obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]);
}
@@ -1060,7 +866,7 @@ class Item extends Controller {
$obj['id'] = $mid;
$obj['diaspora:guid'] = $uuid;
$obj['attributedTo'] = channel_url($channel);
- $obj['published'] = $created;
+ $obj['published'] = datetime_convert('UTC', 'UTC', $created, ATOM_TIME);
$obj['name'] = $title;
$datarray['obj'] = $obj;
@@ -1082,19 +888,13 @@ class Item extends Controller {
if ($parent_item)
$parent_mid = $parent_item['mid'];
-
// Fallback so that we always have a thr_parent
if (!$thr_parent)
$thr_parent = $mid;
-
$item_thread_top = ((!$parent) ? 1 : 0);
- if ((!$plink) && ($item_thread_top)) {
- $plink = $mid;
- }
-
if (isset($datarray['obj']) && $datarray['obj']) {
$datarray['obj']['id'] = $mid;
}
@@ -1132,7 +932,7 @@ class Item extends Controller {
$datarray['item_unseen'] = intval($item_unseen);
$datarray['item_wall'] = intval($item_wall);
$datarray['item_origin'] = intval($item_origin);
- $datarray['item_type'] = $webpage;
+ $datarray['item_type'] = $item_type;
$datarray['item_private'] = intval($private);
$datarray['item_thread_top'] = intval($item_thread_top);
$datarray['item_starred'] = intval($item_starred);
@@ -1157,7 +957,7 @@ class Item extends Controller {
$datarray['public_policy'] = $public_policy;
$datarray['comment_policy'] = map_scope($comment_policy);
$datarray['term'] = array_unique($post_tags, SORT_REGULAR);
- $datarray['plink'] = $plink;
+ $datarray['plink'] = $plink ?? $mid;
$datarray['route'] = $route;
// A specific ACL over-rides public_policy completely
@@ -1211,14 +1011,14 @@ class Item extends Controller {
call_hooks('post_local', $datarray);
- if (x($datarray, 'cancel')) {
+ if (!empty($datarray['cancel'])) {
logger('mod_item: post cancelled by plugin or duplicate suppressed.');
if ($return_path)
goaway(z_root() . "/" . $return_path);
if ($api_source)
return (['success' => false, 'message' => 'operation cancelled']);
$json = ['cancel' => 1];
- $json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
+ $json['reload'] = z_root() . '/' . $_POST['jsreload'];
echo json_encode($json);
killme();
}
@@ -1227,8 +1027,8 @@ class Item extends Controller {
if (mb_strlen($datarray['title']) > 191)
$datarray['title'] = mb_substr($datarray['title'], 0, 191);
- if ($webpage) {
- IConfig::Set($datarray, 'system', webpage_to_namespace($webpage),
+ if (intval($item_type) !== ITEM_TYPE_POST) {
+ IConfig::Set($datarray, 'system', item_type_to_namespace($item_type),
(($pagetitle) ? $pagetitle : basename($datarray['mid'])), true);
}
elseif ($namespace) {
@@ -1245,6 +1045,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)
@@ -1255,14 +1056,19 @@ 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);
- if ((x($_REQUEST, 'return')) && strlen($return_path)) {
+ if ((!empty($_POST['return'])) && strlen($return_path)) {
logger('return: ' . $return_path);
if ($return_path === 'hq') {
@@ -1281,6 +1087,7 @@ class Item extends Controller {
}
$post_id = $post['item_id'];
+ $approval_id = $post['approval_id'] ?? 0;
$datarray = $post['item'];
@@ -1355,6 +1162,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)
@@ -1365,6 +1173,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'];
@@ -1375,8 +1184,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');
@@ -1408,11 +1221,12 @@ class Item extends Controller {
$json = [
'success' => 1,
'id' => $post_id,
+ 'thr_parent_id' => $thr_parent_id,
'html' => conversation($item, $mode, true, 'r_preview'),
];
- if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload']))
- $json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
+ if (!empty($_POST['jsreload']))
+ $json['reload'] = z_root() . '/' . $_POST['jsreload'];
logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
@@ -1429,9 +1243,7 @@ class Item extends Controller {
if ((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
- 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))
);
@@ -1458,7 +1270,6 @@ class Item extends Controller {
$can_delete = true;
}
-
if (!($can_delete || $local_delete)) {
notice(t('Permission denied.') . EOL);
return;
@@ -1474,13 +1285,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);
@@ -1489,6 +1301,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']]);
+ }
}
}
@@ -1672,5 +1487,234 @@ class Item extends Controller {
}
}
+ private function init_zot_request() {
+
+ $item_id = argv(1);
+
+ if (!$item_id)
+ http_status_exit(404, 'Not found');
+
+ $portable_id = EMPTY_STR;
+
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
+ dbesc(ACTIVITY_FOLLOW),
+ dbesc(ACTIVITY_UNFOLLOW)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
+
+ $i = null;
+
+ // do we have the item (at all)?
+
+ $r = q("select parent_mid from item where uuid = '%s' $item_normal limit 1",
+ dbesc($item_id)
+ );
+
+ if (!$r) {
+ http_status_exit(404, 'Not found');
+ }
+
+ // process an authenticated fetch
+
+ $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR);
+ if ($sigdata['portable_id'] && $sigdata['header_valid']) {
+ $portable_id = $sigdata['portable_id'];
+ if (!check_channelallowed($portable_id)) {
+ http_status_exit(403, 'Permission denied');
+ }
+ if (!check_siteallowed($sigdata['signer'])) {
+ http_status_exit(403, 'Permission denied');
+ }
+ observer_auth($portable_id);
+
+ $i = q("select id as item_id, uid from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1",
+ dbesc($r[0]['parent_mid']),
+ dbesc($portable_id)
+ );
+ }
+ elseif (Config::get('system', 'require_authenticated_fetch', false)) {
+ http_status_exit(403, 'Permission denied');
+ }
+
+ // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
+ // with a bias towards those items owned by channels on this site (item_wall = 1)
+
+ $sql_extra = item_permissions_sql(0);
+
+ if (!$i) {
+ $i = q("select id as item_id, uid, item_private from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
+ dbesc($r[0]['parent_mid'])
+ );
+ }
+
+ if (!$i) {
+ http_status_exit(403, 'Forbidden');
+ }
+
+ $chan = channelx_by_n($i[0]['uid']);
+
+ if (!$chan) {
+ http_status_exit(404, 'Not found');
+ }
+
+ if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) {
+ http_status_exit(403, 'Forbidden');
+ }
+
+ $parents_str = ids_to_querystr($i, 'item_id');
+
+ // We won't need to check for privacy mismatches if the verified observer is also owner
+ $parent_item_private = ((isset($i[0]['item_private'])) ? " and item_private = " . intval($i[0]['item_private']) . " " : '');
+
+ $total = q("SELECT count(*) AS count FROM item WHERE parent = %d $parent_item_private $item_normal ",
+ intval($parents_str)
+ );
+
+ App::set_pager_total($total[0]['count']);
+ App::set_pager_itemspage(30);
+
+ if (App::$pager['total'] > App::$pager['itemspage']) {
+ // let mod conversation handle this request
+ App::$query_string = str_replace('item', 'conversation', App::$query_string);
+ $i = Activity::paged_collection_init(App::$pager['total'], App::$query_string);
+ as_return_and_die($i ,$chan);
+ }
+ else {
+ $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent = %d $parent_item_private $item_normal ORDER BY item.id",
+ intval($parents_str)
+ );
+
+ xchan_query($items, true);
+ $items = fetch_post_tags($items, true);
+
+ $i = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection', App::$pager['total']);
+ }
+
+ if ($portable_id && (!intval($items[0]['item_private']))) {
+ $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($items[0]['uid']),
+ dbesc($portable_id)
+ );
+ if (!$c) {
+ ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
+ }
+ }
+
+ as_return_and_die($i ,$chan);
+ }
+
+ private function init_as_request() {
+
+ $item_id = argv(1);
+ if (!$item_id)
+ http_status_exit(404, 'Not found');
+
+ $portable_id = EMPTY_STR;
+
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
+ dbesc(ACTIVITY_FOLLOW),
+ dbesc(ACTIVITY_UNFOLLOW)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
+
+ $i = null;
+
+ // do we have the item (at all)?
+ // add preferential bias to item owners (item_wall = 1)
+
+ $r = q("select * from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
+ dbesc($item_id)
+ );
+
+ if (!$r) {
+ http_status_exit(404, 'Not found');
+ }
+
+ // process an authenticated fetch
+
+ $sigdata = HTTPSig::verify(EMPTY_STR);
+ if ($sigdata['portable_id'] && $sigdata['header_valid']) {
+ $portable_id = $sigdata['portable_id'];
+ if (!check_channelallowed($portable_id)) {
+ http_status_exit(403, 'Permission denied');
+ }
+ if (!check_siteallowed($sigdata['signer'])) {
+ http_status_exit(403, 'Permission denied');
+ }
+ observer_auth($portable_id);
+
+ $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ",
+ dbesc($r[0]['parent_mid']),
+ dbesc($portable_id)
+ );
+ }
+ elseif (Config::get('system', 'require_authenticated_fetch', false)) {
+ http_status_exit(403, 'Permission denied');
+ }
+
+ // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
+ // with a bias towards those items owned by channels on this site (item_wall = 1)
+
+ $sql_extra = item_permissions_sql(0);
+
+ if (!$i) {
+ $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
+ dbesc($r[0]['parent_mid'])
+ );
+ }
+
+ $bear = Activity::token_from_request();
+ if ($bear) {
+ logger('bear: ' . $bear, LOGGER_DEBUG);
+ if (!$i) {
+ $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
+ dbesc($bear)
+ );
+ if ($t) {
+ $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
+ dbesc($item_id),
+ intval($t[0]['iid'])
+ );
+ }
+ }
+ }
+
+ if (!$i) {
+ http_status_exit(403, 'Forbidden');
+ }
+
+ // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it.
+
+ xchan_query($r, true);
+ $items = fetch_post_tags($r, false);
+
+ $chan = channelx_by_n($items[0]['uid']);
+
+ if (!$chan)
+ http_status_exit(404, 'Not found');
+
+ if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream'))
+ http_status_exit(403, 'Forbidden');
+
+ $i = Activity::encode_item($items[0]);
+
+ if (!$i)
+ http_status_exit(404, 'Not found');
+
+ if ($portable_id && (!intval($items[0]['item_private']))) {
+ $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($items[0]['uid']),
+ dbesc($portable_id)
+ );
+ if (!$c) {
+ ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
+ }
+ }
+
+ as_return_and_die($i ,$chan);
+
+ }
}
diff --git a/Zotlabs/Module/Lang.php b/Zotlabs/Module/Lang.php
index fe185ebea..1eeb29363 100644
--- a/Zotlabs/Module/Lang.php
+++ b/Zotlabs/Module/Lang.php
@@ -65,8 +65,22 @@ class Lang extends Controller {
}
nav_set_selected('Language');
- return lang_selector();
+ return $this->lang_selector();
}
+ private function lang_selector(): string
+ {
+ $lang_options = language_list();
+ array_unshift($lang_options, t('default'));
+
+ $tpl = get_markup_template('lang_selector.tpl');
+
+ return replace_macros($tpl, [
+ '$title' => t('Select an alternate language'),
+ '$langs' => array($lang_options, App::$language),
+
+ ]);
+ }
+
}
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index d493742e7..52c559a17 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -22,9 +22,9 @@ class Like extends Controller {
'like' => 'Like',
'dislike' => 'Dislike',
'announce' => ACTIVITY_SHARE,
- 'attendyes' => 'Accept',
- 'attendno' => 'Reject',
- 'attendmaybe' => 'TentativeAccept'
+ 'accept' => 'Accept',
+ 'reject' => 'Reject',
+ 'tentativeaccept' => 'TentativeAccept'
];
// unlike (etc.) reactions are an undo of positive reactions, rather than a negative action.
@@ -52,43 +52,31 @@ class Like extends Controller {
profile_load($parts[0]);
}
- $item_normal = item_normal();
-
if ($page_mode === 'list') {
+ $item_normal = item_normal();
+
$items = q("SELECT item.*, item.id AS item_id FROM item
WHERE uid = %d $item_normal
AND parent = %d",
intval($arr['item']['uid']),
intval($arr['item']['parent'])
);
+
xchan_query($items, true);
$items = fetch_post_tags($items, true);
$items = conv_sort($items, 'commented');
}
else {
- $activities = q("SELECT item.*, item.id AS item_id FROM item
- WHERE uid = %d $item_normal
- AND thr_parent = '%s'
- AND verb IN ('%s', '%s', '%s', '%s', '%s', '%s', 'Accept', 'Reject', 'TentativeAccept')",
- intval($arr['item']['uid']),
- dbesc($arr['item']['mid']),
- dbesc('Like'),
- dbesc('Dislike'),
- dbesc(ACTIVITY_SHARE),
- dbesc(ACTIVITY_ATTEND),
- dbesc(ACTIVITY_ATTENDNO),
- dbesc(ACTIVITY_ATTENDMAYBE)
- );
- xchan_query($activities, true);
- $items = array_merge([$arr['item']], $activities);
- $items = fetch_post_tags($items, true);
+ $item = item_by_item_id($arr['item']['id'], $arr['item']['parent']);
+ xchan_query($item, true);
+ $item = fetch_post_tags($item, true);
}
$ret = [
'success' => 1,
'orig_id' => $arr['orig_item_id'], //this is required for pubstream items where $item_id != $item['id']
'id' => $arr['item']['id'],
- 'html' => conversation($items, $conv_mode, true, $page_mode),
+ 'html' => conversation($item, $conv_mode, true, $page_mode),
];
// mod photos
@@ -284,7 +272,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 +375,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'])
@@ -483,11 +474,11 @@ class Like extends Controller {
$bodyverb = t('%1$s likes %2$s\'s %3$s');
if ($verb === 'dislike')
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
- if ($verb === 'attendyes')
+ if ($verb === 'accept')
$bodyverb = t('%1$s is attending %2$s\'s %3$s');
- if ($verb === 'attendno')
+ if ($verb === 'reject')
$bodyverb = t('%1$s is not attending %2$s\'s %3$s');
- if ($verb === 'attendmaybe')
+ if ($verb === 'tentativeaccept')
$bodyverb = t('%1$s may attend %2$s\'s %3$s');
if (!isset($bodyverb))
@@ -559,6 +550,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
@@ -569,11 +561,12 @@ class Like extends Controller {
call_hooks('post_local_end', $arr);
- if ($is_rsvp && in_array($verb, ['attendyes', 'attendmaybe'])) {
+ if ($is_rsvp && in_array($verb, ['accept', 'tentativeaccept'])) {
event_addtocal($item_id, local_channel());
}
+/* Item sync is now done in item_store()
$r = q("select * from item where id = %d",
intval($post_id)
);
@@ -582,7 +575,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 +602,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/Login.php b/Zotlabs/Module/Login.php
index 721ac15ac..f5a83a91a 100644
--- a/Zotlabs/Module/Login.php
+++ b/Zotlabs/Module/Login.php
@@ -5,12 +5,28 @@ namespace Zotlabs\Module;
class Login extends \Zotlabs\Web\Controller {
function get() {
- if(local_channel())
+ if (local_channel()) {
goaway(z_root());
- if(remote_channel() && $_SESSION['atoken'])
+ }
+
+ if (remote_channel() && $_SESSION['atoken']) {
goaway(z_root());
+ }
+
+ if (!empty($_GET['retry'])) {
+ notice( t('Login failed.') . EOL );
+ }
+
+ $o = '<div class="generic-content-wrapper">';
+ $o .= '<div class="section-title-wrapper">';
+ $o .= '<h2 class="">' . t('Login') . '</h2>';
+ $o .= '</div>';
+ $o .= '<div class="section-content-wrapper">';
+ $o .= login(true);
+ $o .= '</div>';
+ $o .= '</div>';
- return login(true);
+ return $o;
}
}
diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php
index 8259f7d39..122d90b1b 100644
--- a/Zotlabs/Module/Magic.php
+++ b/Zotlabs/Module/Magic.php
@@ -11,37 +11,39 @@ class Magic extends Controller {
function init() {
- $ret = [
- 'success' => false,
- 'url' => '',
- 'message' => ''
- ];
-
logger('mod_magic: invoked', LOGGER_DEBUG);
- logger('args: ' . print_r($_REQUEST,true),LOGGER_DATA);
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $data = $_POST;
+ } elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
+ $data = $_GET;
+ } else {
+ http_status_exit(405, 'Method Not Allowed');
+ }
+
+ logger('request method: ' . print_r($_SERVER['REQUEST_METHOD'], true), LOGGER_DATA);
+ logger('args: ' . print_r($data, true), LOGGER_DATA);
- $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : '');
- $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : '');
- $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
- $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
- $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
- $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
+ $bdest = $data['bdest'] ?? '';
+ $owa = $data['owa'] ?? 0;
+ $delegate = $data['delegate'] ?? '';
// bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing
- if ($bdest) {
- $dest = hex2bin($bdest);
+ if (!$bdest) {
+ http_status_exit(400, 'Bad Request');
}
+ $dest = hex2bin($bdest);
$parsed = parse_url($dest);
- if (! $parsed) {
- goaway($dest);
+ if (!$parsed) {
+ http_status_exit(400, 'Bad Request');
}
- $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (isset($parsed['port']) ? ':' . $parsed['port'] : '');
- $owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa');
+ $basepath = unparse_url($parsed, ['scheme', 'host', 'port']);
+
+ $owapath = SConfig::get($basepath, 'system', 'openwebauth', $basepath . '/owa');
// This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating.
// By default, we'll proceed without asking.
@@ -53,12 +55,14 @@ class Magic extends Controller {
];
call_hooks('magic_auth',$arr);
+
$dest = $arr['destination'];
- if (! $arr['proceed']) {
+
+ if (!$arr['proceed']) {
goaway($dest);
}
- if((get_observer_hash()) && (stripos($dest,z_root()) === 0)) {
+ if (get_observer_hash() && str_starts_with($dest, z_root())) {
// We are already authenticated on this site and a registered observer.
// First check if this is a delegate request on the local system and process accordingly.
@@ -106,29 +110,43 @@ class Magic extends Controller {
$headers['Content-Type'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string();
$headers['Host'] = $parsed['host'];
- $headers['(request-target)'] = 'get ' . '/owa';
+ $headers['(request-target)'] = 'get /owa';
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
$redirects = 0;
+
$x = z_fetch_url($owapath, false, $redirects, ['headers' => $headers]);
logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA);
+
if ($x['success']) {
$j = json_decode($x['body'],true);
if ($j['success'] && $j['encrypted_token']) {
// decrypt the token using our private key
$token = '';
- openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']);
+ openssl_private_decrypt(base64url_decode($j['encrypted_token']), $token, $channel['channel_prvkey']);
$x = strpbrk($dest,'?&');
// redirect using the encrypted token which will be exchanged for an authenticated session
- $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
+ $args = (($x) ? '&owt=' . $token : '?owt=' . $token) . (($delegate) ? '&delegate=1' : '');
goaway($dest . $args);
}
+ else {
+ $o = '<h1>OWA ERROR</h1>';
+ if (!empty($j['message'])) {
+ $o .= '<h2>' . $j['message'] . '</h2>';
+ }
+ $o .= '<a href=' . $dest . '>' . $dest . '</a>';
+
+ echo $o;
+ killme();
+
+ }
}
}
}
goaway($dest);
+
}
}
diff --git a/Zotlabs/Module/Mitem.php b/Zotlabs/Module/Mitem.php
index ac7470e13..81787f8c4 100644
--- a/Zotlabs/Module/Mitem.php
+++ b/Zotlabs/Module/Mitem.php
@@ -184,8 +184,8 @@ class Mitem extends \Zotlabs\Web\Controller {
'$nick' => $which,
'$sys' => \App::$is_sys
));
-
- $o .= replace_macros(get_markup_template('mitemlist.tpl'),array(
+
+ return replace_macros(get_markup_template('mitemlist.tpl'),array(
'$title' => t('Menu:'),
'$create' => $create,
'$nametitle' => t('Link Name'),
@@ -204,29 +204,27 @@ class Mitem extends \Zotlabs\Web\Controller {
'$hintedit' => t('Edit this menu item'),
'$nick' => $which,
));
-
- return $o;
}
-
-
+
+
if(argc() > 3) {
if(intval(argv(3))) {
-
+
$m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1",
intval(argv(3)),
intval($owner)
);
-
+
if(! $m) {
notice( t('Menu item not found.') . EOL);
goaway(z_root() . '/menu/'. $which . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
-
+
$mitem = $m[0];
-
+
$lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock');
-
+
if(argc() == 5 && argv(4) == 'drop') {
menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']);
$r = menu_del_item($mitem['mitem_menu_id'], $owner, intval(argv(3)));
@@ -235,12 +233,12 @@ class Mitem extends \Zotlabs\Web\Controller {
info( t('Menu item deleted.') . EOL);
else
notice( t('Menu item could not be deleted.'). EOL);
-
+
goaway(z_root() . '/mitem/' . $which . '/' . $mitem['mitem_menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
-
+
// edit menu item
- $o = replace_macros(get_markup_template('mitemedit.tpl'), array(
+ return replace_macros(get_markup_template('mitemedit.tpl'), array(
'$header' => t('Edit Menu Element'),
'$menu_id' => \App::$data['menu']['menu_id'],
'$permissions' => t('Menu Item Permissions'),
@@ -261,10 +259,8 @@ class Mitem extends \Zotlabs\Web\Controller {
'$menu_names' => $menu_names,
'$nick' => $which
));
-
- return $o;
}
}
}
-
+
}
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
index ed2a1e4f9..1d8f65348 100644
--- a/Zotlabs/Module/Moderate.php
+++ b/Zotlabs/Module/Moderate.php
@@ -67,15 +67,15 @@ class Moderate extends \Zotlabs\Web\Controller {
$item['item_blocked'] = 0;
item_update_parent_commented($item);
- notice( t('Item approved') . EOL);
+ info(t('Item approved') . EOL);
}
elseif($action === 'drop') {
// TODO: not implemented
// 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);
- notice( t('Item deleted') . EOL);
+ drop_item($post_id);
+ info(t('Item deleted') . EOL);
}
// refetch the item after changes have been made
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index 3ea813547..f95d92fe2 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -70,17 +70,19 @@ class Network extends \Zotlabs\Web\Controller {
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
- $order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
+ $order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
switch($order) {
- case 0:
- $order = 'comment';
+ case 'commented':
+ $ordering = 'commented';
break;
- case 1:
- $order = 'post';
+ case 'created':
+ $ordering = 'created';
break;
- case 2:
+ case 'unthreaded':
$nouveau = true;
break;
+ default:
+ $ordering = 'created';
}
$search = $_GET['search'] ?? '';
@@ -92,7 +94,7 @@ class Network extends \Zotlabs\Web\Controller {
}
if($datequery)
- $order = 'post';
+ $order = 'created';
// filter by collection (e.g. group)
@@ -274,36 +276,18 @@ class Network extends \Zotlabs\Web\Controller {
elseif($pf && $unseen && $nouveau) {
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
- if(! ($vnotify & VNOTIFY_LIKE))
+ $likes_sql = '';
+ if (!($vnotify & VNOTIFY_LIKE)) {
$likes_sql = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ }
// This is for nouveau view public forum cid queries (if a forum notification is clicked)
- //$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
- //intval(local_channel()),
- //intval(TERM_FORUM),
- //dbesc($cid_r[0]['xchan_name'])
- //);
-
- //$p_str = ids_to_querystr($p, 'parent');
+ $sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) AND item_unseen = 1 AND verb != 'Announce' $likes_sql ";
- $p_sql = '';
- //if($p_str)
- //$p_sql = " OR item.parent IN ( $p_str ) ";
-
- $sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 $likes_sql ";
}
else {
// This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)
- $ttype = (($pf) ? TERM_FORUM : TERM_MENTION);
-
- $p1 = dbq("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal ");
- $p2 = dbq("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'");
-
- $p_str = ids_to_querystr(array_merge($p1, $p2), 'parent');
- if(! $p_str)
- killme();
-
- $sql_extra = " AND item.parent IN ( $p_str ) ";
+ $sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) ";
}
}
@@ -393,10 +377,10 @@ class Network extends \Zotlabs\Web\Controller {
}
if ($dm) {
- $sql_extra .= ' AND item_private = 2 ';
+ $sql_extra .= ' AND item.item_private = 2 ';
}
else {
- $sql_extra .= ' AND item_private IN (0, 1) ';
+ $sql_extra .= ' AND item.item_private IN (0, 1) ';
}
@@ -445,10 +429,12 @@ class Network extends \Zotlabs\Web\Controller {
$abook_uids = ' and abook.abook_channel = ' . local_channel() . ' ';
$uids = ' and item.uid = ' . local_channel() . ' ';
- if(feature_enabled(local_channel(), 'network_list_mode'))
+ $page_mode = 'client';
+
+ $blog_mode = feature_enabled(local_channel(), 'network_list_mode');
+ if ($blog_mode) {
$page_mode = 'list';
- else
- $page_mode = 'client';
+ }
$parents_str = '';
@@ -472,11 +458,12 @@ class Network extends \Zotlabs\Web\Controller {
if($nouveau && $load) {
// "New Item View" - show all items unthreaded in reverse created date order
- $items = dbq("SELECT item.*, item.id AS item_id, created FROM item
+ $items = dbq("SELECT item.*, item.id AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
$net_query
WHERE true $uids $item_normal
and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ AND item.verb NOT IN ('Add', 'Remove')
$sql_extra $sql_options $sql_nets
$net_query2
ORDER BY item.created DESC $pager_sql "
@@ -492,13 +479,6 @@ class Network extends \Zotlabs\Web\Controller {
}
elseif($update) {
- // Normal conversation view
-
- if($order === 'post')
- $ordering = 'created';
- else
- $ordering = 'commented';
-
if($load) {
// Fetch a page full of parent items for this page
$r = dbq("SELECT item.parent AS item_id FROM item
@@ -527,12 +507,7 @@ class Network extends \Zotlabs\Web\Controller {
// Then fetch all the children of the parents that are on this page
if($r) {
- $parents_str = ids_to_querystr($r, 'item_id');
- $items = dbq("SELECT item.*, item.id AS item_id FROM item
- WHERE true $uids $item_normal
- AND item.parent IN ( $parents_str )
- $sql_extra "
- );
+ $items = items_by_parent_ids($r, blog_mode: $blog_mode);
xchan_query($items, true);
$items = fetch_post_tags($items, true);
diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php
index 0af2ec93a..7a7becbc8 100644
--- a/Zotlabs/Module/Notify.php
+++ b/Zotlabs/Module/Notify.php
@@ -1,8 +1,8 @@
<?php
namespace Zotlabs\Module;
-use \Zotlabs\Lib\PConfig;
-use \Zotlabs\Web\Controller;
+use Zotlabs\Lib\PConfig;
+use Zotlabs\Web\Controller;
class Notify extends Controller {
diff --git a/Zotlabs/Module/OAuth2TestVehicle.php b/Zotlabs/Module/OAuth2TestVehicle.php
index 5ae278e8c..57cda3c28 100644
--- a/Zotlabs/Module/OAuth2TestVehicle.php
+++ b/Zotlabs/Module/OAuth2TestVehicle.php
@@ -31,8 +31,8 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller {
$_SESSION['api_response'] = (x($_SESSION, 'api_response') ? $_SESSION['api_response'] : '');
}
function get() {
-
- $o .= replace_macros(get_markup_template('oauth2testvehicle.tpl'), array(
+
+ $output = replace_macros(get_markup_template('oauth2testvehicle.tpl'), array(
'$baseurl' => z_root(),
'$api_response' => $_SESSION['api_response'],
/*
@@ -97,8 +97,10 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller {
)
)
));
+
$_SESSION['success'] = '';
- return $o;
+
+ return $output;
}
function post() {
diff --git a/Zotlabs/Module/Oauth.php b/Zotlabs/Module/Oauth.php
index 061296257..6063c7738 100644
--- a/Zotlabs/Module/Oauth.php
+++ b/Zotlabs/Module/Oauth.php
@@ -103,7 +103,8 @@ class Oauth extends Controller {
if((argc() > 1) && (argv(1) === 'add')) {
$tpl = get_markup_template("oauth_edit.tpl");
- $o .= replace_macros($tpl, array(
+
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$title' => t('Add application'),
'$submit' => t('Submit'),
@@ -114,7 +115,6 @@ class Oauth extends Controller {
'$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')),
'$icon' => array('icon', t('Icon url'), '', t('Optional')),
));
- return $o;
}
if((argc() > 2) && (argv(1) === 'edit')) {
@@ -129,7 +129,7 @@ class Oauth extends Controller {
$app = $r[0];
$tpl = get_markup_template("oauth_edit.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$title' => t('Add application'),
'$submit' => t('Update'),
@@ -140,7 +140,6 @@ class Oauth extends Controller {
'$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''),
'$icon' => array('icon', t('Icon url'), $app['icon'], ''),
));
- return $o;
}
if((argc() > 2) && (argv(1) === 'delete')) {
@@ -163,7 +162,8 @@ class Oauth extends Controller {
$tpl = get_markup_template("oauth.tpl");
- $o .= replace_macros($tpl, array(
+
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$baseurl' => z_root(),
'$title' => t('Connected OAuth Apps'),
@@ -175,8 +175,6 @@ class Oauth extends Controller {
'$remove' => t('Remove authorization'),
'$apps' => $r,
));
- return $o;
-
}
}
diff --git a/Zotlabs/Module/Oauth2.php b/Zotlabs/Module/Oauth2.php
index 4b0b1991e..7aadd91bc 100644
--- a/Zotlabs/Module/Oauth2.php
+++ b/Zotlabs/Module/Oauth2.php
@@ -108,7 +108,8 @@ class Oauth2 extends Controller {
if((argc() > 1) && (argv(1) === 'add')) {
$tpl = get_markup_template("oauth2_edit.tpl");
- $o .= replace_macros($tpl, array(
+
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$title' => t('Add OAuth2 application'),
'$submit' => t('Submit'),
@@ -119,7 +120,6 @@ class Oauth2 extends Controller {
'$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application sepcifically requires this')),
'$scope' => array('scope', t('Authorization scope'), '', t('leave blank unless your application sepcifically requires this')),
));
- return $o;
}
if((argc() > 2) && (argv(1) === 'edit')) {
@@ -136,7 +136,7 @@ class Oauth2 extends Controller {
$app = $r[0];
$tpl = get_markup_template("oauth2_edit.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$title' => t('Add application'),
'$submit' => t('Update'),
@@ -147,7 +147,6 @@ class Oauth2 extends Controller {
'$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application specifically requires this')),
'$scope' => array('scope', t('Authorization scope'), $app['scope'], t('leave blank unless your application specifically requires this')),
));
- return $o;
}
if((argc() > 2) && (argv(1) === 'delete')) {
@@ -184,7 +183,8 @@ class Oauth2 extends Controller {
);
$tpl = get_markup_template("oauth2.tpl");
- $o .= replace_macros($tpl, array(
+
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$baseurl' => z_root(),
'$title' => t('Connected OAuth2 Apps'),
@@ -196,8 +196,6 @@ class Oauth2 extends Controller {
'$remove' => t('Remove authorization'),
'$apps' => $r,
));
- return $o;
-
}
}
diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php
index 37a46a23e..201e5a06f 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -23,6 +23,7 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $url)
http_status_exit(404, 'Not found');
+ $arr = [];
$maxwidth = $_REQUEST['maxwidth'] ?? 0;
$maxheight = $_REQUEST['maxheight'] ?? 0;
$format = $_REQUEST['format'] ?? '';
diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php
index 85467d4f4..254b1c7d1 100644
--- a/Zotlabs/Module/Owa.php
+++ b/Zotlabs/Module/Owa.php
@@ -18,96 +18,97 @@ use Zotlabs\Web\Controller;
class Owa extends Controller {
- function init() {
+ public function init(): void
+ {
$ret = [ 'success' => false ];
- if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
- $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
+ if (!$this->validateAuthorizationHeader()) {
+ $this->error('Missing or invalid authorization header.');
}
- if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
- $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
- if ($sigblock) {
- $keyId = $sigblock['keyId'];
- $parsed = parse_url($keyId);
- if (str_starts_with($parsed['scheme'],'http')) {
- unset($parsed['fragment']);
- unset($parsed['query']);
- $keyId = unparse_url($parsed);
- }
- else {
- $keyId = str_replace('acct:', '', $keyId);
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_REMOTE_USER'];
+
+ $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
+ if ($sigblock) {
+ $keyId = $sigblock['keyId'];
+ $parsed = parse_url($keyId);
+ if (str_starts_with($parsed['scheme'],'http')) {
+ unset($parsed['fragment']);
+ unset($parsed['query']);
+ $keyId = unparse_url($parsed);
+ }
+ else {
+ $keyId = str_replace('acct:', '', $keyId);
+ }
+ if ($keyId) {
+ $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
+ AND hubloc_deleted = 0 AND xchan_pubkey != ''
+ ORDER BY hubloc_id DESC",
+ dbesc($keyId),
+ dbesc($keyId),
+ dbesc($keyId)
+ );
+ if (! $r) {
+ $found = discover_by_webbie($keyId);
+ logger('found = ' . print_r($found, true));
+ if ($found) {
+ $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
+ dbesc($keyId),
+ dbesc($keyId),
+ dbesc($keyId)
+ );
+ }
}
- if ($keyId) {
- $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
- AND hubloc_deleted = 0 AND xchan_pubkey != ''
- ORDER BY hubloc_id DESC",
- dbesc($keyId),
- dbesc($keyId),
- dbesc($keyId)
- );
- if (! $r) {
+
+ if ($r) {
+ foreach ($r as $hubloc) {
+ $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
+ if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
+ logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
+ logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
+ $ret['success'] = true;
+ $token = random_string(32);
+ Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
+ $result = '';
+ openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
+ $ret['encrypted_token'] = base64url_encode($result);
+ break;
+ } else {
+ logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
+ }
+ }
+
+ if (!$ret['success']) {
+
+ // Possible a reinstall?
+ // In this case we probably already have an old hubloc
+ // but not the new one yet.
+
$found = discover_by_webbie($keyId);
- logger('found = ' . print_r($found, true));
+
if ($found) {
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
- dbesc($keyId),
- dbesc($keyId),
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
+ dbesc(str_replace('acct:', '', $keyId)),
dbesc($keyId)
);
- }
- }
-
- if ($r) {
- foreach ($r as $hubloc) {
- $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
- if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
- logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
- logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
- $ret['success'] = true;
- $token = random_string(32);
- Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
- $result = '';
- openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
- $ret['encrypted_token'] = base64url_encode($result);
- break;
- } else {
- logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
- }
- }
- if (!$ret['success']) {
-
- // Possible a reinstall?
- // In this case we probably already have an old hubloc
- // but not the new one yet.
-
- $found = discover_by_webbie($keyId);
-
- if ($found) {
- $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
- dbesc(str_replace('acct:', '', $keyId)),
- dbesc($keyId)
- );
-
- if ($r) {
- $verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
- if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
- logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
- logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
- $ret['success'] = true;
- $token = random_string(32);
- Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
- $result = '';
- openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
- $ret['encrypted_token'] = base64url_encode($result);
- } else {
- logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
- }
+ if ($r) {
+ $verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
+ if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
+ logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
+ logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
+ $ret['success'] = true;
+ $token = random_string(32);
+ Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
+ $result = '';
+ openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
+ $ret['encrypted_token'] = base64url_encode($result);
+ } else {
+ logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
}
}
}
@@ -118,4 +119,33 @@ class Owa extends Controller {
json_return_and_die($ret,'application/x-zot+json');
}
+
+ private function validateAuthorizationHeader(): bool
+ {
+ if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
+ $auth = trim($_SERVER['HTTP_AUTHORIZATION']);
+ } else if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
+ $auth = trim($_SERVER['REDIRECT_REMOTE_USER']);
+ } else {
+ return false;
+ }
+
+ return strncmp($auth, 'Signature', 9) === 0;
+ }
+
+ /**
+ * Terminates the request, and return a json error response.
+ *
+ * @Note This function does not return!
+ *
+ * @param string $msg The error message for the response.
+ */
+ private function error(string $msg): void {
+ $ret = [
+ 'success' => false,
+ 'message' => $msg
+ ];
+
+ json_return_and_die($ret,'application/x-zot+json');
+ }
}
diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php
index 8a698005a..a4ee5eaa2 100644
--- a/Zotlabs/Module/Page.php
+++ b/Zotlabs/Module/Page.php
@@ -183,9 +183,7 @@ class Page extends \Zotlabs\Web\Controller {
if($r[0]['mimetype'] === 'application/x-pdl')
\App::$page['pdl_content'] = true;
- $o .= prepare_page($r[0]);
- return $o;
-
+ return prepare_page($r[0]);
}
}
diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php
index e0bbc31d0..aa512e6da 100644
--- a/Zotlabs/Module/Pdledit.php
+++ b/Zotlabs/Module/Pdledit.php
@@ -51,7 +51,7 @@ class Pdledit extends Controller {
if(argc() > 1)
$module = 'mod_' . argv(1) . '.pdl';
else {
- $o .= '<div class="generic-content-wrapper-styled">';
+ $o = '<div class="generic-content-wrapper-styled">';
$o .= '<h1>' . t('Edit System Page Description') . '</h1>';
$edited = [];
diff --git a/Zotlabs/Module/Permcat.php b/Zotlabs/Module/Permcat.php
index 064c9cefb..0335c7bc6 100644
--- a/Zotlabs/Module/Permcat.php
+++ b/Zotlabs/Module/Permcat.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
-use \Zotlabs\Lib as Zlib;
+use Zotlabs\Lib as Zlib;
class Permcat extends \Zotlabs\Web\Controller {
@@ -22,4 +22,4 @@ class Permcat extends \Zotlabs\Web\Controller {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 870a2cb79..5f6162ba7 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -557,7 +557,9 @@ class Photos extends \Zotlabs\Web\Controller {
$can_post = false;
$visitor = 0;
-
+ $link_item = null;
+ $like = null;
+ $dislike = null;
$owner_uid = \App::$data['channel']['channel_id'];
$owner_aid = \App::$data['channel']['channel_account_id'];
@@ -965,7 +967,6 @@ class Photos extends \Zotlabs\Web\Controller {
$map = null;
if($linked_items) {
-
xchan_query($linked_items);
$linked_items = fetch_post_tags($linked_items,true);
@@ -1103,26 +1104,14 @@ class Photos extends \Zotlabs\Web\Controller {
$alike = array();
$dlike = array();
- $like = '';
- $dislike = '';
-
- $conv_responses = array(
- 'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
- 'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
- );
-
if($r) {
- foreach($r as $item) {
- builtin_activity_puller($item, $conv_responses);
- }
-
$like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : '');
$like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : '');
if(is_array($like_list) && (count($like_list) > MAX_LIKERS)) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
- array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
+ array_push($like_list_part, '<a href="#" data-bs-toggle="modal" data-bs-target="#likeModal-' . $link_item['id'] . '"><b>' . t('View all') . '</b></a>');
} else {
$like_list_part = '';
}
@@ -1134,7 +1123,7 @@ class Photos extends \Zotlabs\Web\Controller {
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (is_array($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
- array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
+ array_push($dislike_list_part, '<a href="#" data-bs-toggle="modal" data-bs-target="#dislikeModal-' . $link_item['id'] . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}
@@ -1217,12 +1206,17 @@ class Photos extends \Zotlabs\Web\Controller {
$like_e = $like;
$dislike_e = $dislike;
$paginate = paginate();
+ $responses = [];
- $response_verbs = array('like');
- if(feature_enabled($owner_uid,'dislike'))
- $response_verbs[] = 'dislike';
+ if ($link_item) {
+ $response_verbs = ['like'];
- $responses = get_responses($conv_responses,$response_verbs,'',$link_item);
+ if(feature_enabled($owner_uid,'dislike')) {
+ $response_verbs[] = 'dislike';
+ }
+
+ $responses = get_responses($response_verbs, $link_item);
+ }
$hookdata = [
'onclick' => '$.colorbox({href: \'' . $photo['href'] . '\'}); return false;',
diff --git a/Zotlabs/Module/Pin.php b/Zotlabs/Module/Pin.php
index de3c75622..14a45c10d 100644
--- a/Zotlabs/Module/Pin.php
+++ b/Zotlabs/Module/Pin.php
@@ -29,8 +29,9 @@ class Pin extends \Zotlabs\Web\Controller {
if(! $observer)
http_status_exit(403, 'Forbidden');
- $r = q("SELECT * FROM item WHERE id = %d AND id = parent AND item_private = 0 LIMIT 1",
- $item_id
+ $r = q("SELECT * FROM item WHERE id = %d AND uid = %d AND id = parent AND item_private = 0 LIMIT 1",
+ intval($item_id),
+ intval(local_channel())
);
if(! $r) {
notice(t('Unable to locate original post.'));
diff --git a/Zotlabs/Module/Profperm.php b/Zotlabs/Module/Profperm.php
index 842197415..4594728b1 100644
--- a/Zotlabs/Module/Profperm.php
+++ b/Zotlabs/Module/Profperm.php
@@ -55,6 +55,8 @@ class Profperm extends \Zotlabs\Web\Controller {
}
+ $o = '';
+
if((argc() > 1) && (intval(argv(1)))) {
$r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1",
intval(argv(1)),
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index 6d8edf4d8..99b8ab587 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -183,6 +183,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
$sql_extra_order = " ORDER BY item.created DESC ";
$thread_top = '';
+
}
$net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : '');
@@ -196,17 +197,15 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($update) {
- $ordering = Config::Get('system', 'pubstream_ordering', 'commented');
+ $ordering = Config::Get('system', 'pubstream_ordering', 'created');
if($load) {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
- left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql
$item_normal
- and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2",
dbesc($mid)
@@ -216,11 +215,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
// Fetch a page full of parent items for this page
$r = dbq("SELECT parent AS item_id FROM item
left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
- left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.item_private = 0 $thread_top
$uids $site_firehose_sql
$item_normal
- and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2
ORDER BY $ordering DESC $pager_sql "
@@ -231,10 +228,8 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
- left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql $item_normal_update $simple_update
- and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2",
dbesc($mid)
@@ -243,11 +238,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
else {
$r = dbq("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
- left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.item_private = 0 $thread_top
$uids $site_firehose_sql $item_normal_update
$simple_update
- and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2"
);
@@ -258,15 +251,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$parents_str = '';
if($r) {
-
- $parents_str = ids_to_querystr($r,'item_id');
-
- $items = dbq("SELECT item.*, item.id AS item_id FROM item
- WHERE true $uids $item_normal
- AND item.parent IN ( $parents_str )
- $sql_extra $sql_extra_order"
- );
-
+ $items = items_by_parent_ids($r);
// use effective_uid param of xchan_query to help sort out comment permission
// for sys_channel owned items.
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/Regate.php b/Zotlabs/Module/Regate.php
index c67f45a88..956c5e2ea 100644
--- a/Zotlabs/Module/Regate.php
+++ b/Zotlabs/Module/Regate.php
@@ -375,7 +375,7 @@ class Regate extends \Zotlabs\Web\Controller {
]);
$reonar = json_decode( $r['reg_stuff'], true);
- $reonar['deny'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg;
+ $reonar['deny'] = $now . ',' . $ip . ' ' . $did2;
$flags = ( $r['reg_flags'] &= ( $r['reg_flags'] ^ ACCOUNT_UNVERIFIED) )
| ( $r['reg_flags'] |= REGISTER_DENIED);
$rd = q("UPDATE register SET reg_stuff='%s', reg_vital=0, reg_flags=%d WHERE reg_id = %d ",
@@ -456,7 +456,7 @@ class Regate extends \Zotlabs\Web\Controller {
// $log = ' from § ' . $ip . ' §' . ' (' . dbesc($did2) . ')';
zar_log($msg);
$o = replace_macros(get_markup_template('plain.tpl'), [
- '$title' => $title,
+ '$title' => $msg,
'$now' => $nowfmt,
'$infos' => $msg
]);
diff --git a/Zotlabs/Module/Removeaccount.php b/Zotlabs/Module/Removeaccount.php
index cd18b79c0..b41acb8b0 100644
--- a/Zotlabs/Module/Removeaccount.php
+++ b/Zotlabs/Module/Removeaccount.php
@@ -36,22 +36,22 @@ class Removeaccount extends \Zotlabs\Web\Controller {
return;
}
}
-
+
$global_remove = 0; //intval($_POST['global']);
-
- account_remove($account_id, 1 - $global_remove);
+
+ account_remove($account_id, 1 - $global_remove);
}
-
+
function get() {
-
+
if(! local_channel())
goaway(z_root());
-
+
$hash = random_string();
-
+
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeaccount.tpl');
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Account'),
@@ -60,9 +60,5 @@ class Removeaccount extends \Zotlabs\Web\Controller {
// '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')),
'$submit' => t('Remove Account')
));
-
- return $o;
-
}
-
}
diff --git a/Zotlabs/Module/Removeme.php b/Zotlabs/Module/Removeme.php
index 4d475ead6..d71f8d4ab 100644
--- a/Zotlabs/Module/Removeme.php
+++ b/Zotlabs/Module/Removeme.php
@@ -54,7 +54,7 @@ class Removeme extends \Zotlabs\Web\Controller {
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeme.tpl');
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove Channel'),
@@ -63,9 +63,5 @@ class Removeme extends \Zotlabs\Web\Controller {
// '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')
));
-
- return $o;
-
}
-
}
diff --git a/Zotlabs/Module/Request.php b/Zotlabs/Module/Request.php
new file mode 100644
index 000000000..439f56282
--- /dev/null
+++ b/Zotlabs/Module/Request.php
@@ -0,0 +1,89 @@
+<?php
+namespace Zotlabs\Module;
+
+use Zotlabs\Web\Controller;
+
+class Request extends Controller
+{
+
+ private function mapVerb(string $verb) : string
+ {
+ $verbs = [
+ 'like' => 'Like',
+ 'dislike' => 'Dislike',
+ 'announce' => 'Announce',
+ 'accept' => 'Accept',
+ 'reject' => 'Reject',
+ 'tentativeaccept' => 'TentativeAccept'
+ ];
+
+ if (array_key_exists($verb, $verbs)) {
+ return $verbs[$verb];
+ }
+
+ return EMPTY_STR;
+ }
+
+
+ private function processSubthreadRequest() : string
+ {
+ $mid = $_GET['mid'];
+ $parent = intval($_GET['parent']);
+
+ $offset = null;
+ if ($_GET['verb'] === 'load') {
+ $offset = intval($_GET['offset']);
+ }
+
+ $module = strip_tags($_GET['module']);
+
+ $items = items_by_thr_parent($mid, $parent, $offset);
+ xchan_query($items);
+
+ $items = fetch_post_tags($items,true);
+
+ if ($module === 'channel') {
+ $parts = explode('@', $items[0]['owner']['xchan_addr']);
+ profile_load($parts[0]);
+ }
+
+ $ret['html'] = conversation($items, $module, true, 'r_preview');
+
+ json_return_and_die($ret);
+ }
+
+ public function get() : string
+ {
+
+ if (in_array($_GET['verb'], ['comment', 'load'])) {
+ return self::processSubthreadRequest();
+ }
+
+ $verb = self::mapVerb($_GET['verb']);
+
+ if (!$verb) {
+ killme();
+ }
+
+ $text = get_response_button_text($_GET['verb']);
+ $mid = strip_tags($_GET['mid']);
+ $parent = intval($_GET['parent']);
+ $observer_hash = get_observer_hash();
+
+ $ret['result'] = item_activity_xchans($mid, $parent, $verb);
+
+ $commentable = $ret['result']['is_commentable'];
+ unset($ret['result']['is_commentable']);
+
+ if ($commentable) {
+ $ret['action'] = (($verb === 'Announce') ? 'jotShare' : 'dolike');
+ $ret['action_label'] = ((find_xchan_in_array($observer_hash, $ret['result'])) ? (($verb === 'Announce') ? t('+ Repeat again') : t('- Remove yours')) : t('+ Add yours'));
+ }
+
+ $ret['title'] = $text['label'];
+
+ json_return_and_die($ret);
+
+ }
+
+}
diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php
index 90cf8b854..4254dd38b 100644
--- a/Zotlabs/Module/Rmagic.php
+++ b/Zotlabs/Module/Rmagic.php
@@ -29,7 +29,7 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($r['hubloc_url'] === z_root())
goaway(z_root() . '/login');
$dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string));
- goaway($r['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest);
+ goaway($r['hubloc_url'] . '/magic?owa=1&bdest=' . $dest);
}
}
}
@@ -84,7 +84,7 @@ class Rmagic extends \Zotlabs\Web\Controller {
else
$dest = bin2hex(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
- goaway($url . '/magic' . '?f=&owa=1&bdest=' . $dest);
+ goaway($url . '/magic?owa=1&bdest=' . $dest);
}
}
}
diff --git a/Zotlabs/Module/Search_ac.php b/Zotlabs/Module/Search_ac.php
index 24b724c5d..cd0960859 100644
--- a/Zotlabs/Module/Search_ac.php
+++ b/Zotlabs/Module/Search_ac.php
@@ -90,12 +90,7 @@ class Search_ac extends \Zotlabs\Web\Controller {
'items' => $results,
);
echo json_encode($o);
-
- logger('search_ac: ' . print_r($x,true),LOGGER_DATA,LOG_INFO);
-
+
killme();
}
-
-
-
}
diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php
index 0266cee12..7f0d11069 100644
--- a/Zotlabs/Module/Settings/Account.php
+++ b/Zotlabs/Module/Settings/Account.php
@@ -100,7 +100,7 @@ class Account {
$attremail = ((!strpos($email, '@')) ? 'disabled="disabled"' : '');
$tpl = get_markup_template("settings_account.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("settings_account"),
'$title' => t('Account Settings'),
'$origpass' => array('origpass', t('Current Password'), ' ',''),
@@ -114,7 +114,5 @@ class Account {
'$removeaccount' => t('Remove this account including all its channels'),
'$account_settings' => $account_settings
));
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Calendar.php b/Zotlabs/Module/Settings/Calendar.php
index 65240c635..3b15f4aa6 100644
--- a/Zotlabs/Module/Settings/Calendar.php
+++ b/Zotlabs/Module/Settings/Calendar.php
@@ -33,7 +33,7 @@ class Calendar {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Calendar {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Channel_home.php b/Zotlabs/Module/Settings/Channel_home.php
index 470dbe4c3..388b70942 100644
--- a/Zotlabs/Module/Settings/Channel_home.php
+++ b/Zotlabs/Module/Settings/Channel_home.php
@@ -81,7 +81,7 @@ class Channel_home {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -90,8 +90,5 @@ class Channel_home {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Connections.php b/Zotlabs/Module/Settings/Connections.php
index 52a95a3d1..9d1069cf3 100644
--- a/Zotlabs/Module/Settings/Connections.php
+++ b/Zotlabs/Module/Settings/Connections.php
@@ -33,7 +33,7 @@ class Connections {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Connections {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Conversation.php b/Zotlabs/Module/Settings/Conversation.php
index 5f3d903a8..51ee2c83a 100644
--- a/Zotlabs/Module/Settings/Conversation.php
+++ b/Zotlabs/Module/Settings/Conversation.php
@@ -36,7 +36,7 @@ class Conversation {
$tpl = (($aj) ? get_markup_template("settings_module_ajax.tpl") : get_markup_template("settings_module.tpl"));
- $o .= replace_macros($tpl, array(
+ $o = replace_macros($tpl, array(
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Conversation Settings'),
diff --git a/Zotlabs/Module/Settings/Directory.php b/Zotlabs/Module/Settings/Directory.php
index 09ea61f60..e1957d2fa 100644
--- a/Zotlabs/Module/Settings/Directory.php
+++ b/Zotlabs/Module/Settings/Directory.php
@@ -33,7 +33,7 @@ class Directory {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Directory {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php
index a7fccea47..98c3d7543 100644
--- a/Zotlabs/Module/Settings/Display.php
+++ b/Zotlabs/Module/Settings/Display.php
@@ -24,7 +24,7 @@ class Display {
$theme = 'redbasic';
- $preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 0);
+ $thread_allow = ((!empty($_POST['thread_allow'])) ? intval($_POST['thread_allow']) : 0);
$user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0);
$nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0);
$title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0);
@@ -40,7 +40,7 @@ class Display {
$itemspage = 30;
- set_pconfig(local_channel(),'system','preload_images',$preload_images);
+ set_pconfig(local_channel(), 'system', 'thread_allow', $thread_allow);
set_pconfig(local_channel(),'system','user_scalable',$user_scalable);
set_pconfig(local_channel(),'system','update_interval', $browser_update);
set_pconfig(local_channel(),'system','itemspage', $itemspage);
@@ -146,8 +146,7 @@ class Display {
$start_menu = get_pconfig(local_channel(), 'system', 'start_menu', 0);
}
- $preload_images = get_pconfig(local_channel(),'system','preload_images');
- $preload_images = (($preload_images===false)? '0': $preload_images); // default if not set: 0
+ $thread_allow = get_pconfig(local_channel(), 'system', 'thread_allow', true);
$user_scalable = get_pconfig(local_channel(),'system','user_scalable');
$user_scalable = (($user_scalable===false)? '0': $user_scalable); // default if not set: 0
@@ -192,7 +191,7 @@ class Display {
'$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false),
'$schema' => (($schemas) ? array('schema', t('Select scheme'), $existing_schema, '' , $schemas) : false),
- '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no),
+ '$thread_allow' => ['thread_allow', t('Threaded conversation view'), $thread_allow, t('Display replies below their parent message (default yes)'), $yes_no],
'$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no),
'$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')),
'$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 30 items')),
diff --git a/Zotlabs/Module/Settings/Editor.php b/Zotlabs/Module/Settings/Editor.php
index 85c3e69ae..50bd2b2ad 100644
--- a/Zotlabs/Module/Settings/Editor.php
+++ b/Zotlabs/Module/Settings/Editor.php
@@ -33,7 +33,7 @@ class Editor {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Editor {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Events.php b/Zotlabs/Module/Settings/Events.php
index 0a0e3516c..3a7faa8b4 100644
--- a/Zotlabs/Module/Settings/Events.php
+++ b/Zotlabs/Module/Settings/Events.php
@@ -33,7 +33,7 @@ class Events {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Events {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Features.php b/Zotlabs/Module/Settings/Features.php
index 553ff0836..84c868e48 100644
--- a/Zotlabs/Module/Settings/Features.php
+++ b/Zotlabs/Module/Settings/Features.php
@@ -38,17 +38,14 @@ class Features {
$arr[$fname][1][] = array('feature_' . $f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On')));
}
}
-
+
$tpl = get_markup_template("settings_features.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("settings_features"),
'$title' => t('Additional Features'),
'$features' => $arr,
'$baseurl' => z_root(),
'$submit' => t('Submit'),
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Manage.php b/Zotlabs/Module/Settings/Manage.php
index 6fb57eafb..6e47cfcc7 100644
--- a/Zotlabs/Module/Settings/Manage.php
+++ b/Zotlabs/Module/Settings/Manage.php
@@ -34,7 +34,7 @@ class Manage {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -42,8 +42,5 @@ class Manage {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Network.php b/Zotlabs/Module/Settings/Network.php
index eae963a25..39c66622e 100644
--- a/Zotlabs/Module/Settings/Network.php
+++ b/Zotlabs/Module/Settings/Network.php
@@ -52,7 +52,7 @@ class Network {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -61,8 +61,5 @@ class Network {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Photos.php b/Zotlabs/Module/Settings/Photos.php
index f68c8847b..05c380850 100644
--- a/Zotlabs/Module/Settings/Photos.php
+++ b/Zotlabs/Module/Settings/Photos.php
@@ -33,7 +33,7 @@ class Photos {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -41,8 +41,5 @@ class Photos {
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Settings/Profiles.php b/Zotlabs/Module/Settings/Profiles.php
index 0ff2dfb6d..5052385a8 100644
--- a/Zotlabs/Module/Settings/Profiles.php
+++ b/Zotlabs/Module/Settings/Profiles.php
@@ -42,7 +42,7 @@ class Profiles {
$tpl = get_markup_template("settings_module.tpl");
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
@@ -51,8 +51,5 @@ class Profiles {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php
index 35079e5e5..5b423f67d 100644
--- a/Zotlabs/Module/Setup.php
+++ b/Zotlabs/Module/Setup.php
@@ -263,7 +263,10 @@ class Setup extends \Zotlabs\Web\Controller {
$this->check_htaccess($checks);
- $checkspassed = array_reduce($checks, "self::check_passed", true);
+ $checkspassed = array_reduce(
+ $checks,
+ "Zotlabs\Module\Setup::check_passed",
+ true);
$tpl = get_markup_template('install_checks.tpl');
$o .= replace_macros($tpl, array(
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/Snap.php b/Zotlabs/Module/Snap.php
index 89aebc097..770ba07c2 100644
--- a/Zotlabs/Module/Snap.php
+++ b/Zotlabs/Module/Snap.php
@@ -8,8 +8,8 @@ namespace Zotlabs\Module;
* Module for accessing the DAV storage area from a DAV client.
*/
-use \Sabre\DAV as SDAV;
-use \Zotlabs\Storage;
+use Sabre\DAV as SDAV;
+use Zotlabs\Storage;
// composer autoloader for SabreDAV
require_once('vendor/autoload.php');
@@ -24,7 +24,7 @@ require_once('vendor/autoload.php');
class Snap extends \Zotlabs\Web\Controller {
function init() {
-
+
// workaround for HTTP-auth in CGI mode
if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
@@ -43,20 +43,20 @@ class Snap extends \Zotlabs\Web\Controller {
$_SERVER['PHP_AUTH_PW'] = $password;
}
}
-
+
if (! is_dir('store'))
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
-
+
$which = null;
if (argc() > 1)
$which = argv(1);
-
+
$profile = 0;
-
+
if($which)
profile_load( $which, $profile);
else
- killme();
+ killme();
if($_SERVER['PHP_AUTH_USER'] && $_SERVER['PHP_AUTH_USER'] !== $which)
killme();
@@ -68,7 +68,7 @@ class Snap extends \Zotlabs\Web\Controller {
}
if(! in_array(strtolower($_SERVER['REQUEST_METHOD']),['propfind','get','head']))
- killme();
+ killme();
$auth = new \Zotlabs\Storage\BasicAuth();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'WebDAV');
@@ -101,5 +101,5 @@ class Snap extends \Zotlabs\Web\Controller {
killme();
}
-
+
}
diff --git a/Zotlabs/Module/Sse.php b/Zotlabs/Module/Sse.php
index fda2f2be4..673457db1 100644
--- a/Zotlabs/Module/Sse.php
+++ b/Zotlabs/Module/Sse.php
@@ -207,10 +207,9 @@ class Sse extends Controller {
if ($result) {
XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
- json_return_and_die($result);
}
- killme();
+ json_return_and_die($result);
}
diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php
index 09c4ed614..c457363c0 100644
--- a/Zotlabs/Module/Sse_bs.php
+++ b/Zotlabs/Module/Sse_bs.php
@@ -22,7 +22,6 @@ class Sse_bs extends Controller {
public static $xchans;
function init() {
-
self::$uid = local_channel();
self::$ob_hash = get_observer_hash();
self::$sse_id = false;
@@ -43,8 +42,9 @@ class Sse_bs extends Controller {
self::$offset = 0;
self::$xchans = '';
- if(isset($_REQUEST['sse_rmids']))
- self::mark_read($_REQUEST['sse_rmids']);
+ if (!empty($_REQUEST['sse_rmids'])) {
+ self::mark_read(explode(',', $_REQUEST['sse_rmids']));
+ }
if(!empty($_REQUEST['nquery']) && $_REQUEST['nquery'] !== '%') {
$nquery = $_REQUEST['nquery'];
@@ -118,7 +118,6 @@ class Sse_bs extends Controller {
}
function mark_read($arr) {
-
$mids = [];
$str = '';
$slice = 0;
@@ -142,24 +141,51 @@ class Sse_bs extends Controller {
}
}
- $_SESSION['sse_mids_all'] = serialise($mids_all);
+ $str = implode(',', $mids);
+
+ $sys = get_sys_channel();
+ $sql_order = ((self::$uid > $sys['channel_id']) ? 'DESC' : 'ASC');
+
+ $r = q("SELECT uid, uuid FROM item
+ WHERE uid in (%d, %d)
+ AND verb IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept')
+ AND thr_parent IN (
+ SELECT mid FROM item WHERE uid IN (%d, %d) AND uuid IN (%s) ORDER BY uid $sql_order
+ )
+ GROUP BY uid, uuid
+ ORDER BY uid $sql_order",
+ intval(self::$uid),
+ intval($sys['channel_id']),
+ intval(self::$uid),
+ intval($sys['channel_id']),
+ $str // this is dbesc() in the above foreach loop
+ );
+
+ if ($r) {
+ $activities_str = ids_to_querystr($r, 'uuid', true);
+ $str .= ',' . $activities_str;
+ $activities_arr = explode(',', $activities_str);
+ $mids_all = array_merge($mids_all, $activities_arr);
+ }
+
+ $_SESSION['sse_mids_all'] = serialise(array_unique($mids_all));
if(! self::$uid) {
return;
}
- $str = implode(',', $mids);
-
$x = [ 'channel_id' => self::$uid, 'update' => 'unset' ];
call_hooks('update_unseen',$x);
- if($x['update'] === 'unset' || intval($x['update'])) {
- q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND uuid in (%s) AND item_unseen = 1",
+ if ($x['update'] === 'unset' || intval($x['update'])) {
+ q("UPDATE item SET item_unseen = 0
+ WHERE uid = %d
+ AND uuid in (%s)
+ AND item_unseen = 1",
intval(self::$uid),
$str // this is dbesc() in the above foreach loop
);
}
-
}
function bs_network($notifications) {
@@ -182,32 +208,34 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
- $sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
- $sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND CASE WHEN verb = '" . dbesc(ACTIVITY_SHARE) . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+ $sql_extra2 = " AND CASE WHEN item.verb = '" . dbesc(ACTIVITY_SHARE) . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
- $items = q("SELECT * FROM item
- WHERE uid = %d
- AND created <= '%s'
- AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)
- AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
- AND author_xchan != '%s'
+ $items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
+ LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
+ WHERE item.uid = %d
+ AND item.created <= '%s'
+ AND item.item_unseen = 1 AND item.item_wall = 0 AND item.item_private IN (0, 1)
+ AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
+ AND NOT item.author_xchan = '%s'
$item_normal
$sql_extra
$sql_extra2
- ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
intval(self::$uid),
dbescdate($_SESSION['sse_loadtime']),
dbesc(self::$ob_hash)
@@ -265,28 +293,30 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
- $sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
- $sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+ $sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
- $items = q("SELECT * FROM item
- WHERE uid = %d
- AND created <= '%s'
- AND item_unseen = 1 AND item_private = 2
- AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
- AND author_xchan != '%s'
+ $items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
+ LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
+ WHERE item.uid = %d
+ AND item.created <= '%s'
+ AND item.item_unseen = 1 AND item.item_private = 2
+ AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
+ AND NOT item.author_xchan = '%s'
$item_normal
$sql_extra
$sql_extra2
@@ -347,33 +377,35 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
- $sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
- $sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+ $sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
- $items = q("SELECT * FROM item
- WHERE uid = %d
- AND created <= '%s'
- AND item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1)
- AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
- AND author_xchan != '%s'
+ $items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
+ LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
+ WHERE item.uid = %d
+ AND item.created <= '%s'
+ AND item.item_unseen = 1 AND item.item_wall = 1 AND item.item_private IN (0, 1)
+ AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
+ AND NOT item.author_xchan = '%s'
$item_normal
$sql_extra
$sql_extra2
- ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
intval(self::$uid),
dbescdate($_SESSION['sse_loadtime']),
dbesc(self::$ob_hash)
@@ -442,49 +474,51 @@ class Sse_bs extends Controller {
$sys = get_sys_channel();
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
- $sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
- $sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
+ $sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
if(self::$xchans)
- $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
+ $sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
$sql_extra3 = '';
- $sse_mids_all = unserialise($_SESSION['sse_mids_all']) ?? [];
+ $sse_mids_all = isset($_SESSION['sse_mids_all']) ? unserialise($_SESSION['sse_mids_all']) : [];
if ($sse_mids_all) {
- $sql_extra3 = " AND uuid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
+ $sql_extra3 = " AND item.uuid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
}
- $uids = " AND uid IN ( " . $sys['channel_id'] . " ) ";
+ $uids = " AND item.uid IN ( " . $sys['channel_id'] . " ) ";
$site_firehose = Config::Get('system', 'site_firehose', 0);
if($site_firehose) {
- $uids = " AND uid IN ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) AND item_private = 0 AND item_wall = 1 ";
+ $uids = " AND item.uid IN ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) AND item.item_private = 0 AND item.item_wall = 1 ";
}
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
- $items = q("SELECT * FROM item
+ $items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
+ LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
WHERE true $uids
- AND created <= '%s'
- AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
- AND author_xchan != '%s'
- AND created > '%s'
+ AND item.created <= '%s'
+ AND item.created > '%s'
+ AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
+ AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity not the resulting item
+ AND NOT item.author_xchan = '%s'
$item_normal
$sql_extra
$sql_extra2
$sql_extra3
- ORDER BY created DESC LIMIT $limit OFFSET $offset",
+ ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
dbescdate($_SESSION['sse_loadtime']),
- dbesc(self::$ob_hash),
- dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime'])
+ dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime']),
+ dbesc(self::$ob_hash)
);
if($items) {
@@ -502,13 +536,15 @@ class Sse_bs extends Controller {
}
}
- $r = q("SELECT id FROM item
+ $r = q("SELECT id, body FROM item
WHERE true $uids
+ AND created <= '%s'
AND created > '%s'
$item_normal
$sql_extra
$sql_extra3
AND author_xchan != '%s' LIMIT 100",
+ dbescdate($_SESSION['sse_loadtime']),
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime']),
dbesc(self::$ob_hash)
);
@@ -600,25 +636,15 @@ class Sse_bs extends Controller {
$i = 0;
for($x = 0; $x < $fcount; $x ++) {
- /*
- $p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
- intval(self::$uid),
- intval(TERM_FORUM),
- dbesc($forums[$x]['xchan_name'])
- );
-
- $p_str = ids_to_querystr($p, 'parent');
- $p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
- */
$r = q("select count(*) as total from item
- where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and verb != 'Announce' and item_unseen = 1 $sql_extra $item_normal",
+ where uid = %d and (owner_xchan = '%s' or author_xchan = '%s') and author_xchan != '%s' and verb != 'Announce' and item_unseen = 1 $sql_extra $item_normal",
intval(self::$uid),
dbesc($forums[$x]['xchan_hash']),
- dbesc($forums[$x]['xchan_hash'])
+ dbesc($forums[$x]['xchan_hash']),
+ dbesc(self::$ob_hash)
);
-
if($r[0]['total']) {
$forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
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/Tagger.php b/Zotlabs/Module/Tagger.php
index b6067be5e..a88a3b112 100644
--- a/Zotlabs/Module/Tagger.php
+++ b/Zotlabs/Module/Tagger.php
@@ -1,6 +1,7 @@
<?php
namespace Zotlabs\Module;
+use App;
use Zotlabs\Lib\Libsync;
require_once('include/security.php');
@@ -18,6 +19,7 @@ class Tagger extends \Zotlabs\Web\Controller {
}
$sys = get_sys_channel();
+ $channel = App::get_channel();
$observer_hash = get_observer_hash();
//strip html-tags
@@ -125,10 +127,6 @@ class Tagger extends \Zotlabs\Web\Controller {
$termlink = html_entity_decode('&#x22d5;') . '[zrl=' . z_root() . '/search?tag=' . urlencode($clean_term) . ']'. $clean_term . '[/zrl]';
- $channel = \App::get_channel();
-
- $arr = array();
-
$arr['owner_xchan'] = $item['owner_xchan'];
$arr['author_xchan'] = $channel['channel_hash'];
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/Thing.php b/Zotlabs/Module/Thing.php
index 2038db8c0..aef494e13 100644
--- a/Zotlabs/Module/Thing.php
+++ b/Zotlabs/Module/Thing.php
@@ -50,24 +50,31 @@ class Thing extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
- $term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : '');
+ $term_hash = (($_POST['term_hash']) ? $_POST['term_hash'] : '');
- $name = escape_tags($_REQUEST['term']);
- $verb = escape_tags($_REQUEST['verb']);
- $activity = intval($_REQUEST['activity']);
- $profile_guid = escape_tags($_REQUEST['profile_assign']);
- $url = $_REQUEST['url'];
- $photo = $_REQUEST['img'];
+ $name = escape_tags($_POST['term']);
+ $verb = escape_tags($_POST['verb']);
+ $activity = intval($_POST['activity']);
+ $url = $_POST['url'];
+ $photo = $_POST['img'];
+
+ $profile_guid = isset($_POST['profile_assign'])
+ ? escape_tags($_POST['profile_assign'])
+ : null;
$hash = new_uuid();
$verbs = obj_verbs();
- /**
- * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants"
- * We use the first person form when creating an activity, but the third person for use in activities
- * @FIXME There is no accounting for verb gender for languages where this is significant. We may eventually
- * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module.
+ /*
+ * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person
+ * singular, e.g. "Bill wants" We use the first person form when
+ * creating an activity, but the third person for use in activities
+ *
+ * @FIXME There is no accounting for verb gender for languages where
+ * this is significant. We may eventually require obj_verbs() to
+ * provide full conjugations and specify which form to use in the
+ * $_POST params to this module.
*/
$translated_verb = $verbs[$verb][1];
@@ -100,7 +107,7 @@ class Thing extends \Zotlabs\Web\Controller {
return;
$acl = new \Zotlabs\Access\AccessList($channel);
- $acl->set_from_array($_REQUEST);
+ $acl->set_from_array($_POST);
$x = $acl->get();
@@ -332,7 +339,7 @@ class Thing extends \Zotlabs\Web\Controller {
return '';
}
- $o .= replace_macros(get_markup_template('thing_edit.tpl'),array(
+ return replace_macros(get_markup_template('thing_edit.tpl'),array(
'$thing_hdr' => t('Edit Thing'),
'$multiprof' => feature_enabled(local_channel(),'multi_profiles'),
'$profile_lbl' => t('Select a profile'),
@@ -356,8 +363,6 @@ class Thing extends \Zotlabs\Web\Controller {
'$lockstate' => $lockstate,
'$submit' => t('Submit')
));
-
- return $o;
}
if(argc() == 3 && argv(1) === 'drop') {
@@ -385,16 +390,16 @@ class Thing extends \Zotlabs\Web\Controller {
Libsync::build_sync_packet(0,array('obj' => $r));
- return $o;
+ return '';
}
- $o .= replace_macros(get_markup_template('thing_input.tpl'),array(
+ return replace_macros(get_markup_template('thing_input.tpl'),array(
'$thing_hdr' => t('Add Thing to your Profile'),
'$multiprof' => feature_enabled(local_channel(),'multi_profiles'),
'$profile_lbl' => t('Select a profile'),
'$profile_select' => contact_profile_assign(''),
'$verb_lbl' => $channel['channel_name'],
- '$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_REQUEST)) ? $_REQUEST['activity'] : true),t('Only sends to viewers of the applicable profile')),
+ '$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_GET)) ? $_GET['activity'] : true),t('Only sends to viewers of the applicable profile')),
'$verb_select' => obj_verb_selector(),
'$thing_lbl' => t('Name of thing e.g. something'),
'$url_lbl' => t('URL of thing (optional)'),
@@ -408,8 +413,5 @@ class Thing extends \Zotlabs\Web\Controller {
'$lockstate' => $lockstate,
'$submit' => t('Submit')
));
-
- return $o;
}
-
}
diff --git a/Zotlabs/Module/Viewsrc.php b/Zotlabs/Module/Viewsrc.php
index 3e49b9db4..cfc184a9d 100644
--- a/Zotlabs/Module/Viewsrc.php
+++ b/Zotlabs/Module/Viewsrc.php
@@ -6,34 +6,34 @@ namespace Zotlabs\Module;
class Viewsrc extends \Zotlabs\Web\Controller {
function get() {
-
+
$o = '';
-
+
$sys = get_sys_channel();
-
+
$item_id = ((argc() > 1) ? intval(argv(1)) : 0);
$json = ((argc() > 2 && argv(2) === 'json') ? true : false);
$dload = ((argc() > 2 && argv(2) === 'download') ? true : false);
-
+
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
}
-
-
+
+
if(! $item_id) {
\App::$error = 404;
notice( t('Item not found.') . EOL);
}
-
+
$item_normal = item_normal_search();
-
+
if(local_channel() && $item_id) {
- $r = q("select id, mid, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
+ $r = q("select id, mid, uuid, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
intval(local_channel()),
intval($sys['channel_id']),
intval($item_id)
);
-
+
if($r) {
if(intval($r[0]['item_obscured']))
$dload = true;
@@ -50,18 +50,18 @@ class Viewsrc extends \Zotlabs\Web\Controller {
$o = (($json) ? json_encode($content) : $content);
}
}
-
+
if(is_ajax()) {
echo '<div class="p-1">';
- echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a><br>mid: ' . $r[0]['mid'] . '</div>';
+ echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a><br>mid: ' . $r[0]['mid'] . '<br>uuid: ' . $r[0]['uuid'] . '</div>';
echo '<hr>';
echo '<pre class="p-1">' . $o . '</pre>';
echo '</div>';
killme();
- }
-
+ }
+
return $o;
}
-
-
+
+
}
diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php
index 06c47f91f..5192e3043 100644
--- a/Zotlabs/Module/Vote.php
+++ b/Zotlabs/Module/Vote.php
@@ -107,10 +107,12 @@ class Vote extends Controller {
retain_item($fetch[0]['id']);
if($x['success']) {
- $itemid = $x['item_id'];
- Master::Summon( [ 'Notifier', 'like', $itemid ] );
+ Master::Summon(['Notifier', 'like', $x['item_id']]);
+ if (!empty($x['approval_id'])) {
+ Master::Summon(['Notifier', 'like', $x['approval_id']]);
+ }
}
-
+/*
$r = q("select * from item where id = %d",
intval($itemid)
);
@@ -119,6 +121,7 @@ class Vote extends Controller {
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
+*/
}
$ret['success'] = true;
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index e354f58f1..84c76f8dd 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -10,7 +10,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
function init() {
logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO);
- logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO);
+ logger('wall_attach: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO);
logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO);
// for testing without actually storing anything
// http_status_exit(200,'OK');
@@ -18,12 +18,11 @@ class Wall_attach extends \Zotlabs\Web\Controller {
function post() {
-
$using_api = false;
$result = [];
- if($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) {
+ if($_POST['api_source'] && array_key_exists('media',$_FILES)) {
$using_api = true;
}
@@ -98,8 +97,8 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$r = attach_store($channel, get_observer_hash(), '', $data);
- if(! $r['success']) {
- notice( $r['message'] . EOL);
+ if (!$r['success']) {
+ notice($r['message'] . EOL);
killme();
}
diff --git a/Zotlabs/Module/Webfinger.php b/Zotlabs/Module/Webfinger.php
index 0dafae23c..ba0dca9e7 100644
--- a/Zotlabs/Module/Webfinger.php
+++ b/Zotlabs/Module/Webfinger.php
@@ -7,16 +7,16 @@ namespace Zotlabs\Module;
class Webfinger extends \Zotlabs\Web\Controller {
function get() {
-
-
- $o .= '<h3>Webfinger Diagnostic</h3>';
-
+
+
+ $o = '<h3>Webfinger Diagnostic</h3>';
+
$o .= '<form action="webfinger" method="get">';
$o .= 'Lookup address: <input type="text" style="width: 250px;" name="addr" value="' . $_GET['addr'] .'" />';
- $o .= '<input type="submit" name="submit" value="Submit" /></form>';
-
+ $o .= '<input type="submit" name="submit" value="Submit" /></form>';
+
$o .= '<br /><br />';
-
+
if(x($_GET,'addr')) {
$addr = trim($_GET['addr']);
diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php
index ffb0d94ea..ca15c0b3a 100644
--- a/Zotlabs/Module/Webpages.php
+++ b/Zotlabs/Module/Webpages.php
@@ -63,7 +63,7 @@ class Webpages extends Controller {
switch ($_SESSION['action']) {
case 'import':
$_SESSION['action'] = null;
- $o .= replace_macros(get_markup_template('webpage_import.tpl'), array(
+ return replace_macros(get_markup_template('webpage_import.tpl'), array(
'$title' => t('Import Webpage Elements'),
'$importbtn' => t('Import selected'),
'$action' => 'import',
@@ -71,7 +71,6 @@ class Webpages extends Controller {
'$layouts' => $_SESSION['layouts'],
'$blocks' => $_SESSION['blocks'],
));
- return $o;
case 'importselected':
$_SESSION['action'] = null;
@@ -87,7 +86,7 @@ class Webpages extends Controller {
$pages = get_webpage_elements($channel, 'pages');
$layouts = get_webpage_elements($channel, 'layouts');
$blocks = get_webpage_elements($channel, 'blocks');
- $o .= replace_macros(get_markup_template('webpage_export_list.tpl'), array(
+ $o = replace_macros(get_markup_template('webpage_export_list.tpl'), array(
'$title' => t('Export Webpage Elements'),
'$exportbtn' => t('Export selected'),
'$action' => $_SESSION['export'], // value should be 'zipfile' or 'cloud'
diff --git a/Zotlabs/Module/Xref.php b/Zotlabs/Module/Xref.php
deleted file mode 100644
index e9d494da4..000000000
--- a/Zotlabs/Module/Xref.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-
-class Xref extends \Zotlabs\Web\Controller {
-
- function init() {
- // Sets a referral URL using an xchan directly
- // Link format: example.com/xref/[xchan]/[TargetURL]
- // Target URL is optional.
- // Cookie lasts 24 hours to survive a browser restart. Contains no personal
- // information at all - just somebody else's xchan.
- $referrer = argv(1);
- $expire=time()+60*60*2;
- $path = 'xref';
- setcookie($path, $referrer, $expire, "/");
- $url = '';
-
- if (argc() > 2)
- $url = argv(2);
-
- goaway (z_root() . '/' . $url);
-
- }
-
-}
diff --git a/Zotlabs/Module/Zot_probe.php b/Zotlabs/Module/Zot_probe.php
index 3eaabdd92..feb51f071 100644
--- a/Zotlabs/Module/Zot_probe.php
+++ b/Zotlabs/Module/Zot_probe.php
@@ -9,19 +9,29 @@ class Zot_probe extends \Zotlabs\Web\Controller {
function get() {
+ if (!local_channel()) {
+ return;
+ }
+
$addr = $_GET['addr'] ?? '';
$o = '<h3>Zot6 Probe Diagnostic</h3>';
$o .= '<form action="zot_probe" method="get">';
$o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $addr .'" /><br>';
+ $o .= '<input type="checkbox" name="sign" /> Sign request <br>';
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
$o .= '<br /><br />';
if($addr) {
- $x = Zotfinger::exec($addr);
+ $channel = null;
+ if ($_GET['sign']) {
+ $channel = get_sys_channel();
+ }
+
+ $x = Zotfinger::exec($addr, $channel);
$o .= '<pre>' . htmlspecialchars(print_array($x)) . '</pre>';
diff --git a/Zotlabs/Photo/PhotoGd.php b/Zotlabs/Photo/PhotoGd.php
index a81d9cae2..8d46ae4d5 100644
--- a/Zotlabs/Photo/PhotoGd.php
+++ b/Zotlabs/Photo/PhotoGd.php
@@ -25,6 +25,8 @@ class PhotoGd extends PhotoDriver {
$t['image/gif'] = 'gif';
if(\imagetypes() & IMG_WEBP)
$t['image/webp'] = 'webp';
+ if(\imagetypes() & IMG_AVIF)
+ $t['image/avif'] = 'avif';
return $t;
}
@@ -184,6 +186,19 @@ class PhotoGd extends PhotoDriver {
break;
+ case 'image/avif':
+ $quality = Config::Get('system', 'avif_quality');
+
+ if((! $quality) || ($quality > 100)) {
+ $quality = AVIF_QUALITY;
+ }
+
+ if (function_exists('imageavif')) {
+ \imageavif($this->image, NULL, $quality);
+ }
+
+ break;
+
case 'image/jpeg':
// gd can lack imagejpeg(), but we verify during installation it is available
diff --git a/Zotlabs/Render/SmartyInterface.php b/Zotlabs/Render/SmartyInterface.php
index 64c6aa377..003262939 100644
--- a/Zotlabs/Render/SmartyInterface.php
+++ b/Zotlabs/Render/SmartyInterface.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Render;
-use Smarty;
+use Smarty\Smarty;
use App;
class SmartyInterface extends Smarty {
@@ -19,20 +19,20 @@ class SmartyInterface extends Smarty {
// The order is thus very important here
$template_dirs = array('theme' => "view/theme/$thname/tpl/");
- if ( x(App::$theme_info,"extends") ) {
+ if (!empty(App::$theme_info['extends'])) {
$template_dirs = $template_dirs + array('extends' => "view/theme/" . App::$theme_info["extends"] . "/tpl/");
}
$template_dirs = $template_dirs + array('base' => 'view/tpl/');
$this->setTemplateDir($template_dirs);
$basecompiledir = App::$config['system']['smarty3_folder'];
-
+
$this->setCompileDir($basecompiledir.'/compiled/');
$this->setConfigDir($basecompiledir.'/config/');
$this->setCacheDir($basecompiledir.'/cache/');
- $this->left_delimiter = App::get_template_ldelim('smarty3');
- $this->right_delimiter = App::get_template_rdelim('smarty3');
+ $this->setLeftDelimiter(App::get_template_ldelim('smarty3'));
+ $this->setRightDelimiter(App::get_template_rdelim('smarty3'));
// Don't report errors so verbosely
$this->error_reporting = E_ALL & ~E_WARNING & ~E_NOTICE;
diff --git a/Zotlabs/Render/Theme.php b/Zotlabs/Render/Theme.php
index a42b65e03..2faf3631a 100644
--- a/Zotlabs/Render/Theme.php
+++ b/Zotlabs/Render/Theme.php
@@ -26,9 +26,9 @@ class Theme {
*/
static public function current() {
- self::$system_theme = ((isset(App::$config['system']['theme']))
+ self::$system_theme = ((!empty(App::$config['system']['theme']))
? App::$config['system']['theme'] : '');
- self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme'))
+ self::$session_theme = ((!empty($_SESSION['theme']))
? $_SESSION['theme'] : self::$system_theme);
$page_theme = null;
@@ -87,8 +87,13 @@ class Theme {
// Find any theme at all and use it.
$fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php'));
- if(count($fallback))
- return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
+
+ if (empty($fallback)) {
+ logger('Unable to find a theme');
+ http_status_exit(500, 'internal server error');
+ }
+
+ return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
}
@@ -111,7 +116,7 @@ class Theme {
$opts = '';
$opts = (($uid) ? '?puid=' . $uid : '');
- $schema_str = ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
+ $schema_str = ((!empty(App::$layout['schema'])) ? '&schema=' . App::$layout['schema'] : '');
if(($s) && (! $schema_str))
$schema_str = '&schema=' . $s;
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index e7f71c8c8..6ea6031d3 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -5,6 +5,7 @@ namespace Zotlabs\Storage;
use Sabre\DAV;
use App;
use Zotlabs\Lib\Config;
+use Zotlabs\Lib\Text;
/**
* @brief Provides a DAV frontend for the webbrowser.
@@ -260,13 +261,16 @@ class Browser extends DAV\Browser\Plugin {
}
}
+ $display_path_encoded = Text::rawurlencode_parts($data['display_path']);
+ $href_encoded = Text::rawurlencode_parts($href);
+
// put the array for this file together
$ft['attach_id'] = $id;
// $ft['icon'] = $icon;
$ft['photo_icon'] = $photo_icon;
$ft['is_creator'] = $is_creator;
- $ft['rel_path'] = (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href);
- $ft['full_path'] = z_root() . (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href);
+ $ft['rel_path'] = (($data) ? '/cloud/' . $nick .'/' . $display_path_encoded : $href_encoded);
+ $ft['full_path'] = z_root() . (($data) ? '/cloud/' . $nick .'/' . $display_path_encoded : $href_encoded);
$ft['name'] = $name;
$ft['type'] = $type;
$ft['size'] = $size;
@@ -399,7 +403,6 @@ class Browser extends DAV\Browser\Plugin {
'$allow_gid' => ((isset($channel_acl['allow_gid'])) ? acl2json($channel_acl['allow_gid']) : ''),
'$deny_cid' => ((isset($channel_acl['deny_cid'])) ? acl2json($channel_acl['deny_cid']) : ''),
'$deny_gid' => ((isset($channel_acl['deny_gid'])) ? acl2json($channel_acl['deny_gid']) : ''),
- '$is_owner' => $is_owner,
'$select_all_label' => t('Select All'),
'$bulk_actions_label' => t('Bulk Actions'),
'$adjust_permissions_label' => t('Adjust Permissions'),
diff --git a/Zotlabs/Storage/GitRepo.php b/Zotlabs/Storage/GitRepo.php
deleted file mode 100644
index 306abc0ba..000000000
--- a/Zotlabs/Storage/GitRepo.php
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-
-namespace Zotlabs\Storage;
-
-use PHPGit\Git as PHPGit;
-
-require __DIR__ . '/../../library/PHPGit.autoload.php'; // Load PHPGit dependencies
-
-/**
- * Wrapper class for PHPGit class for git repositories managed by Hubzilla
- *
- * @author Andrew Manning <andrewmanning@grid.reticu.li>
- */
-class GitRepo {
-
- public $url = null;
- public $name = null;
- private $path = null;
- private $channel = null;
- public $git = null;
- private $repoBasePath = null;
-
- function __construct($channel = 'sys', $url = null, $clone = false, $name = null, $path = null) {
-
- if ($channel === 'sys' && !is_site_admin()) {
- logger('Only admin can use channel sys');
- return null;
- }
-
- $this->repoBasePath = __DIR__ . '/../../store/git';
- $this->channel = $channel;
- $this->git = new PHPGit();
-
- // Allow custom path for repo in the case of , for example
- if ($path) {
- $this->path = $path;
- } else {
- $this->path = $this->repoBasePath . "/" . $this->channel . "/" . $this->name;
- }
-
- if ($this->isValidGitRepoURL($url)) {
- $this->url = $url;
- }
-
- if ($name) {
- $this->name = $name;
- } else {
- $this->name = $this->getRepoNameFromURL($url);
- }
- if (!$this->name) {
- logger('Error creating GitRepo. No repo name found.');
- return null;
- }
-
- if (is_dir($this->path)) {
- // ignore the $url input if it exists
- // TODO: Check if the path is either empty or is a valid git repo and error if not
- $this->git->setRepository($this->path);
- // TODO: get repo metadata
- return;
- }
-
- if ($this->url) {
- // create the folder and clone the repo at url to that folder if $clone is true
- if ($clone) {
- if (mkdir($this->path, 0770, true)) {
- $this->git->setRepository($this->path);
- if (!$this->cloneRepo()) {
- // TODO: throw error
- logger('git clone failed: ' . json_encode($this->git));
- }
- } else {
- logger('git repo path could not be created: ' . json_encode($this->git));
- }
- }
- }
- }
-
- public function initRepo() {
- if(!$this->path) return false;
- try {
- return $this->git->init($this->path);
- } catch (\PHPGit\Exception\GitException $ex) {
- return false;
- }
- }
-
- public function pull() {
- try {
- $success = $this->git->pull();
- } catch (\PHPGit\Exception\GitException $ex) {
- return false;
- }
- return $success;
- }
-
- public function getRepoPath() {
- return $this->path;
- }
-
- public function setRepoPath($directory) {
- if (is_dir($directory)) {
- $this->path->$directory;
- $this->git->setRepository($directory);
- return true;
- }
- return false;
- }
-
- public function setIdentity($user_name, $user_email) {
- // setup user for commit messages
- $this->git->config->set("user.name", $user_name, ['global' => false, 'system' => false]);
- $this->git->config->set("user.email", $user_email, ['global' => false, 'system' => false]);
- }
-
- public function cloneRepo() {
- if (validate_url($this->url) && $this->isValidGitRepoURL($this->url) && is_dir($this->path)) {
- return $this->git->clone($this->url, $this->path);
- }
- }
-
- public function probeRepo() {
- $git = $this->git;
- $repo = array();
- $repo['remote'] = $git->remote();
- $repo['branches'] = $git->branch(['all' => true]);
- $repo['logs'] = $git->log(array('limit' => 50));
- return $repo;
- }
-
- // Commit changes to the repo. Default is to stage all changes and commit everything.
- public function commit($msg, $options = array()) {
- try {
- return $this->git->commit($msg, $options);
- } catch (\PHPGit\Exception\GitException $ex) {
- return false;
- }
- }
-
- public static function isValidGitRepoURL($url) {
- if (validate_url($url) && strrpos(parse_url($url, PHP_URL_PATH), '.')) {
- return true;
- } else {
- return false;
- }
- }
-
- public static function getRepoNameFromURL($url) {
- $urlpath = parse_url($url, PHP_URL_PATH);
- $lastslash = strrpos($urlpath, '/') + 1;
- $gitext = strrpos($urlpath, '.');
- if ($gitext) {
- return substr($urlpath, $lastslash, $gitext - $lastslash);
- } else {
- return null;
- }
- }
-
-}
diff --git a/Zotlabs/Thumbs/Epubthumb.php b/Zotlabs/Thumbs/Epubthumb.php
index 6ebbd8933..af372e85c 100644
--- a/Zotlabs/Thumbs/Epubthumb.php
+++ b/Zotlabs/Thumbs/Epubthumb.php
@@ -2,60 +2,197 @@
namespace Zotlabs\Thumbs;
-require_once 'library/epub-meta/epub.php';
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+use GdImage;
+use ZipArchive;
/**
- * @brief Thumbnail creation for epub files.
- *
+ * Thumbnail creation for epub files.
*/
class Epubthumb {
/**
- * @brief Match for application/epub+zip.
+ * Match for application/epub+zip.
*
* @param string $type MimeType
* @return boolean
*/
- function Match($type) {
- return(($type === 'application/epub+zip') ? true : false );
+ function Match(string $type): bool {
+ return $type === 'application/epub+zip';
}
/**
- * @brief
+ * Create the thumbnail if the Epub has a cover.
*
* @param array $attach
- * @param number $preview_style unused
- * @param number $height (optional) default 300
- * @param number $width (optional) default 300
+ * @param int $preview_style unused
+ * @param int $height (optional) default 300
+ * @param int $width (optional) default 300
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
*/
- function Thumb($attach, $preview_style, $height = 300, $width = 300) {
+ function Thumb($attach, $preview_style, $height = 300, $width = 300): void {
$file = dbunescbin($attach['content']);
if (!$file) {
return;
}
- $photo = false;
-
- $ep = new \EPub($file);
- $data = $ep->Cover();
-
- if($data['found']) {
- $photo = $data['data'];
- }
+ $image = $this->getCoverFromEpub($file);
- if($photo) {
- $image = imagecreatefromstring($photo);
- $dest = imagecreatetruecolor($width, $height);
+ if ($image) {
$srcwidth = imagesx($image);
$srcheight = imagesy($image);
+ $dest = imagecreatetruecolor($width, $height);
imagealphablending($dest, false);
imagesavealpha($dest, true);
+
imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight);
+
+ imagejpeg($dest, "{$file}.thumb");
+
imagedestroy($image);
- imagejpeg($dest, dbunescbin($attach['content']) . '.thumb');
+ imagedestroy($dest);
}
}
+
+ /**
+ * Fetch the cover from the epub archive, if it's present.
+ *
+ * There's a few limitations here: This will only work if the cover
+ * is a raster image of a supported format. SVG does not work, neither
+ * will other schemes sometimes used for cover/front page.
+ *
+ * @param string $filename The local filename of the epub archive.
+ *
+ * @return GdImage|false If a cover is found, it is returned as a
+ * GdImage object. Otherwise return false.
+ */
+ private function getCoverFromEpub(string $filename): GdImage|false {
+ $epub = new ZipArchive();
+ $rc = $epub->open($filename, ZipArchive::RDONLY);
+
+ if ($rc !== true) {
+ logger("Error opening file '{$filename}': rc = ${rc}.", LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $cover = false;
+ $cover_name = $this->parseEpub($epub);
+ if ($cover_name !== false) {
+ $cover = $epub->getFromName($cover_name);
+ if ($cover === false) {
+ logger("File '{$cover_name}' not found in EPUB.", LOGGER_DEBUG, LOG_DEBUG);
+ }
+ }
+
+ $epub->close();
+
+ if ($cover !== false && !empty($cover)) {
+ return imagecreatefromstring($cover);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Parse the epub to find the path of the cover image.
+ *
+ * @param ZipArchive $epub An opened epub ZipArchive.
+ *
+ * @return string|false The path to the cover image or false.
+ */
+ private function parseEpub(ZipArchive $epub): string|false {
+ $packagePath = $this->getEpubPackagePath($epub);
+ if ($packagePath !== false) {
+ $package = $epub->getFromName($packagePath);
+ if ($package === false || empty($package)) {
+ logger("Package file '${packagePath}' not found in EPUB", LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $domdoc = new DOMDocument();
+ $domdoc->loadXML($package);
+ $xpath = new DOMXPath($domdoc);
+ $xpath->registerNamespace("n", "http://www.idpf.org/2007/opf");
+ $nodes = $xpath->query('/n:package/n:manifest/n:item[@properties="cover-image"]');
+
+ if ($nodes->count() === 0) {
+ logger('No cover found in EPUB manifest.', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $node = $nodes->item(0);
+ if ($node === null) {
+ logger('No nodes in non-empty node list?', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ if (is_a($node, DOMElement::class)) {
+ // The URL's in the package file is relative to the subdirectory
+ // within the epub archive where it is located. See
+ // https://www.w3.org/TR/epub-33/#sec-parsing-urls-metainf
+ return dirname($packagePath) . '/' . $node->getAttribute('href');
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Locate the package file within the epub.
+ *
+ * The package file in an epub archive contains the manifest
+ * that again may contain a reference to the cover for the
+ * epub.
+ *
+ * @param ZipArchive $epub An opened epub archive.
+ *
+ * @return string|false The full pathname of the package file or false.
+ */
+ private function getEpubPackagePath(ZipArchive $epub): string|false {
+ //
+ // The only mandatory known file within the archive is the
+ // container file, so we fetch it to find the reference to
+ // the package file.
+ //
+ // See: https://www.w3.org/TR/epub-33/#sec-container-metainf
+ //
+ $container = $epub->getFromName('META-INF/container.xml');
+
+ if ($container === false || empty($container)) {
+ logger('No container in archive, probably not an EPUB.', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $domdoc = new DOMDocument();
+ $domdoc->loadXML($container);
+ $nodes = $domdoc->getElementsByTagName('rootfile');
+
+ if ($nodes->count() == 0) {
+ logger('EPUB rootfile not found, is this an epub?', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $packageNode = $nodes->item(0);
+ if ($packageNode === null || !is_a($packageNode, DOMElement::class)) {
+ logger('EPUB rootfile element missing or invalid.', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ $packagePath = $packageNode->getAttribute('full-path');
+ $packageMediaType = $packageNode->getAttribute('media-type');
+
+ if (empty($packagePath) || $packageMediaType !== 'application/oebps-package+xml') {
+ logger('EPUB package path missing or incorrect media type.', LOGGER_DEBUG, LOG_DEBUG);
+ return false;
+ }
+
+ return $packagePath;
+ }
}
diff --git a/Zotlabs/Update/_1007.php b/Zotlabs/Update/_1007.php
index eb52c5bc5..74e1bb310 100644
--- a/Zotlabs/Update/_1007.php
+++ b/Zotlabs/Update/_1007.php
@@ -6,10 +6,10 @@ class _1007 {
function run() {
$r = q("ALTER TABLE `channel` ADD `channel_r_storage` INT UNSIGNED NOT NULL DEFAULT '128', ADD `channel_w_storage` INT UNSIGNED NOT NULL DEFAULT '128', add index ( channel_r_storage ), add index ( channel_w_storage )");
- if($r && $r2)
+ if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Update/_1151.php b/Zotlabs/Update/_1151.php
index d14baabb1..20f3180a0 100644
--- a/Zotlabs/Update/_1151.php
+++ b/Zotlabs/Update/_1151.php
@@ -8,7 +8,7 @@ function run() {
$r3 = q("select likes.*, item.mid from likes left join item on likes.iid = item.id");
if($r3) {
foreach($r3 as $rr) {
- q("update likes set i_mid = '%s' where id = $d",
+ q("update likes set i_mid = '%s' where id = %d",
dbesc($rr['mid']),
intval($rr['id'])
);
@@ -21,4 +21,4 @@ function run() {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
index 7c289ff5f..ce56ae46b 100644
--- a/Zotlabs/Web/HTTPSig.php
+++ b/Zotlabs/Web/HTTPSig.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Web;
+use App;
use DateTime;
use DateTimeZone;
use Zotlabs\Lib\Activity;
@@ -11,6 +12,7 @@ use Zotlabs\Lib\Keyutils;
use Zotlabs\Lib\Webfinger;
use Zotlabs\Lib\Zotfinger;
use Zotlabs\Lib\Libzot;
+use HttpSignature\HttpMessageSigner;
/**
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
@@ -88,7 +90,7 @@ class HTTPSig {
// See draft-cavage-http-signatures-10
- static function verify($data, $key = '', $keytype = '') {
+ public static function verify($data, $key = '', $keytype = '') {
$body = $data;
$headers = null;
@@ -102,11 +104,49 @@ class HTTPSig {
'content_valid' => false
];
-
$headers = self::find_headers($data, $body);
- if (!$headers)
+ if (!$headers) {
return $result;
+ }
+
+ if (array_key_exists('signature-input', $headers) && array_key_exists('signature', $headers)) {
+ $found = preg_match('/keyid="(.*?)"/', $headers['signature-input'], $matches);
+ $keyId = ($found) ? $matches[1] : '';
+
+ if (!$keyId) {
+ return $result;
+ }
+
+ $found = preg_match('/alg="(.*?)"/', $headers['signature-input'], $matches);
+ $alg = ($found) ? $matches[1] : null;
+
+ $keyInfo = self::get_key($key, $keytype, $keyId);
+ $publicKey = $keyInfo['public_key'];
+
+ $messageSigner = new HttpMessageSigner();
+
+ $messageSigner->setPublicKey($publicKey);
+ $messageSigner->setAlgorithm($alg);
+ $messageSigner->setKeyId($keyId);
+
+ $messageSigner->setNonce(preg_match('/nonce="(.*?)"/', $headers['signature-input'], $matches) ? $matches[1] : '');
+ $messageSigner->setTag(preg_match('/tag="(.*?)"/', $headers['signature-input'], $matches) ? $matches[1] : '');
+ $messageSigner->setCreated(preg_match('/created=([0-9]+)/', $headers['signature-input'], $matches) ? $matches[1] : '');
+ $messageSigner->setExpires(preg_match('/expires=([0-9]+)/', $headers['signature-input'], $matches) ? $matches[1] : '');
+
+ $verified = $messageSigner->verifyRequest(App::$request);
+ logger('verified (RFC9421): ' . (($verified) ? 'true' : 'false'), LOGGER_DEBUG);
+
+ return [
+ 'signer' => $keyId,
+ 'portable_id' => $keyInfo['portable_id'] ?? '',
+ 'header_signed' => true,
+ 'header_valid' => $verified,
+ 'content_signed' => array_key_exists('content-digest', $headers),
+ 'content_valid' => $verified
+ ];
+ }
if (is_array($body)) {
btlogger('body is array:' . print_r($body, true));
diff --git a/Zotlabs/Web/HttpMeta.php b/Zotlabs/Web/HttpMeta.php
index 7cf93dda9..d12037a51 100644
--- a/Zotlabs/Web/HttpMeta.php
+++ b/Zotlabs/Web/HttpMeta.php
@@ -5,16 +5,9 @@ namespace Zotlabs\Web;
class HttpMeta {
- private $vars = null;
- private $og = null;
-
- function __construct() {
-
- $this->vars = [];
- $this->og = [];
- $this->ogproperties = [];
-
- }
+ private $vars = [];
+ private $og = [];
+ private $ogproperties = [];
//Set Meta Value
// Mode:
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index 122e7ff73..9f4cb4b4a 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -4,6 +4,7 @@ namespace Zotlabs\Web;
use App;
use Zotlabs\Extend\Route;
+use Zotlabs\Render\Theme;
use Zotlabs\Lib\Config;
use Exception;
@@ -33,6 +34,7 @@ use Exception;
* so within the module init and/or post functions and then invoke killme() to terminate
* further processing.
*/
+
class Router {
private $modname = '';
@@ -49,7 +51,7 @@ class Router {
$module = App::$module;
$modname = "Zotlabs\\Module\\" . ucfirst($module);
- if(strlen($module)) {
+ if(!empty($module)) {
/*
* We will always have a module name.
@@ -57,11 +59,11 @@ class Router {
*/
$routes = Route::get();
- if($routes) {
+ if ($routes) {
foreach($routes as $route) {
- if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
+ if (is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
include_once($route[0]);
- if(class_exists($modname)) {
+ if (class_exists($modname)) {
$this->controller = new $modname;
$this->module_loaded = true;
}
@@ -71,14 +73,14 @@ class Router {
// legacy plugins - this can be removed when they have all been converted
- if(! ($this->module_loaded)) {
- if(is_array(App::$plugins) && in_array($module, App::$plugins) && file_exists("addon/{$module}/{$module}.php")) {
+ if (!$this->module_loaded) {
+ if (is_array(App::$plugins) && in_array($module, App::$plugins) && file_exists("addon/{$module}/{$module}.php")) {
include_once("addon/{$module}/{$module}.php");
- if(class_exists($modname)) {
+ if (class_exists($modname)) {
$this->controller = new $modname;
$this->module_loaded = true;
}
- elseif(function_exists($module . '_module')) {
+ elseif (function_exists($module . '_module')) {
$this->module_loaded = true;
}
}
@@ -89,7 +91,7 @@ class Router {
* Otherwise, look for the standard program module
*/
- if(! ($this->module_loaded)) {
+ if (!$this->module_loaded) {
try {
$filename = 'Zotlabs/SiteModule/'. ucfirst($module). '.php';
if(file_exists($filename)) {
@@ -105,15 +107,16 @@ class Router {
$this->module_loaded = true;
}
}
- if(! $this->module_loaded)
+ if (!$this->module_loaded) {
throw new Exception('Module not found');
+ }
}
- catch(Exception $e) {
- if(file_exists("mod/site/{$module}.php")) {
+ catch (Exception $e) {
+ if (file_exists("mod/site/{$module}.php")) {
include_once("mod/site/{$module}.php");
$this->module_loaded = true;
}
- elseif(file_exists("mod/{$module}.php")) {
+ elseif (file_exists("mod/{$module}.php")) {
include_once("mod/{$module}.php");
$this->module_loaded = true;
}
@@ -125,6 +128,7 @@ class Router {
'installed' => $this->module_loaded,
'controller' => $this->controller
];
+
/**
* @hooks module_loaded
* Called when a module has been successfully locate to server a URL request.
@@ -138,7 +142,8 @@ class Router {
* * \e mixed \b controller - The initialized module object
*/
call_hooks('module_loaded', $x);
- if($x['installed']) {
+
+ if ($x['installed']) {
$this->module_loaded = true;
$this->controller = $x['controller'];
}
@@ -147,7 +152,7 @@ class Router {
* The URL provided does not resolve to a valid module.
*/
- if(! ($this->module_loaded)) {
+ if (!$this->module_loaded) {
// undo the setting of a letsencrypt acme-challenge rewrite rule
// which blocks access to our .well-known routes.
@@ -155,8 +160,8 @@ class Router {
// for a custom .htaccess in the .well-known directory; but they should
// make the file read-only so letsencrypt doesn't modify it
- if(strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
- if(file_exists('.well-known/.htaccess') && Config::Get('system','fix_apache_acme',true)) {
+ if (strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
+ if (file_exists('.well-known/.htaccess') && Config::Get('system','fix_apache_acme',true)) {
rename('.well-known/.htaccess','.well-known/.htaccess.old');
}
}
@@ -166,16 +171,17 @@ class Router {
'installed' => $this->module_loaded,
'controller' => $this->controller
];
+
call_hooks('page_not_found',$x);
// Stupid browser tried to pre-fetch our Javascript img template.
// Don't log the event or return anything - just quietly exit.
- if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
+ if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
killme();
}
- if(Config::Get('system','log_404',true)) {
+ if (Config::Get('system','log_404',true)) {
logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING);
logger('index.php: page not found: ' . $_SERVER['REQUEST_URI']
. ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: '
@@ -206,7 +212,7 @@ class Router {
* Call module functions
*/
- if($this->module_loaded) {
+ if ($this->module_loaded) {
App::$page['page_title'] = App::$module;
$placeholder = '';
@@ -218,13 +224,18 @@ class Router {
* to over-ride them.
*/
- $arr = array('init' => true, 'replace' => false);
+ $arr = [
+ 'init' => true,
+ 'replace' => false
+ ];
+
call_hooks(App::$module . '_mod_init', $arr);
- if(! $arr['replace']) {
- if($this->controller && method_exists($this->controller,'init')) {
+
+ if (!$arr['replace']) {
+ if ($this->controller && method_exists($this->controller,'init')) {
$this->controller->init();
}
- elseif(function_exists(App::$module . '_init')) {
+ elseif (function_exists(App::$module . '_init')) {
$func = App::$module . '_init';
$func();
}
@@ -250,52 +261,58 @@ class Router {
* load current theme info
*/
- $current_theme = \Zotlabs\Render\Theme::current();
+ $current_theme = Theme::current();
$theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php';
if (file_exists($theme_info_file)){
require_once($theme_info_file);
}
- if(function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
+ if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
$func = str_replace('-', '_', $current_theme[0]) . '_init';
$func();
}
- elseif (x(App::$theme_info, 'extends') && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) {
+ elseif (!empty(App::$theme_info['extends']) && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) {
require_once('view/theme/' . App::$theme_info['extends'] . '/php/theme.php');
- if(function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) {
+ if (function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) {
$func = str_replace('-', '_', App::$theme_info['extends']) . '_init';
$func();
}
}
- if(($_SERVER['REQUEST_METHOD'] === 'POST') && (! App::$error) && (! x($_POST, 'auth-params'))) {
+ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !App::$error && empty($_POST['auth-params'])) {
call_hooks(App::$module . '_mod_post', $_POST);
- if($this->controller && method_exists($this->controller,'post')) {
+ if ($this->controller && method_exists($this->controller, 'post')) {
$this->controller->post();
}
- elseif(function_exists(App::$module . '_post')) {
+ elseif (function_exists(App::$module . '_post')) {
$func = App::$module . '_post';
$func();
}
}
- if(! App::$error) {
- $arr = array('content' => App::$page['content'], 'replace' => false);
+ if (!App::$error) {
+ $arr = [
+ 'content' => App::$page['content'],
+ 'replace' => false
+ ];
+
call_hooks(App::$module . '_mod_content', $arr);
- if(! $arr['replace']) {
- if($this->controller && method_exists($this->controller,'get')) {
+ if (!$arr['replace']) {
+ if ($this->controller && method_exists($this->controller, 'get')) {
$arr = array('content' => $this->controller->get());
}
- elseif(function_exists(App::$module . '_content')) {
+ elseif (function_exists(App::$module . '_content')) {
$func = App::$module . '_content';
$arr = array('content' => $func());
}
}
+
call_hooks(App::$module . '_mod_aftercontent', $arr);
- App::$page['content'] = ((isset($arr['replace'])) ? $arr['content'] : App::$page['content'] . $arr['content']);
+
+ App::$page['content'] = ((empty($arr['replace'])) ? App::$page['content'] . $arr['content'] : $arr['content']);
}
}
}
diff --git a/Zotlabs/Web/Session.php b/Zotlabs/Web/Session.php
index ec26e6b0d..1762d3832 100644
--- a/Zotlabs/Web/Session.php
+++ b/Zotlabs/Web/Session.php
@@ -132,7 +132,7 @@ class Session {
else
logger('no session handler');
- if (x($_COOKIE, 'jsdisabled')) {
+ if (!empty($_COOKIE['jsdisabled'])) {
setcookie(
'jsdisabled',
$_COOKIE['jsdisabled'],
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
index 6f8a4b956..89ef755d9 100644
--- a/Zotlabs/Web/WebServer.php
+++ b/Zotlabs/Web/WebServer.php
@@ -2,6 +2,10 @@
namespace Zotlabs\Web;
+use App;
+use Zotlabs\Lib\Text;
+use GuzzleHttp\Psr7\ServerRequest;
+
class WebServer {
public function run() {
@@ -15,9 +19,10 @@ class WebServer {
$installed = sys_boot();
+ App::$request = ServerRequest::fromGlobals();
- \App::$language = get_best_language();
- load_translation_table(\App::$language, !$installed);
+ App::$language = get_best_language();
+ load_translation_table(App::$language, !$installed);
/**
@@ -31,8 +36,8 @@ class WebServer {
*
*/
- if(\App::$session) {
- \App::$session->start();
+ if(App::$session) {
+ App::$session->start();
}
else {
session_start();
@@ -51,16 +56,16 @@ class WebServer {
unset($_SESSION['language']);
}
- if ((x($_SESSION, 'language')) && ($_SESSION['language'] !== \App::$language)) {
- \App::$language = $_SESSION['language'];
+ if ((!empty($_SESSION['language'])) && ($_SESSION['language'] !== App::$language)) {
+ App::$language = $_SESSION['language'];
load_translation_table(\App::$language);
}
- if (x($_GET,'zid') && $installed) {
- \App::$query_string = strip_zids(\App::$query_string);
+ if (!empty($_GET['zid']) && $installed) {
+ App::$query_string = strip_zids(App::$query_string);
if(! local_channel()) {
- if (!isset($_SESSION['my_address']) || $_SESSION['my_address'] != $_GET['zid']) {
- $_SESSION['my_address'] = $_GET['zid'];
+ if (!isset($_SESSION['my_address'])) {
+ $_SESSION['my_address'] = Text::escape_tags($_GET['zid']);
$_SESSION['authenticated'] = 0;
}
if(!$_SESSION['authenticated']) {
@@ -69,26 +74,28 @@ class WebServer {
}
}
- if (x($_GET,'zat') && $installed) {
- \App::$query_string = strip_zats(\App::$query_string);
+ if (!empty($_GET['zat']) && $installed) {
+ App::$query_string = strip_zats(App::$query_string);
if(! local_channel()) {
zat_init();
}
}
- if (x($_REQUEST,'owt') && $installed) {
+ if (!empty($_REQUEST['owt']) && $installed) {
$token = $_REQUEST['owt'];
- \App::$query_string = strip_query_param(\App::$query_string,'owt');
+ App::$query_string = strip_query_param(App::$query_string,'owt');
owt_init($token);
}
- if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
+ if(!empty($_SESSION['authenticated']) || !empty($_POST['auth-params']) || App::$module === 'login') {
require('include/auth.php');
+ }
if (!$installed) {
/* Allow an exception for the view module so that pcss will be interpreted during installation */
- if(\App::$module != 'view')
- \App::$module = 'setup';
+ if(App::$module != 'view') {
+ App::$module = 'setup';
+ }
}
else {
@@ -109,17 +116,7 @@ class WebServer {
$Router->Dispatch();
- // TODO: this is not used for anything atm and messes up comanche templates by adding some javascript
- //$this->set_homebase();
-
- // now that we've been through the module content, see if the page reported
- // a permission problem and if so, a 403 response would seem to be in order.
-
- if(isset($_SESSION['sysmsg']) && is_array($_SESSION['sysmsg']) && stristr(implode("", $_SESSION['sysmsg']), t('Permission denied'))) {
- header($_SERVER['SERVER_PROTOCOL'] . ' 403 ' . t('Permission denied.'));
- }
-
- call_hooks('page_end', \App::$page['content']);
+ call_hooks('page_end', App::$page['content']);
construct_page();
@@ -131,10 +128,11 @@ class WebServer {
/* initialise content region */
- if(! x(\App::$page, 'content'))
- \App::$page['content'] = '';
+ if(empty(App::$page['content'])) {
+ App::$page['content'] = '';
+ }
- call_hooks('page_content_top', \App::$page['content']);
+ call_hooks('page_content_top', App::$page['content']);
}
@@ -146,44 +144,24 @@ class WebServer {
* to all protocol drivers; thus doing it here avoids duplication.
*/
- if (( \App::$module === 'channel' ) && argc() > 1) {
- \App::$channel_links = [
+ if (App::$module === 'channel' && argc() > 1) {
+ App::$channel_links = [
[
'rel' => 'lrdd',
'type' => 'application/xrd+xml',
- 'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ 'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . App::get_hostname()
],
[
'rel' => 'jrd',
'type' => 'application/jrd+json',
- 'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ 'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . App::get_hostname()
],
];
- $x = [ 'channel_address' => argv(1), 'channel_links' => \App::$channel_links ];
+ $x = [ 'channel_address' => argv(1), 'channel_links' => App::$channel_links ];
call_hooks('channel_links', $x );
- \App::$channel_links = $x['channel_links'];
+ App::$channel_links = $x['channel_links'];
header('Link: ' . \App::get_channel_links());
}
}
-
- private function set_homebase() {
-
- // If you're just visiting, let javascript take you home
-
- if(x($_SESSION, 'visitor_home')) {
- $homebase = $_SESSION['visitor_home'];
- }
- elseif(local_channel()) {
- $homebase = z_root() . '/channel/' . \App::$channel['channel_address'];
- }
-
- if(isset($homebase)) {
- \App::$page['content'] .= '<script>var homebase = "' . $homebase . '";</script>';
- }
-
- }
-
-
-
}
diff --git a/Zotlabs/Widget/Activity.php b/Zotlabs/Widget/Activity.php
index 34e0f67dc..19f7acadb 100644
--- a/Zotlabs/Widget/Activity.php
+++ b/Zotlabs/Widget/Activity.php
@@ -17,7 +17,7 @@ class Activity {
$o = '';
if(is_array($arr) && array_key_exists('limit',$arr))
- $limit = " limit " . intval($limit) . " ";
+ $limit = " limit " . intval($arr['limit']) . " ";
else
$limit = '';
diff --git a/Zotlabs/Widget/Activity_order.php b/Zotlabs/Widget/Activity_order.php
index e8ee11508..8d47370db 100644
--- a/Zotlabs/Widget/Activity_order.php
+++ b/Zotlabs/Widget/Activity_order.php
@@ -16,7 +16,7 @@ class Activity_order {
return '';
if(! feature_enabled(local_channel(),'order_tab')) {
- set_pconfig(local_channel(), 'mod_network', 'order', 0);
+ set_pconfig(local_channel(), 'mod_network', 'order', 'created');
return '';
}
@@ -26,17 +26,17 @@ class Activity_order {
if(x($_GET, 'order')) {
switch($_GET['order']){
- case 'post':
+ case 'created':
$postord_active = 'active';
- set_pconfig(local_channel(), 'mod_network', 'order', 1);
+ set_pconfig(local_channel(), 'mod_network', 'order', 'created');
break;
- case 'comment':
+ case 'commented':
$commentord_active = 'active';
- set_pconfig(local_channel(), 'mod_network', 'order', 0);
+ set_pconfig(local_channel(), 'mod_network', 'order', 'commented');
break;
case 'unthreaded':
$unthreaded_active = 'active';
- set_pconfig(local_channel(), 'mod_network', 'order', 2);
+ set_pconfig(local_channel(), 'mod_network', 'order', 'unthreaded');
break;
default:
$commentord_active = 'active';
@@ -44,19 +44,19 @@ class Activity_order {
}
}
else {
- $order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
+ $order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
switch($order) {
- case 0:
+ case 'commented':
$commentord_active = 'active';
break;
- case 1:
+ case 'created':
$postord_active = 'active';
break;
- case 2:
+ case 'unthreaded':
$unthreaded_active = 'active';
break;
default:
- $commentord_active = 'active';
+ $postord_active = 'active';
}
}
@@ -90,26 +90,26 @@ class Activity_order {
// tabs
- $tabs = [];
+ $tabs[] = [
+ 'label' => t('Posted Date'),
+ 'icon' => '',
+ 'url'=>z_root() . '/' . $cmd . '?order=created' . $filter,
+ 'sel'=> $postord_active,
+ 'title' => t('Order by last posted date'),
+ ];
$tabs[] = [
'label' => t('Commented Date'),
'icon' => '',
- 'url'=>z_root() . '/' . $cmd . '?f=&order=comment' . $filter,
+ 'url'=>z_root() . '/' . $cmd . '?order=commented' . $filter,
'sel'=> $commentord_active,
'title' => t('Order by last commented date'),
];
- $tabs[] = [
- 'label' => t('Posted Date'),
- 'icon' => '',
- 'url'=>z_root() . '/' . $cmd . '?f=&order=post' . $filter,
- 'sel'=> $postord_active,
- 'title' => t('Order by last posted date'),
- ];
+
$tabs[] = array(
'label' => t('Date Unthreaded'),
'icon' => '',
- 'url' => z_root() . '/' . $cmd . '?f=&order=unthreaded' . $filter,
+ 'url' => z_root() . '/' . $cmd . '?order=unthreaded' . $filter,
'sel' => $unthreaded_active,
'title' => t('Order unthreaded by date'),
);
diff --git a/Zotlabs/Widget/Album.php b/Zotlabs/Widget/Album.php
index 003f6f49d..667952360 100644
--- a/Zotlabs/Widget/Album.php
+++ b/Zotlabs/Widget/Album.php
@@ -59,6 +59,9 @@ class Album {
//edit album name
$album_edit = null;
+ $ph = photo_factory('');
+ $phototypes = $ph->supportedTypes();
+
$photos = array();
if($r) {
$twist = 'rotright';
@@ -94,7 +97,7 @@ class Album {
$tpl = get_markup_template('photo_album.tpl');
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$photos' => $photos,
'$album' => (($title) ? $title : $album),
'$album_id' => rand(),
@@ -102,11 +105,9 @@ class Album {
'$can_post' => false,
'$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
'$order' => false,
- '$upload_form' => $upload_form,
- '$usage' => $usage_message
+ '$upload_form' => '', // $upload_form,
+ '$usage' => '', // $usage_message
));
-
- return $o;
}
}
diff --git a/Zotlabs/Widget/Channel_activities.php b/Zotlabs/Widget/Channel_activities.php
index a799ea81e..2677f82c3 100644
--- a/Zotlabs/Widget/Channel_activities.php
+++ b/Zotlabs/Widget/Channel_activities.php
@@ -91,7 +91,7 @@ class Channel_activities {
self::$activities['photos'] = [
'label' => t('Photos'),
- 'icon' => 'photo',
+ 'icon' => 'image',
'url' => z_root() . '/photos/' . self::$channel['channel_address'],
'date' => $r[0]['edited'],
'items' => $i,
@@ -123,7 +123,7 @@ class Channel_activities {
self::$activities['files'] = [
'label' => t('Files'),
- 'icon' => 'folder-open',
+ 'icon' => 'folder',
'url' => z_root() . '/cloud/' . self::$channel['channel_address'],
'date' => $r[0]['edited'],
'items' => $i,
@@ -166,7 +166,7 @@ class Channel_activities {
self::$activities['webpages'] = [
'label' => t('Webpages'),
- 'icon' => 'newspaper-o',
+ 'icon' => 'layout-text-sidebar',
'url' => z_root() . '/webpages/' . self::$channel['channel_address'],
'date' => $r[0]['edited'],
'items' => $i,
@@ -223,7 +223,7 @@ class Channel_activities {
$i[] = [
'url' => z_root() . '/manage/' . $rr['channel_id'],
'title' => '',
- 'summary' => '<div class="text-truncate lh-sm"><img src="' . $rr['xchan_photo_s'] . '" class="menu-img-2">' . '<strong>' . $rr['channel_name'] . '</strong><br><small class="opacity-75">' . $rr['xchan_addr'] . '</small></div>',
+ 'summary' => '<div class="text-truncate lh-sm"><img src="' . $rr['xchan_photo_s'] . '" class="menu-img-2">' . '<strong>' . $rr['channel_name'] . '</strong><br><small class="text-body-secondary">' . $rr['xchan_addr'] . '</small></div>',
'footer' => $footer
];
@@ -237,7 +237,7 @@ class Channel_activities {
self::$activities['channels'] = [
'label' => t('Channels'),
- 'icon' => 'home',
+ 'icon' => 'house',
'url' => z_root() . '/manage',
'date' => datetime_convert(),
'items' => $i,
diff --git a/Zotlabs/Widget/Item.php b/Zotlabs/Widget/Item.php
index 6f943ffdf..3de135cb9 100644
--- a/Zotlabs/Widget/Item.php
+++ b/Zotlabs/Widget/Item.php
@@ -34,7 +34,7 @@ class Item {
if($arr['title']) {
$r = q("select item.* from item left join iconfig on item.id = iconfig.iid
where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s'
- and iconfig.k = 'WEBPAGE' and item_type = %d $sql_extra $revision limit 1",
+ and iconfig.k = 'WEBPAGE' and item_type = %d $sql_extra limit 1",
intval($channel_id),
dbesc($arr['title']),
intval(ITEM_TYPE_WEBPAGE)
diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php
index 294a982b1..cc1811ffc 100644
--- a/Zotlabs/Widget/Messages.php
+++ b/Zotlabs/Widget/Messages.php
@@ -23,20 +23,37 @@ class Messages {
$_SESSION['messages_loadtime'] = datetime_convert();
+ $r = q("SELECT DISTINCT(term) FROM term WHERE uid = %d AND ttype = %d ORDER BY term",
+ intval(local_channel()),
+ intval(TERM_FILE)
+ );
+
+ $file_tags = [];
+
+ if ($r) {
+ foreach($r as $rr) {
+ $file_tags[] = $rr['term'];
+ }
+ }
+
$tpl = get_markup_template('messages_widget.tpl');
$o = replace_macros($tpl, [
'$entries' => $page['entries'] ?? [],
'$offset' => $page['offset'] ?? 0,
'$feature_star' => feature_enabled(local_channel(), 'star_posts'),
+ '$feature_file' => feature_enabled(local_channel(), 'filing'),
+ '$file_tags' => $file_tags,
'$strings' => [
- 'messages_title' => t('Public and restricted messages'),
- 'direct_messages_title' => t('Direct messages'),
- 'starred_messages_title' => t('Starred messages'),
- 'notice_messages_title' => t('Notices'),
+ 'messages_title' => t('Public and restricted conversations'),
+ 'direct_messages_title' => t('Private conversations'),
+ 'starred_messages_title' => t('Starred conversations'),
+ 'filed_messages_title' => t('Filed messages'),
+ 'notice_messages_title' => t('Notifications'),
'loading' => t('Loading'),
- 'empty' => t('No messages'),
- 'unseen_count' => t('Unseen'),
- 'filter' => t('Filter by name or address')
+ 'empty' => t('No conversations'),
+ 'unseen_count' => t('Unseen reactions'),
+ 'filter' => t('Filter by name or address'),
+ 'file_filter' => t('Filter by file name')
]
]);
@@ -50,6 +67,7 @@ class Messages {
$offset = $options['offset'] ?? 0;
$type = $options['type'] ?? '';
$author = $options['author'] ?? '';
+ $file = $options['file'] ?? '';
if ($offset == -1) {
return;
@@ -67,8 +85,7 @@ class Messages {
$item_normal_c = str_replace('item.', 'c.', $item_normal);
$entries = [];
$limit = 30;
- $dummy_order_sql = '';
- $author_sql = '';
+ $order_sql = 'i.created DESC';
$loadtime = (($offset) ? $_SESSION['messages_loadtime'] : datetime_convert());
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify', -1);
@@ -84,43 +101,59 @@ class Messages {
$vnotify_sql_i = " AND i.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
- if($author) {
- $author_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
+ $filter_sql = '';
+ if($type !== 'filed' && $author) {
+ $filter_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
}
+ $filed_filter_sql = '';
+ if($type === 'filed' && $file) {
+ $filed_filter_sql = " AND (term.term = '" . protect_sprintf(dbesc($file)) . "') ";
+ }
+
+ $dummy_order_sql = '';
+
switch($type) {
case 'direct':
- $type_sql = ' AND i.item_private = 2 ';
+ $type_sql = ' AND i.item_private = 2 AND i.item_thread_top = 1 ';
// $dummy_order_sql has no other meaning but to trick
// some mysql backends into using the right index.
$dummy_order_sql = ', i.received DESC ';
break;
case 'starred':
- $type_sql = ' AND i.item_starred = 1 ';
+ $type_sql = ' AND i.item_starred = 1 AND i.item_thread_top = 1 ';
+ break;
+ case 'filed':
+ $type_sql = ' AND i.id IN (SELECT term.oid FROM term WHERE term.ttype = ' . TERM_FILE . ' AND term.uid = i.uid ' . $filed_filter_sql . ')';
break;
default:
- $type_sql = ' AND i.item_private IN (0, 1) ';
+ $type_sql = ' AND i.item_private IN (0, 1) AND i.item_thread_top = 1 ';
}
$items = q("SELECT *,
(SELECT count(*) FROM item c WHERE c.uid = %d AND c.parent = i.parent AND c.item_unseen = 1 AND c.item_thread_top = 0 $item_normal_c $vnotify_sql_c) AS unseen_count
- FROM item i WHERE i.uid = %d
+ FROM item i
+ WHERE i.uid = %d
AND i.created <= '%s'
$type_sql
- AND i.item_thread_top = 1
- $author_sql
+ $filter_sql
$item_normal_i
- ORDER BY i.created DESC $dummy_order_sql
+ ORDER BY $order_sql $dummy_order_sql
LIMIT $limit OFFSET $offset",
intval(local_channel()),
intval(local_channel()),
dbescdate($loadtime)
);
+ if ($type === 'filed') {
+ $items = fetch_post_tags($items);
+ }
+
xchan_query($items, false);
$i = 0;
$entries = [];
+ $ids = [];
foreach($items as $item) {
@@ -149,6 +182,16 @@ class Messages {
$info .= t('via') . ' ' . $item['source']['xchan_name'];
}
+ if ($type == 'filed') {
+ $info = '';
+ foreach ($item['term'] as $t) {
+ if ($t['ttype'] !== TERM_FILE) {
+ continue;
+ }
+ $info .= '<span class="badge rounded-pill bg-danger me-1"><i class="bi bi-folder"></i>&nbsp;' . $t['term'] . '</span>';
+ }
+ }
+
$summary = $item['title'];
if (!$summary) {
$summary = $item['summary'];
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
index 225403535..f9cee6e71 100644
--- a/Zotlabs/Widget/Notifications.php
+++ b/Zotlabs/Widget/Notifications.php
@@ -21,16 +21,16 @@ class Notifications {
'icon' => 'grid-3x3',
'severity' => 'secondary',
'label' => t('Network'),
- 'title' => t('New network activity notifications'),
+ 'title' => t('Unseen network activity'),
'viewall' => [
'url' => 'network',
'label' => t('Network stream')
],
'markall' => [
- 'label' => t('Mark all notifications read')
+ 'label' => t('Mark all read')
],
'filter' => [
- 'posts_label' => t('Show new posts only'),
+ 'posts_label' => t('Conversation starters'),
'name_label' => t('Filter by name or address')
]
];
@@ -40,17 +40,17 @@ class Notifications {
'type' => 'home',
'icon' => 'house',
'severity' => 'danger',
- 'label' => t('Home'),
- 'title' => t('New home activity notifications'),
+ 'label' => t('Channel'),
+ 'title' => t('Unseen channel activity'),
'viewall' => [
'url' => 'channel/' . $channel['channel_address'],
- 'label' => t('Home stream')
+ 'label' => t('Channel stream')
],
'markall' => [
- 'label' => t('Mark all notifications seen')
+ 'label' => t('Mark all seen')
],
'filter' => [
- 'posts_label' => t('Show new posts only'),
+ 'posts_label' => t('Conversation starters'),
'name_label' => t('Filter by name or address')
]
];
@@ -59,17 +59,17 @@ class Notifications {
'type' => 'dm',
'icon' => 'envelope',
'severity' => 'danger',
- 'label' => t('Direct Messages'),
- 'title' => t('New direct messages notifications'),
+ 'label' => t('Private'),
+ 'title' => t('Unseen private activity'),
'viewall' => [
'url' => 'network/?dm=1',
- 'label' => t('Direct messages stream')
+ 'label' => t('Private stream')
],
'markall' => [
- 'label' => t('Mark all notifications read')
+ 'label' => t('Mark all read')
],
'filter' => [
- 'posts_label' => t('Show new posts only'),
+ 'posts_label' => t('Conversation starters'),
'name_label' => t('Filter by name or address')
]
];
@@ -79,13 +79,13 @@ class Notifications {
'icon' => 'calendar-date',
'severity' => 'secondary',
'label' => t('Events'),
- 'title' => t('New events notifications'),
+ 'title' => t('Unseen events activity'),
'viewall' => [
'url' => 'cdav/calendar',
'label' => t('View events')
],
'markall' => [
- 'label' => t('Mark all events seen')
+ 'label' => t('Mark all seen')
]
];
@@ -94,10 +94,10 @@ class Notifications {
'icon' => 'people',
'severity' => 'danger',
'label' => t('New Connections'),
- 'title' => t('New connections notifications'),
+ 'title' => t('New connections'),
'viewall' => [
'url' => 'connections',
- 'label' => t('View all connections')
+ 'label' => t('View all')
]
];
@@ -106,21 +106,21 @@ class Notifications {
'icon' => 'folder',
'severity' => 'danger',
'label' => t('Files'),
- 'title' => t('New files notifications'),
+ 'title' => t('Useen files activity'),
];
$notifications[] = [
'type' => 'notify',
'icon' => 'exclamation-circle',
'severity' => 'danger',
- 'label' => t('Notices'),
- 'title' => t('Notices'),
+ 'label' => t('Notifications'),
+ 'title' => t('Unseen notifications'),
'viewall' => [
'url' => 'notifications/system',
- 'label' => t('View all notices')
+ 'label' => t('View all')
],
'markall' => [
- 'label' => t('Mark all notices seen')
+ 'label' => t('Mark all seen')
]
];
@@ -129,7 +129,7 @@ class Notifications {
'icon' => 'chat-quote',
'severity' => 'secondary',
'label' => t('Forums'),
- 'title' => t('Forums'),
+ 'title' => t('Unseen forums activity'),
'filter' => [
'name_label' => t('Filter by name or address')
]
@@ -142,7 +142,7 @@ class Notifications {
'icon' => 'person-exclamation',
'severity' => 'danger',
'label' => t('Registrations'),
- 'title' => t('New registrations notifications'),
+ 'title' => t('Unseen registration activity'),
];
}
@@ -152,7 +152,7 @@ class Notifications {
'icon' => 'globe',
'severity' => 'secondary',
'label' => t('Public Stream'),
- 'title' => t('New public stream notifications'),
+ 'title' => t('Unseen public stream activity'),
'viewall' => [
'url' => 'pubstream',
'label' => t('Public stream')
@@ -163,7 +163,7 @@ class Notifications {
],
*/
'filter' => [
- 'posts_label' => t('Show new posts only'),
+ 'posts_label' => t('Conversation starters'),
'name_label' => t('Filter by name or address')
]
];
diff --git a/Zotlabs/Widget/Pinned.php b/Zotlabs/Widget/Pinned.php
index 2ba170fe8..7b95d3bc6 100644
--- a/Zotlabs/Widget/Pinned.php
+++ b/Zotlabs/Widget/Pinned.php
@@ -67,19 +67,19 @@ class Pinned {
$attend = null;
$canvote = false;
- $conv_responses = [];
-
- if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
- $conv_responses['attendyes'] = [ 'title' => t('Attending','title') ];
- $conv_responses['attendno'] = [ 'title' => t('Not attending','title') ];
- $conv_responses['attendmaybe'] = [ 'title' => t('Might attend','title') ];
- if($commentable && $observer) {
- $attend = [ t('I will attend'), t('I will not attend'), t('I might attend') ];
- $isevent = true;
- }
+ $response_verbs[] = 'like';
+
+ if(feature_enabled(\App::$profile['profile_uid'],'dislike')) {
+ $response_verbs[] = 'dislike';
+ }
+
+ $response_verbs[] = 'announce';
+
+ if ($item['obj_type'] === 'Question') {
+ $response_verbs[] = 'answer';
}
- $this->activity($item, $conv_responses);
+ $responses = get_responses($response_verbs, $item);
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
$forged = ((! intval($item['item_verified']) && $item['sig']) ? t('Message signature incorrect') : '');
@@ -110,10 +110,12 @@ class Pinned {
'text' => strip_tags($body['html']),
'id' => $item['id'],
'mids' => json_encode([ $midb64 ]),
+ 'mid' => $item['uuid'],
+ 'rawmid' => $item['mid'],
+ 'parent' => $item['parent'],
'isevent' => $isevent,
'attend' => $attend,
- 'consensus' => $consensus,
- 'conlabels' => ($canvote ? $conlabels : []),
+ 'conlabels' => [],
'canvote' => $canvote,
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, ($author['xchan_addr'] ? $author['xchan_addr'] : $author['xchan_url']) ),
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $owner['xchan_name'], ($owner['xchan_addr'] ? $owner['xchan_addr'] : $owner['xchan_url']) ),
@@ -152,7 +154,7 @@ class Pinned {
'hide' => (! $is_new && isset($observer['xchan_hash']) && $observer['xchan_hash'] != $owner['xchan_hash'] ? t("Don't show") : ''),
// end toolbar buttons
'modal_dismiss' => t('Close'),
- 'responses' => $conv_responses,
+ 'responses' => $responses,
'author_id' => (($author['xchan_addr']) ? $author['xchan_addr'] : $author['xchan_url'])
];
@@ -194,74 +196,14 @@ class Pinned {
if(empty($mids_list))
return [];
- $r = q("SELECT * FROM item WHERE uuid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
+
+ $r = q("SELECT parent AS item_id FROM item WHERE uuid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0",
dbesc(implode(",", $mids_list)),
intval($this->uid)
);
- if($r)
- return $r;
-
- return [];
- }
+ return items_by_parent_ids($r, blog_mode: true);
- /*
- * @brief List activities on item
- *
- * @param array $item
- * @param array $conv_responses
- * @return array
- *
- */
- private function activity($item, &$conv_responses) {
-
- foreach(array_keys($conv_responses) as $verb) {
- $verb_sql = '';
-
- switch($verb) {
- case 'like':
- $verb_sql = " AND verb IN ('Like', '" . ACTIVITY_LIKE . "') ";
- break;
- case 'dislike':
- $verb_sql = " AND verb IN ('Dislike', '" . ACTIVITY_DISLIKE . "') ";
- break;
- case 'attendyes':
- $verb_sql = " AND verb IN ('Accept', '" . ACTIVITY_ATTEND . "') ";
- break;
- case 'attendno':
- $verb_sql = " AND verb IN ('Reject', '" . ACTIVITY_ATTENDNO . "') ";
- break;
- case 'attendmaybe':
- $verb_sql = " AND verb IN ('TentativeAccept', '" . ACTIVITY_ATTENDMAYBE . "') ";
- break;
- default:
- break;
- }
-
- $r = q("SELECT * FROM item WHERE parent = %d AND id <> parent $verb_sql AND item_deleted = 0",
- intval($item['id'])
- );
- if(! $r) {
- unset($conv_responses[$verb]);
- continue;
- }
-
- $conv_responses[$verb]['count'] = count($r);
- $conv_responses[$verb]['button'] = get_response_button_text($verb, $conv_responses[$verb]['count']);
-
- foreach($r as $rr) {
-
- $author = q("SELECT * FROM xchan WHERE xchan_hash = '%s' LIMIT 1",
- dbesc($rr['author_xchan'])
- );
- $name = (($author && $author[0]['xchan_name']) ? $author[0]['xchan_name'] : t('Unknown'));
- $conv_responses[$verb]['list'][] = (($rr['author_xchan'] && $author && $author[0]['xchan_photo_s']) ?
- '<a class="dropdown-item" href="' . chanlink_hash($rr['author_xchan']) . '">' . '<img class="menu-img-1" src="' . zid($author[0]['xchan_photo_s']) . '" alt="' . urlencode($name) . '" /> ' . $name . '</a>' :
- '<a class="dropdown-item" href="#" class="disabled">' . $name . '</a>'
- );
- }
- }
-
- $conv_responses['count'] = count($conv_responses);
}
+
}
diff --git a/Zotlabs/Widget/Portfolio.php b/Zotlabs/Widget/Portfolio.php
index a06f56e30..1c9dc162a 100644
--- a/Zotlabs/Widget/Portfolio.php
+++ b/Zotlabs/Widget/Portfolio.php
@@ -66,6 +66,10 @@ class Portfolio {
//edit album name
$album_edit = null;
+
+ $ph = photo_factory('');
+ $phototypes = $ph->supportedTypes();
+
$photos = array();
if($r) {
$twist = 'rotright';
@@ -103,7 +107,7 @@ class Portfolio {
$tpl = get_markup_template('photo_album_portfolio.tpl');
- $o .= replace_macros($tpl, array(
+ return replace_macros($tpl, array(
'$photos' => $photos,
'$mode' => $mode,
'$count' => $count,
@@ -113,11 +117,7 @@ class Portfolio {
'$can_post' => false,
'$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
'$order' => false,
- '$upload_form' => $upload_form,
- '$usage' => $usage_message
));
-
- return $o;
}
}
diff --git a/Zotlabs/Widget/Tagcloud.php b/Zotlabs/Widget/Tagcloud.php
index 00456f24f..efd571576 100644
--- a/Zotlabs/Widget/Tagcloud.php
+++ b/Zotlabs/Widget/Tagcloud.php
@@ -18,8 +18,7 @@ class Tagcloud {
$flags = 0;
$type = TERM_HASHTAG;
- // @FIXME there exists no $authors variable
- $r = tagadelic($uid, $count, $authors, $owner, $flags, 0, $type);
+ $r = tagadelic($uid, $count, '', '', $flags, 0, $type);
// @FIXME this should use a template
diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php
index 96b70af15..9271269cf 100644
--- a/Zotlabs/Widget/Tasklist.php
+++ b/Zotlabs/Widget/Tasklist.php
@@ -19,7 +19,7 @@ class Tasklist {
if(App::$profile_uid !== local_channel())
return EMPTY_STR;
- $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>';
+ $o = '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>';
$o .= '<script>function taskComplete(id) { $.post("tasks/complete/"+id, function(data) { tasksFetch();}); }
function tasksFetch() {
$.get("tasks/fetch" + ((tasksShowAll) ? "/all" : ""), function(data) {
diff --git a/Zotlabs/Zot6/Zot6Handler.php b/Zotlabs/Zot6/Zot6Handler.php
index 053901205..1716ff84b 100644
--- a/Zotlabs/Zot6/Zot6Handler.php
+++ b/Zotlabs/Zot6/Zot6Handler.php
@@ -12,7 +12,7 @@ class Zot6Handler implements IHandler {
}
function Rekey($sender, $data, $hub) {
- return self::reply_rekey_request($sender, $data, $hub);
+ return self::rekey_request($sender, $data, $hub);
}
function Refresh($sender, $recipients, $hub, $force) {
@@ -34,11 +34,13 @@ class Zot6Handler implements IHandler {
logger('notify received from ' . $hub['hubloc_url']);
- $x = Libzot::fetch($data, $hub);
- $ret['delivery_report'] = $x;
+ $x = Libzot::fetch($data);
+ if ($x) {
+ $ret['delivery_report'] = $x;
+ $ret['success'] = true;
+ }
- $ret['success'] = true;
return $ret;
}