incomplete support for fetching data from user outbox (only article yet)
parent
61203001a3
commit
d208afe899
|
@ -1,2 +0,0 @@
|
||||||
[contentnation]
|
|
||||||
service-uri = http://local.contentnation.net
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
$l = [
|
||||||
|
'image' => 'Artikelbild',
|
||||||
|
'newarticle' => 'Ein neuer Artikel wurde veröffentlicht',
|
||||||
|
];
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
$l = [
|
||||||
|
'image' => 'article image',
|
||||||
|
'newarticle' => 'A new Artikel was published',
|
||||||
|
];
|
|
@ -6,7 +6,7 @@
|
||||||
* @author Sascha Nitsch (grumpydeveloper)
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
**/
|
**/
|
||||||
|
|
||||||
namespace Federator\Api;
|
namespace Federator\Api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /@username or /users/ handlers
|
* /@username or /users/ handlers
|
||||||
|
@ -48,14 +48,50 @@ class FedUsers implements APIInterface
|
||||||
public function exec($paths, $user)
|
public function exec($paths, $user)
|
||||||
{
|
{
|
||||||
$method = $_SERVER["REQUEST_METHOD"];
|
$method = $_SERVER["REQUEST_METHOD"];
|
||||||
switch ($method) {
|
$handler = null;
|
||||||
case 'GET':
|
|
||||||
switch (sizeof($paths)) {
|
switch (sizeof($paths)) {
|
||||||
case 2:
|
case 2:
|
||||||
|
if ($method === 'GET') {
|
||||||
// /users/username or /@username
|
// /users/username or /@username
|
||||||
return $this->returnUserProfile($paths[1]);
|
return $this->returnUserProfile($paths[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
// /users/username/(inbox|outbox|following|followers)
|
||||||
|
switch ($paths[2]) {
|
||||||
|
case 'following':
|
||||||
|
// $handler = new FedUsers\Following();
|
||||||
|
break;
|
||||||
|
case 'followers':
|
||||||
|
// $handler = new FedUsers\Followers();
|
||||||
|
break;
|
||||||
|
case 'inbox':
|
||||||
|
// $handler = new FedUsers\Inbox();
|
||||||
|
break;
|
||||||
|
case 'outbox':
|
||||||
|
$handler = new FedUsers\Outbox($this->main);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// /users/username/collections/(features|tags)
|
||||||
|
// not yet implemented
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($handler !== null) {
|
||||||
|
$ret = false;
|
||||||
|
switch ($method) {
|
||||||
|
case 'GET':
|
||||||
|
$ret = $handler->get($paths[1]);
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
$ret = $handler->post($paths[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($ret !== false) {
|
||||||
|
$this->response = $ret;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->main->setResponseCode(404);
|
$this->main->setResponseCode(404);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Api\FedUsers;
|
||||||
|
|
||||||
|
interface FedUsersInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* get call for user
|
||||||
|
*
|
||||||
|
* @param string $_user user to fetch data for
|
||||||
|
* @return string|false response or false in case of error
|
||||||
|
*/
|
||||||
|
public function get($_user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* post call for user
|
||||||
|
*
|
||||||
|
* @param string $_user user to add data to
|
||||||
|
* @return string|false response or false in case of error
|
||||||
|
*/
|
||||||
|
public function post($_user);
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Api\FedUsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle activitypub outbox requests
|
||||||
|
*/
|
||||||
|
class Outbox implements \Federator\Api\FedUsers\FedUsersInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* main instance
|
||||||
|
*
|
||||||
|
* @var \Federator\Main $main
|
||||||
|
*/
|
||||||
|
private $main;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param \Federator\Main $main main instance
|
||||||
|
*/
|
||||||
|
public function __construct($main)
|
||||||
|
{
|
||||||
|
$this->main = $main;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle get call
|
||||||
|
*
|
||||||
|
* @param string $_user user to fetch outbox for
|
||||||
|
* @return string|false response
|
||||||
|
*/
|
||||||
|
public function get($_user)
|
||||||
|
{
|
||||||
|
$dbh = $this->main->getDatabase();
|
||||||
|
$cache = $this->main->getCache();
|
||||||
|
$connector = $this->main->getConnector();
|
||||||
|
// get user
|
||||||
|
$user = \Federator\DIO\User::getUserByName(
|
||||||
|
$dbh,
|
||||||
|
$_user,
|
||||||
|
$connector,
|
||||||
|
$cache
|
||||||
|
);
|
||||||
|
if ($user->id === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// get posts from user
|
||||||
|
$outbox = new \Federator\Data\ActivityPub\Common\Outbox();
|
||||||
|
$min = $this->main->extractFromURI("min", "");
|
||||||
|
$max = $this->main->extractFromURI("max", "");
|
||||||
|
$page = $this->main->extractFromURI("page", "");
|
||||||
|
if ($page !== "") {
|
||||||
|
$items = \Federator\DIO\Posts::getPostsByUser($dbh, $user->id, $connector, $cache, $min, $max);
|
||||||
|
$outbox->setItems($items);
|
||||||
|
} else {
|
||||||
|
$items = [];
|
||||||
|
}
|
||||||
|
$host = $_SERVER['SERVER_NAME'];
|
||||||
|
$id = 'https://' . $host .'/' . $_user . '/outbox';
|
||||||
|
$outbox->setPartOf($id);
|
||||||
|
$outbox->setID($id);
|
||||||
|
if ($page !== '') {
|
||||||
|
$id .= '?page=' . urlencode($page);
|
||||||
|
}
|
||||||
|
if ($page === '' || $outbox->count() == 0) {
|
||||||
|
$outbox->setFirst($id);
|
||||||
|
$outbox->setLast($id . '&min=0');
|
||||||
|
}
|
||||||
|
if (sizeof($items)>0) {
|
||||||
|
$newestId = $items[0]->getPublished();
|
||||||
|
$oldestId = $items[sizeof($items)-1]->getPublished();
|
||||||
|
$outbox->setNext($id . '&max=' . $newestId);
|
||||||
|
$outbox->setPrev($id . '&min=' . $oldestId);
|
||||||
|
}
|
||||||
|
$obj = $outbox->toObject();
|
||||||
|
return json_encode($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle post call
|
||||||
|
*
|
||||||
|
* @param string $_user user to add data to outbox @unused-param
|
||||||
|
* @return string|false response
|
||||||
|
*/
|
||||||
|
public function post($_user)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,15 @@ namespace Federator\Cache;
|
||||||
*/
|
*/
|
||||||
interface Cache extends \Federator\Connector\Connector
|
interface Cache extends \Federator\Connector\Connector
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* save remote posts by user
|
||||||
|
*
|
||||||
|
* @param string $user user name
|
||||||
|
* @param \Federator\Data\ActivityPub\Common\APObject[]|false $posts user posts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function saveRemotePostsByUser($user, $posts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save remote stats
|
* save remote stats
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,6 +13,17 @@ namespace Federator\Connector;
|
||||||
*/
|
*/
|
||||||
interface Connector
|
interface Connector
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* get posts by given user
|
||||||
|
*
|
||||||
|
* @param string $id user id
|
||||||
|
* @param string $minId min ID
|
||||||
|
* @param string $maxId max ID
|
||||||
|
|
||||||
|
* @return \Federator\Data\ActivityPub\Common\APObject[]|false
|
||||||
|
*/
|
||||||
|
public function getRemotePostsByUser($id, $minId, $maxId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get remote user by given name
|
* get remote user by given name
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Activity extends APObject
|
||||||
|
{
|
||||||
|
// actor | object | target | result | origin | instrument
|
||||||
|
/**
|
||||||
|
* actor
|
||||||
|
*
|
||||||
|
* @var string $actor
|
||||||
|
*/
|
||||||
|
private $actor = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param ?string $type type
|
||||||
|
*/
|
||||||
|
public function __construct($type = null)
|
||||||
|
{
|
||||||
|
parent::__construct($type ?? "Activity");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set actor
|
||||||
|
*
|
||||||
|
* @param string $actor new actor
|
||||||
|
* @return Activity
|
||||||
|
*/
|
||||||
|
public function setAActor(string $actor)
|
||||||
|
{
|
||||||
|
$this->actor = $actor;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAActor() : string
|
||||||
|
{
|
||||||
|
return $this->actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create from json/array
|
||||||
|
*
|
||||||
|
* @param mixed $json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
if (array_key_exists('actor', $json)) {
|
||||||
|
$this->actor = $json['actor'];
|
||||||
|
unset($json['actor']);
|
||||||
|
}
|
||||||
|
if (!parent::fromJson($json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
if ($this->actor !== '') {
|
||||||
|
$return['actor'] = $this->actor;
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get Child Object
|
||||||
|
*
|
||||||
|
* @return APObject|null
|
||||||
|
*/
|
||||||
|
public function getObject()
|
||||||
|
{
|
||||||
|
return parent::getObject();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,951 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class APObject implements \JsonSerializable
|
||||||
|
{
|
||||||
|
// actor | bto | current | first | id | instrument | last | items | oneOf |
|
||||||
|
// anyOf | closed | origin | next | object | prev | result | target |
|
||||||
|
// type | accuracy | altitude | content | duration | height | href | hreflang |
|
||||||
|
// partOf | latitude | longitude | endTime | radius | rel |
|
||||||
|
// startIndex | totalItems | units | width | subject | relationship | describes |
|
||||||
|
// formerType | deleted
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unique id
|
||||||
|
*
|
||||||
|
* @var string $id
|
||||||
|
*/
|
||||||
|
private $id = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* child object
|
||||||
|
*
|
||||||
|
* @var APObject|null $object
|
||||||
|
*/
|
||||||
|
private $object = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* type
|
||||||
|
*
|
||||||
|
* @var string $type
|
||||||
|
*/
|
||||||
|
private $type = 'Object';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* content
|
||||||
|
*
|
||||||
|
* @var string $content
|
||||||
|
*/
|
||||||
|
private $content = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* duration in seconds
|
||||||
|
*
|
||||||
|
* @var \DateInterval|false $duration
|
||||||
|
*/
|
||||||
|
private $duration = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* height
|
||||||
|
*
|
||||||
|
* @var int $height
|
||||||
|
*/
|
||||||
|
private $height = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* href
|
||||||
|
*
|
||||||
|
* @var string $href
|
||||||
|
*/
|
||||||
|
private $href = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* end time
|
||||||
|
*
|
||||||
|
* @var int $endTime
|
||||||
|
*/
|
||||||
|
private $endTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* width
|
||||||
|
*
|
||||||
|
* @var int $width
|
||||||
|
*/
|
||||||
|
private $width = -1;
|
||||||
|
|
||||||
|
|
||||||
|
// fiels are attachment | attributedTo | audience | content | context | name | endTime | generator |
|
||||||
|
// icon | image | inReplyTo | location | preview | published | replies | startTime | summary | tag |
|
||||||
|
// updated | url | to | bto | cc | bcc | mediaType | duration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attachements
|
||||||
|
*
|
||||||
|
* @var APObject[] $attachment
|
||||||
|
*/
|
||||||
|
private $attachment = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attributed to
|
||||||
|
*
|
||||||
|
* @var string $attributedTo
|
||||||
|
*/
|
||||||
|
private $attributedTo = '';
|
||||||
|
|
||||||
|
// audience
|
||||||
|
// content
|
||||||
|
// context
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name
|
||||||
|
*
|
||||||
|
* @var string $name
|
||||||
|
*/
|
||||||
|
private $name = '';
|
||||||
|
|
||||||
|
// endTime
|
||||||
|
// generator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* images
|
||||||
|
* @var Image[] $icon
|
||||||
|
*/
|
||||||
|
private $icon = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* images
|
||||||
|
*
|
||||||
|
* @var Image[] $image
|
||||||
|
*/
|
||||||
|
private $image = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reply id
|
||||||
|
*
|
||||||
|
* @var string $inReplyTo
|
||||||
|
*/
|
||||||
|
private $inReplyTo = "";
|
||||||
|
|
||||||
|
// location
|
||||||
|
// preview
|
||||||
|
|
||||||
|
/**
|
||||||
|
* published timestamp
|
||||||
|
*
|
||||||
|
* @var int $published
|
||||||
|
*/
|
||||||
|
private $published = 0;
|
||||||
|
|
||||||
|
// startTime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* summary
|
||||||
|
*
|
||||||
|
* @var string $summary
|
||||||
|
*/
|
||||||
|
private $summary = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tags
|
||||||
|
*
|
||||||
|
* @var Tag[] $tag
|
||||||
|
*/
|
||||||
|
private $tag = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updated timestamp
|
||||||
|
*
|
||||||
|
* @var int $updated
|
||||||
|
*/
|
||||||
|
private $updated = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*
|
||||||
|
* @var string $url
|
||||||
|
*/
|
||||||
|
private $url = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of to ids
|
||||||
|
*
|
||||||
|
* @var array<string> $to
|
||||||
|
*/
|
||||||
|
private $to = array();
|
||||||
|
|
||||||
|
// bto
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of cc ids
|
||||||
|
*
|
||||||
|
* @var array<string> $cc
|
||||||
|
*/
|
||||||
|
private $cc = array();
|
||||||
|
|
||||||
|
// bcc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* media type
|
||||||
|
*
|
||||||
|
* @var string $mediaType
|
||||||
|
*/
|
||||||
|
private $mediaType = "";
|
||||||
|
|
||||||
|
// duration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of contexts
|
||||||
|
*
|
||||||
|
* @var array<string> $context
|
||||||
|
*/
|
||||||
|
private $context = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key value map of contexts
|
||||||
|
* @var array<string, string> $contexts
|
||||||
|
*/
|
||||||
|
private $contexts = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* atom URI
|
||||||
|
*
|
||||||
|
* @var string $atomURI
|
||||||
|
*/
|
||||||
|
private $atomURI = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reply to atom URI
|
||||||
|
*
|
||||||
|
* @var ?string $replyAtomURI
|
||||||
|
*/
|
||||||
|
private $replyAtomURI = null;
|
||||||
|
|
||||||
|
// found items
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generated unique id
|
||||||
|
*
|
||||||
|
* @var string $uuid
|
||||||
|
*/
|
||||||
|
private $uuid = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sensitive flag
|
||||||
|
*
|
||||||
|
* @var ?bool $sensitive
|
||||||
|
*/
|
||||||
|
private $sensitive = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blur hash
|
||||||
|
* @var string $blurhash
|
||||||
|
*/
|
||||||
|
private $blurhash = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* conversation id
|
||||||
|
* @var string $conversation
|
||||||
|
*/
|
||||||
|
private $conversation = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param string $type type of object
|
||||||
|
*/
|
||||||
|
public function __construct(string $type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set note content
|
||||||
|
*
|
||||||
|
* @param string $content note content
|
||||||
|
* @return APObject current instance
|
||||||
|
*/
|
||||||
|
public function setContent(string $content)
|
||||||
|
{
|
||||||
|
$this->content = $content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get note content
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add context to list
|
||||||
|
*
|
||||||
|
* @param string $context new context
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
final public function addContext($context)
|
||||||
|
{
|
||||||
|
if (!in_array($context, $this->context, false)) {
|
||||||
|
$this->context[] = $context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add multiple contexts to list
|
||||||
|
*
|
||||||
|
* @param array<string,string> $contexts new contexts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
final public function addContexts($contexts)
|
||||||
|
{
|
||||||
|
foreach ($contexts as $key => $value) {
|
||||||
|
if (!in_array($key, $this->contexts, false)) {
|
||||||
|
$this->contexts[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set id
|
||||||
|
*
|
||||||
|
* @param string $id new id
|
||||||
|
* @return APObject current object
|
||||||
|
*/
|
||||||
|
final public function setID($id)
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getID() : string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set href
|
||||||
|
*
|
||||||
|
* @param string $href href
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function setHref(string $href)
|
||||||
|
{
|
||||||
|
$this->href = $href;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set child object
|
||||||
|
*
|
||||||
|
* @param APObject $object
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setObject($object)
|
||||||
|
{
|
||||||
|
$this->object = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get child object
|
||||||
|
*
|
||||||
|
* @return APObject|null child object
|
||||||
|
*/
|
||||||
|
public function getObject()
|
||||||
|
{
|
||||||
|
return $this->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set summary
|
||||||
|
*
|
||||||
|
* @param string $summary summary
|
||||||
|
* @return APObject this
|
||||||
|
*/
|
||||||
|
public function setSummary($summary)
|
||||||
|
{
|
||||||
|
$this->summary = $summary;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set type
|
||||||
|
*
|
||||||
|
* @param string $type type
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setType(string $type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType() : string
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set attachments
|
||||||
|
*
|
||||||
|
* @param APObject[] $attachment
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setAttachment($attachment)
|
||||||
|
{
|
||||||
|
$this->attachment = $attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAttachment(APObject $attachment) : void
|
||||||
|
{
|
||||||
|
$this->attachment[] = $attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get attachments
|
||||||
|
*
|
||||||
|
* @return APObject[] attachments
|
||||||
|
*/
|
||||||
|
public function getAttachment()
|
||||||
|
{
|
||||||
|
return $this->attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAttachmentsAsJson() : string
|
||||||
|
{
|
||||||
|
if ($this->attachment === []) {
|
||||||
|
return "{}";
|
||||||
|
}
|
||||||
|
$obj = [];
|
||||||
|
foreach ($this->attachment as $a) {
|
||||||
|
$obj[] = $a->toObject();
|
||||||
|
}
|
||||||
|
return json_encode($obj) | '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set attributed to
|
||||||
|
*
|
||||||
|
* @param string $to attribute to
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function setAttributedTo(string $to)
|
||||||
|
{
|
||||||
|
$this->attributedTo = $to;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAttributedTo() : string
|
||||||
|
{
|
||||||
|
return $this->attributedTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set name
|
||||||
|
*
|
||||||
|
* @param string $name name
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function setName(string $name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add Image
|
||||||
|
*
|
||||||
|
* @param Image $image image to add
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addImage(Image $image)
|
||||||
|
{
|
||||||
|
$this->image[] = $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInReplyTo(string $reply) : void
|
||||||
|
{
|
||||||
|
$this->inReplyTo = $reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInReplyTo() : string
|
||||||
|
{
|
||||||
|
return $this->inReplyTo ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set published timestamp
|
||||||
|
*
|
||||||
|
* @param int $published published timestamp
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function setPublished(int $published)
|
||||||
|
{
|
||||||
|
$this->published = $published;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPublished() : int
|
||||||
|
{
|
||||||
|
return $this->published;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add Tag
|
||||||
|
*
|
||||||
|
* @param Tag $tag tag to add
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addTag(Tag $tag)
|
||||||
|
{
|
||||||
|
$this->tag[] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set url
|
||||||
|
*
|
||||||
|
* @param string $url URL
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function setURL(string $url)
|
||||||
|
{
|
||||||
|
$this->url = $url;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get URL
|
||||||
|
*
|
||||||
|
* @return string URL
|
||||||
|
*/
|
||||||
|
public function getURL()
|
||||||
|
{
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add to
|
||||||
|
*
|
||||||
|
* @param string $to additional to address
|
||||||
|
* @return APObject
|
||||||
|
*/
|
||||||
|
public function addTo(string $to)
|
||||||
|
{
|
||||||
|
$this->to[] = $to;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get to
|
||||||
|
*
|
||||||
|
* @return array<string>
|
||||||
|
*/
|
||||||
|
public function getTo()
|
||||||
|
{
|
||||||
|
return $this->to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add cc
|
||||||
|
*
|
||||||
|
* @param string $cc additional cc address
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addCC($cc)
|
||||||
|
{
|
||||||
|
$this->cc[] = $cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get cc
|
||||||
|
*
|
||||||
|
* @return array<string>
|
||||||
|
*/
|
||||||
|
public function getCC()
|
||||||
|
{
|
||||||
|
return $this->cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaType() : string
|
||||||
|
{
|
||||||
|
return $this->mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set atom URI
|
||||||
|
*
|
||||||
|
* @param string $uri atom URI
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setAtomURI($uri)
|
||||||
|
{
|
||||||
|
$this->atomURI = $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set reply atom URI
|
||||||
|
* @param string $uri reply atom URI
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setReplyAtomURI($uri)
|
||||||
|
{
|
||||||
|
$this->replyAtomURI = $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set sensitive
|
||||||
|
*
|
||||||
|
* @param bool $sensitive status
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSensitive($sensitive)
|
||||||
|
{
|
||||||
|
$this->sensitive = $sensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set conversation id
|
||||||
|
* @param string $conversation conversation ID
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setConversation(string $conversation)
|
||||||
|
{
|
||||||
|
$this->conversation = $conversation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConversation() : ?string
|
||||||
|
{
|
||||||
|
return $this->conversation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create from json
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $json input
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
if (!is_array($json)) {
|
||||||
|
error_log("fromJson called with ".gettype($json). " => ". debug_backtrace()[1]['function']
|
||||||
|
. " json: " . print_r($json, true));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (array_key_exists('id', $json)) {
|
||||||
|
$this->id = $json['id'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('content', $json)) {
|
||||||
|
$this->content = $json['content'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('duration', $json)) {
|
||||||
|
try {
|
||||||
|
$this->duration = new \DateInterval($json['duration']);
|
||||||
|
} catch (\Exception $unused_e) {
|
||||||
|
error_log("error parsing duration ". $json['duration']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('height', $json)) {
|
||||||
|
$this->height = intval($json['height'], 10);
|
||||||
|
}
|
||||||
|
if (array_key_exists('href', $json)) {
|
||||||
|
$this->href = $json['href'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('endTime', $json) && $json['endTime'] !== null) {
|
||||||
|
$this->endTime = $this->parseDateTime($json['endTime']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('width', $json)) {
|
||||||
|
$this->width = intval($json['width'], 10);
|
||||||
|
}
|
||||||
|
if (array_key_exists('attachment', $json) && $json['attachment'] !== null) {
|
||||||
|
$attachment = [];
|
||||||
|
foreach ($json['attachment'] as $a) {
|
||||||
|
$att = \Federator\Data\ActivityPub\Factory::newFromJson($a, "");
|
||||||
|
if ($att !== null) {
|
||||||
|
$attachment[] = $att;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->attachment = $attachment;
|
||||||
|
}
|
||||||
|
if (array_key_exists('attributedTo', $json)) {
|
||||||
|
if (is_array($json['attributedTo']) && array_key_exists(0, $json['attributedTo'])) {
|
||||||
|
if (is_array($json['attributedTo'][0])) {
|
||||||
|
$this->attributedTo = $json['attributedTo'][0]['id'];
|
||||||
|
} else {
|
||||||
|
$this->attributedTo = $json['attributedTo'][0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->attributedTo = (string)$json['attributedTo'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('name', $json)) {
|
||||||
|
$this->name = $json['name'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('icon', $json)) {
|
||||||
|
if (array_key_exists('type', $json['icon'])) {
|
||||||
|
$image = new Image();
|
||||||
|
$image->fromJson($json['icon']);
|
||||||
|
$this->icon[] = $image;
|
||||||
|
} else {
|
||||||
|
foreach ($json['icon'] as $icon) {
|
||||||
|
$image = new Image();
|
||||||
|
$image->fromJson($icon);
|
||||||
|
$this->icon[] = $image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('image', $json)) {
|
||||||
|
$image = new Image();
|
||||||
|
$image->fromJson($json['image']);
|
||||||
|
$this->image[] = $image;
|
||||||
|
}
|
||||||
|
if (array_key_exists('inReplyTo', $json)) {
|
||||||
|
$this->inReplyTo = $json['inReplyTo'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('published', $json)) {
|
||||||
|
$this->published = $this->parseDateTime($json['published']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('summary', $json)) {
|
||||||
|
$this->summary = $json['summary'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('tag', $json)) {
|
||||||
|
$tags = [];
|
||||||
|
foreach ($json['tag'] as $t) {
|
||||||
|
$tag = new Tag();
|
||||||
|
$tag->fromJson($t);
|
||||||
|
$tags[] = $tag;
|
||||||
|
}
|
||||||
|
$this->tag = $tags;
|
||||||
|
}
|
||||||
|
if (array_key_exists('updated', $json)) {
|
||||||
|
$this->updated = $this->parseDateTime($json['updated']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('url', $json)) {
|
||||||
|
$this->url = $json['url'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('to', $json)) {
|
||||||
|
if (is_array($json['to'])) {
|
||||||
|
foreach ($json['to'] as $to) {
|
||||||
|
$this->to[] = $to;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->to[] = $json['to'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('cc', $json)) {
|
||||||
|
if (is_array($json['cc'])) {
|
||||||
|
foreach ($json['cc'] as $cc) {
|
||||||
|
$this->cc[] = $cc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->cc[] = $json['cc'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('mediaType', $json)) {
|
||||||
|
$this->mediaType = $json['mediaType'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('object', $json)) {
|
||||||
|
$this->object = \Federator\Data\ActivityPub\Factory::newFromJson($json['object'], "");
|
||||||
|
}
|
||||||
|
if (array_key_exists('sensitive', $json)) {
|
||||||
|
$this->sensitive = $json['sensitive'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('blurhash', $json)) {
|
||||||
|
$this->blurhash = $json['blurhash'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('uuid', $json)) {
|
||||||
|
$this->uuid = $json['uuid'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('conversation', $json)) {
|
||||||
|
$this->conversation = $json['conversation'];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see JsonSerializable::jsonSerialize()
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = [];
|
||||||
|
if (sizeof($this->context) == 1) {
|
||||||
|
$return['@context'] = array_values($this->context)[0];
|
||||||
|
} elseif (sizeof($this->context) > 1) {
|
||||||
|
$c = [];
|
||||||
|
foreach (array_values($this->context) as $context) {
|
||||||
|
$c[] = $context;
|
||||||
|
}
|
||||||
|
$return['@context'] = $c;
|
||||||
|
}
|
||||||
|
if (sizeof($this->contexts) > 0) {
|
||||||
|
if (array_key_exists('@context', $return)) {
|
||||||
|
$return['@context'] = [$return['@context']];
|
||||||
|
} else {
|
||||||
|
$return['@context'] = [];
|
||||||
|
}
|
||||||
|
$return['@context'][] = $this->contexts;
|
||||||
|
}
|
||||||
|
if ($this->id !== "") {
|
||||||
|
$return['id'] = $this->id;
|
||||||
|
}
|
||||||
|
$return['type'] = $this->type;
|
||||||
|
|
||||||
|
if ($this->content !== "") {
|
||||||
|
$return['content'] = $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->duration !== false) {
|
||||||
|
$return['duration'] = $this->duration->format("P%yY%mM%dDT%hH%iM%sS");
|
||||||
|
}
|
||||||
|
if ($this->height != -1) {
|
||||||
|
$return['height'] = $this->height;
|
||||||
|
}
|
||||||
|
if ($this->href !== "") {
|
||||||
|
$return['href'] = $this->href;
|
||||||
|
}
|
||||||
|
if ($this->endTime > 0) {
|
||||||
|
$return['endTime'] = gmdate("Y-m-d\TH:i:s\Z", $this->endTime);
|
||||||
|
}
|
||||||
|
if ($this->width != -1) {
|
||||||
|
$return['width'] = $this->width;
|
||||||
|
}
|
||||||
|
if (sizeof($this->attachment) > 0) {
|
||||||
|
$attachment = [];
|
||||||
|
foreach ($this->attachment as $a) {
|
||||||
|
$attachment[] = $a->toObject();
|
||||||
|
}
|
||||||
|
$return['attachment'] = $attachment;
|
||||||
|
}
|
||||||
|
if ($this->attributedTo !== "") {
|
||||||
|
$return['attributedTo'] = $this->attributedTo;
|
||||||
|
}
|
||||||
|
if ($this->name !== "") {
|
||||||
|
$return['name'] = $this->name;
|
||||||
|
}
|
||||||
|
if (sizeof($this->icon) > 0) {
|
||||||
|
if (sizeof($this->icon) > 1) {
|
||||||
|
$icons = [];
|
||||||
|
foreach ($this->icon as $icon) {
|
||||||
|
$icons[] = $icon->toObject();
|
||||||
|
}
|
||||||
|
$return['icon'] = $icons;
|
||||||
|
} else {
|
||||||
|
$return['icon'] = $this->icon[0]->toObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeof($this->image) > 0) {
|
||||||
|
$images = [];
|
||||||
|
foreach ($this->image as $image) {
|
||||||
|
$images[] = $image->toObject();
|
||||||
|
}
|
||||||
|
$return['image'] = $images;
|
||||||
|
}
|
||||||
|
if ($this->inReplyTo !== "") {
|
||||||
|
$return['inReplyTo'] = $this->inReplyTo;
|
||||||
|
}
|
||||||
|
if ($this->published > 0) {
|
||||||
|
$return['published'] = gmdate("Y-m-d\TH:i:s\Z", $this->published);
|
||||||
|
}
|
||||||
|
if ($this->summary !== "") {
|
||||||
|
$return['summary'] = $this->summary;
|
||||||
|
}
|
||||||
|
if (sizeof($this->tag) > 0) {
|
||||||
|
$tags = [];
|
||||||
|
foreach ($this->tag as $tag) {
|
||||||
|
$tags[] = $tag->toObject();
|
||||||
|
}
|
||||||
|
$return['tag'] = $tags;
|
||||||
|
}
|
||||||
|
if ($this->updated > 0) {
|
||||||
|
$return['updated'] = gmdate("Y-m-d\TH:i:S\Z", $this->updated);
|
||||||
|
}
|
||||||
|
if ($this->url !== '') {
|
||||||
|
$return['url'] = $this->url;
|
||||||
|
}
|
||||||
|
if (sizeof($this->to) > 0) {
|
||||||
|
$return['to'] = $this->to;
|
||||||
|
}
|
||||||
|
if (sizeof($this->cc) > 0) {
|
||||||
|
$return['cc'] = $this->cc;
|
||||||
|
}
|
||||||
|
if ($this->mediaType !== '') {
|
||||||
|
$return['mediaType'] = $this->mediaType;
|
||||||
|
}
|
||||||
|
if ($this->object !== null) {
|
||||||
|
$return['object'] = $this->object->toObject();
|
||||||
|
}
|
||||||
|
if ($this->atomURI !== '') {
|
||||||
|
$return['atomUri'] = $this->atomURI;
|
||||||
|
}
|
||||||
|
if ($this->replyAtomURI !== null) {
|
||||||
|
$return['inReplyTo'] = $this->replyAtomURI;
|
||||||
|
$return['inReplyToAtomUri'] = $this->replyAtomURI;
|
||||||
|
}
|
||||||
|
if ($this->sensitive !== null) {
|
||||||
|
$return['sensitive'] = $this->sensitive;
|
||||||
|
}
|
||||||
|
if ($this->blurhash !== '') {
|
||||||
|
$return['blurhash'] = $this->blurhash;
|
||||||
|
}
|
||||||
|
if ($this->conversation !== '') {
|
||||||
|
$return['conversation'] = $this->conversation;
|
||||||
|
}
|
||||||
|
if ($this->uuid !== '') {
|
||||||
|
$return['uuid'] = $this->uuid;
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set uuid
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUUID($id)
|
||||||
|
{
|
||||||
|
$this->uuid = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUUID() : string
|
||||||
|
{
|
||||||
|
return $this->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseDateTime(string $input) : int
|
||||||
|
{
|
||||||
|
$timestamp = 0;
|
||||||
|
if (strpos($input, "T")!== false) {
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d\TH:i:sT', $input);
|
||||||
|
if ($date === false) {
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d\TH:i:s+', $input);
|
||||||
|
}
|
||||||
|
if ($date !== false) {
|
||||||
|
$timestamp = $date->getTimestamp();
|
||||||
|
} else {
|
||||||
|
error_log("date parsing error ". $input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$timestamp = intval($input, 10);
|
||||||
|
}
|
||||||
|
return $timestamp;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Article extends APObject
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct("Article");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
* @param mixed $json input
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Collection extends APObject
|
||||||
|
{
|
||||||
|
protected int $totalItems = 0;
|
||||||
|
private string $first = '';
|
||||||
|
private string $last = '';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('Collection');
|
||||||
|
parent::addContext('https://www.w3.org/ns/activitystreams');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
$return['type'] = 'Collection';
|
||||||
|
if ($this->totalItems > 0) {
|
||||||
|
$return['totalItems'] = $this->totalItems;
|
||||||
|
}
|
||||||
|
if ($this->first !== '') {
|
||||||
|
$return['first'] = $this->first;
|
||||||
|
}
|
||||||
|
if ($this->last !== '') {
|
||||||
|
$return['last'] = $this->last;
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count() : int
|
||||||
|
{
|
||||||
|
return $this->totalItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFirst(string $url) : void
|
||||||
|
{
|
||||||
|
$this->first = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLast(string $url) : void
|
||||||
|
{
|
||||||
|
$this->last = $url;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Create extends Activity
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('Create');
|
||||||
|
parent::addContext('https://www.w3.org/ns/activitystreams');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
$return['type'] = 'Create';
|
||||||
|
// overwrite id from url
|
||||||
|
$return['id'] = $this->getURL();
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Image extends APObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*
|
||||||
|
* @var string $url
|
||||||
|
*/
|
||||||
|
private $url = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* media type
|
||||||
|
*
|
||||||
|
* @var string $mediaType
|
||||||
|
*/
|
||||||
|
private $mediaType = '';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct("Image");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set media type
|
||||||
|
* @param string $mediaType media type
|
||||||
|
* @return Image current instance
|
||||||
|
*/
|
||||||
|
public function setMediaType(string $mediaType)
|
||||||
|
{
|
||||||
|
$this->mediaType = $mediaType;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
* @param mixed $json input
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
if (!parent::fromJson($json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (array_key_exists('url', $json)) {
|
||||||
|
$this->url = $json['url'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('mediaType', $json)) {
|
||||||
|
$this->mediaType = $json['mediaType'];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Note extends APObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* sender
|
||||||
|
*
|
||||||
|
* @var string $sender
|
||||||
|
*/
|
||||||
|
private $sender = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* receiver
|
||||||
|
*
|
||||||
|
* @var string $receiver
|
||||||
|
*/
|
||||||
|
private $receiver = "";
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct("Note");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set sender
|
||||||
|
*
|
||||||
|
* @param string $sender note sender
|
||||||
|
* @return Note current instance
|
||||||
|
*/
|
||||||
|
public function setSender(string $sender)
|
||||||
|
{
|
||||||
|
$this->sender = $sender;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sender
|
||||||
|
*
|
||||||
|
* @return string sender
|
||||||
|
*/
|
||||||
|
public function getSender()
|
||||||
|
{
|
||||||
|
return $this->sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set receiver
|
||||||
|
*
|
||||||
|
* @param string $receiver note receiver
|
||||||
|
* @return Note current instance
|
||||||
|
*/
|
||||||
|
public function setReceiver(string $receiver)
|
||||||
|
{
|
||||||
|
$this->receiver = $receiver;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
if ($this->sender !== "") {
|
||||||
|
$return['sender'] = $this->sender;
|
||||||
|
}
|
||||||
|
if ($this->receiver !== "") {
|
||||||
|
$return['receiver'] = $this->receiver;
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
* @param mixed $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
if (!parent::fromJson($json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->receiver = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class OrderedCollection extends Collection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* nested items
|
||||||
|
*
|
||||||
|
* @var APObject[]
|
||||||
|
*/
|
||||||
|
protected $items = [];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
parent::addContext('https://www.w3.org/ns/activitystreams');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
$return['type'] = 'OrderedCollection';
|
||||||
|
if ($this->totalItems > 0) {
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
$return['OrderedItems'][] = $item->toObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function append(APObject &$item) : void
|
||||||
|
{
|
||||||
|
$this->items[] = $item;
|
||||||
|
$this->totalItems = sizeof($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get item with given index
|
||||||
|
*
|
||||||
|
* @return APObject|false
|
||||||
|
*/
|
||||||
|
public function get(int $index)
|
||||||
|
{
|
||||||
|
if ($index >= 0) {
|
||||||
|
if ($index >= $this->totalItems) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->items[$index];
|
||||||
|
} else {
|
||||||
|
if ($this->totalItems+ $index < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->items[$this->totalItems + $index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set items
|
||||||
|
*
|
||||||
|
* @param APObject[] $items
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setItems(&$items)
|
||||||
|
{
|
||||||
|
$this->items = $items;
|
||||||
|
$this->totalItems = sizeof($items);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class OrderedCollectionPage extends OrderedCollection
|
||||||
|
{
|
||||||
|
private string $next = '';
|
||||||
|
private string $prev = '';
|
||||||
|
private string $partOf = '';
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
parent::addContext('https://www.w3.org/ns/activitystreams');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
if ($this->next !== '') {
|
||||||
|
$return['next'] = $this->next;
|
||||||
|
}
|
||||||
|
if ($this->prev !== '') {
|
||||||
|
$return['prev'] = $this->prev;
|
||||||
|
}
|
||||||
|
if ($this->partOf !== '') {
|
||||||
|
$return['partOf'] = $this->partOf;
|
||||||
|
}
|
||||||
|
$return['type'] = 'OrderedCollectionPage';
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set next url
|
||||||
|
*
|
||||||
|
* @param string $url new next URL
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setNext($url)
|
||||||
|
{
|
||||||
|
$this->next = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set prev url
|
||||||
|
*
|
||||||
|
* @param string $url new prev URL
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPrev($url)
|
||||||
|
{
|
||||||
|
$this->prev = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPartOf(string $url) : void
|
||||||
|
{
|
||||||
|
$this->partOf = $url;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Outbox extends OrderedCollectionPage
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
parent::addContext('https://www.w3.org/ns/activitystreams');
|
||||||
|
parent::addContexts([
|
||||||
|
"ostatus" => "http://ostatus.org#",
|
||||||
|
"atomUri" => "ostatus:atomUri",
|
||||||
|
"inReplyToAtomUri" => "ostatus:inReplyToAtomUri",
|
||||||
|
"conversation" => "ostatus:conversation",
|
||||||
|
"sensitive" => "as:sensitive",
|
||||||
|
"toot" => "http://joinmastodon.org/ns#",
|
||||||
|
"votersCount" => "toot:votersCount",
|
||||||
|
"Hashtag" => "as:Hashtag"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert internal state to php array
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public function toObject()
|
||||||
|
{
|
||||||
|
$return = parent::toObject();
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object from json
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $json input json
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
return parent::fromJson($json);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub\Common;
|
||||||
|
|
||||||
|
class Tag extends APObject
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct("Tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill object from json
|
||||||
|
*
|
||||||
|
* @param mixed $json input
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function fromJson($json)
|
||||||
|
{
|
||||||
|
if (!parent::fromJson($json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (array_key_exists('type', $json)) {
|
||||||
|
$this->setType($json['type']);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data\ActivityPub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class for creating various ActivityPub classes
|
||||||
|
*/
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object tree from json
|
||||||
|
* @param array<string, mixed> $json input json
|
||||||
|
* @return Common\APObject|null object or false on error
|
||||||
|
*/
|
||||||
|
public static function newFromJson($json, string $jsonstring)
|
||||||
|
{
|
||||||
|
if (gettype($json) !== "array") {
|
||||||
|
error_log("newFromJson called with ".gettype($json). " => ". debug_backtrace()[1]['function']
|
||||||
|
. " json: " . print_r($json, true));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!array_key_exists('type', $json)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$return = null;
|
||||||
|
switch ($json['type']) {
|
||||||
|
case 'Article':
|
||||||
|
$return = new Common\Article();
|
||||||
|
break;
|
||||||
|
/*case 'Document':
|
||||||
|
$return = new Common\Document();
|
||||||
|
break;
|
||||||
|
case 'Event':
|
||||||
|
$return = new Common\Event();
|
||||||
|
break;
|
||||||
|
case 'Follow':
|
||||||
|
$return = new Common\Follow();
|
||||||
|
break;*/
|
||||||
|
case 'Image':
|
||||||
|
$return = new Common\Image();
|
||||||
|
break;
|
||||||
|
/*case 'Note':
|
||||||
|
$return = new Common\Note();
|
||||||
|
break;
|
||||||
|
case 'Question':
|
||||||
|
$return = new \Common\Question();
|
||||||
|
break;
|
||||||
|
case 'Video':
|
||||||
|
$return = new \Common\Video();
|
||||||
|
break;*/
|
||||||
|
default:
|
||||||
|
error_log("newFromJson: unknown type: '" . $json['type'] . "' " . $jsonstring);
|
||||||
|
error_log(print_r($json, true));
|
||||||
|
}
|
||||||
|
if ($return !== null && $return->fromJson($json)) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create object tree from json
|
||||||
|
* @param array<string, mixed> $json input json
|
||||||
|
* @return Common\Activity|false object or false on error
|
||||||
|
*/
|
||||||
|
public static function newActivityFromJson($json)
|
||||||
|
{
|
||||||
|
if (!array_key_exists('type', $json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//$return = false;
|
||||||
|
switch ($json['type']) {
|
||||||
|
case 'MakePhanHappy':
|
||||||
|
break;
|
||||||
|
/* case 'Accept':
|
||||||
|
$return = new Common\Accept();
|
||||||
|
break;
|
||||||
|
case 'Announce':
|
||||||
|
$return = new Common\Announce();
|
||||||
|
break;
|
||||||
|
case 'Create':
|
||||||
|
$return = new Common\Create();
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
$return = new Common\Delete();
|
||||||
|
break;
|
||||||
|
case 'Follow':
|
||||||
|
$return = new Common\Follow();
|
||||||
|
break;
|
||||||
|
case 'Undo':
|
||||||
|
$return = new \Common\Undo();
|
||||||
|
break;*/
|
||||||
|
default:
|
||||||
|
error_log("newActivityFromJson " . print_r($json, true));
|
||||||
|
}
|
||||||
|
/*if ($return !== false && $return->fromJson($json) !== null) {
|
||||||
|
return $return;
|
||||||
|
}*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\DIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IO functions related to users
|
||||||
|
*/
|
||||||
|
class Posts
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get posts by user
|
||||||
|
*
|
||||||
|
* @param \mysqli $dbh @unused-param
|
||||||
|
* database handle
|
||||||
|
* @param string $id
|
||||||
|
* user id
|
||||||
|
* @param \Federator\Connector\Connector $connector
|
||||||
|
* connector to fetch use with
|
||||||
|
* @param \Federator\Cache\Cache|null $cache
|
||||||
|
* optional caching service
|
||||||
|
* @param string $minId
|
||||||
|
* minimum ID
|
||||||
|
* @param string $maxId
|
||||||
|
* maximum ID
|
||||||
|
* @return \Federator\Data\ActivityPub\Common\APObject[]
|
||||||
|
*/
|
||||||
|
public static function getPostsByUser($dbh, $id, $connector, $cache, $minId, $maxId)
|
||||||
|
{
|
||||||
|
// ask cache
|
||||||
|
if ($cache !== null) {
|
||||||
|
$posts = $cache->getRemotePostsByUser($id, $minId, $maxId);
|
||||||
|
if ($posts !== false) {
|
||||||
|
return $posts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$posts = [];
|
||||||
|
// TODO: check our db
|
||||||
|
|
||||||
|
if ($posts === []) {
|
||||||
|
// ask connector for user-id
|
||||||
|
$posts = $connector->getRemotePostsByUser($id, $minId, $maxId);
|
||||||
|
if ($posts === false) {
|
||||||
|
$posts = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// save posts to DB
|
||||||
|
if ($cache !== null) {
|
||||||
|
$cache->saveRemotePostsByUser($id, $posts);
|
||||||
|
}
|
||||||
|
return $posts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,7 +44,8 @@ class User
|
||||||
$public = openssl_pkey_get_details($private_key)['key'];
|
$public = openssl_pkey_get_details($private_key)['key'];
|
||||||
$private = '';
|
$private = '';
|
||||||
openssl_pkey_export($private_key, $private);
|
openssl_pkey_export($private_key, $private);
|
||||||
$sql = 'insert into users (id, externalid, rsapublic, rsaprivate, validuntil, type, name, summary, registered, iconmediatype, iconurl, imagemediatype, imageurl)';
|
$sql = 'insert into users (id, externalid, rsapublic, rsaprivate, validuntil,';
|
||||||
|
$sql .= ' type, name, summary, registered, iconmediatype, iconurl, imagemediatype, imageurl)';
|
||||||
$sql .= ' values (?, ?, ?, ?, now() + interval 1 day, ?, ?, ?, ?, ?, ?, ?, ?)';
|
$sql .= ' values (?, ?, ?, ?, now() + interval 1 day, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||||
$stmt = $dbh->prepare($sql);
|
$stmt = $dbh->prepare($sql);
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
|
@ -68,7 +69,8 @@ class User
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// update to existing user
|
// update to existing user
|
||||||
$sql = 'update users set validuntil=now() + interval 1 day, type=?, name=?, summary=?, registered=?, iconmediatype=?, iconurl=?, imagemediatype=?, imageurl=? where id=?';
|
$sql = 'update users set validuntil=now() + interval 1 day, type=?, name=?, summary=?, registered=?,';
|
||||||
|
$sql .= ' iconmediatype=?, iconurl=?, imagemediatype=?, imageurl=? where id=?';
|
||||||
$stmt = $dbh->prepare($sql);
|
$stmt = $dbh->prepare($sql);
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
throw new \Federator\Exceptions\ServerError();
|
throw new \Federator\Exceptions\ServerError();
|
||||||
|
@ -151,7 +153,8 @@ class User
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
// check our db
|
// check our db
|
||||||
$sql = 'select id,externalid,type,name,summary,unix_timestamp(registered),rsapublic,iconmediatype,iconurl,imagemediatype,imageurl from users where id=? and validuntil>=now()';
|
$sql = 'select id,externalid,type,name,summary,unix_timestamp(registered),rsapublic,';
|
||||||
|
$sql .= 'iconmediatype,iconurl,imagemediatype,imageurl from users where id=? and validuntil>=now()';
|
||||||
$stmt = $dbh->prepare($sql);
|
$stmt = $dbh->prepare($sql);
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
throw new \Federator\Exceptions\ServerError();
|
throw new \Federator\Exceptions\ServerError();
|
||||||
|
|
|
@ -96,8 +96,8 @@ class Language
|
||||||
if ($root === '') {
|
if ($root === '') {
|
||||||
$root = '.';
|
$root = '.';
|
||||||
}
|
}
|
||||||
if (@file_exists($root . '/../lang/' . $this->uselang . "/$group.inc")) {
|
if (@file_exists($root . '../lang/federator/' . $this->uselang . "/$group.inc")) {
|
||||||
require($root . '/../lang/' . $this->uselang . "/$group.inc");
|
require($root . '../lang/federator/' . $this->uselang . "/$group.inc");
|
||||||
$this->lang[$group] = $l;
|
$this->lang[$group] = $l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,12 @@
|
||||||
*
|
*
|
||||||
* @author Sascha Nitsch (grumpydeveloper)
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
**/
|
**/
|
||||||
|
|
||||||
namespace Federator;
|
namespace Federator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* maintenance functions
|
||||||
|
*/
|
||||||
class Maintenance
|
class Maintenance
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,13 @@ class ContentNation implements Connector
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main instance
|
||||||
|
*
|
||||||
|
* @var \Federator\Main $main
|
||||||
|
*/
|
||||||
|
private $main;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service-URL
|
* service-URL
|
||||||
*
|
*
|
||||||
|
@ -30,11 +37,102 @@ class ContentNation implements Connector
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
*
|
*
|
||||||
|
* @param \Federator\Main $main
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct($main)
|
||||||
{
|
{
|
||||||
$config = parse_ini_file($_SERVER['DOCUMENT_ROOT'] . '../contentnation.ini');
|
$config = parse_ini_file($_SERVER['DOCUMENT_ROOT'] . '../contentnation.ini', true);
|
||||||
$this->service = $config['service-uri'];
|
if ($config !== false) {
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
$this->service = $config['contentnation']['service-uri'];
|
||||||
|
$this->main = $main;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get posts by given user
|
||||||
|
*
|
||||||
|
* @param string $userId user id
|
||||||
|
* @param string $min min date
|
||||||
|
* @param string $max max date
|
||||||
|
* @return \Federator\Data\ActivityPub\Common\APObject[]|false
|
||||||
|
*/
|
||||||
|
public function getRemotePostsByUser($userId, $min, $max)
|
||||||
|
{
|
||||||
|
$remoteURL = $this->service . '/api/profile/' . $userId . '/activities';
|
||||||
|
if ($min !== '') {
|
||||||
|
$remoteURL .= '&minTS=' . urlencode($min);
|
||||||
|
}
|
||||||
|
if ($max !== '') {
|
||||||
|
$remoteURL .= '&maxTS=' . urlencode($max);
|
||||||
|
}
|
||||||
|
[$response, $info] = \Federator\Main::getFromRemote($remoteURL, []);
|
||||||
|
if ($info['http_code'] != 200) {
|
||||||
|
print_r($info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$r = json_decode($response, true);
|
||||||
|
if ($r === false || $r === null || !is_array($r)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$posts = [];
|
||||||
|
if (array_key_exists('articles', $r)) {
|
||||||
|
$articles = $r['articles'];
|
||||||
|
$host = $_SERVER['SERVER_NAME'];
|
||||||
|
$imgpath = $this->config['userdata']['path'];
|
||||||
|
$userdata = $this->config['userdata']['url'];
|
||||||
|
foreach ($articles as $article) {
|
||||||
|
$create = new \Federator\Data\ActivityPub\Common\Create();
|
||||||
|
$create->setAActor('https://' . $host .'/' . $article['profilename']);
|
||||||
|
$create->setID($article['id'])
|
||||||
|
->setURL('https://'.$host.'/' . $article['profilename']
|
||||||
|
. '/statuses/' . $article['id'] . '/activity')
|
||||||
|
->setPublished(max($article['published'], $article['modified']))
|
||||||
|
->addTo("https://www.w3.org/ns/activitystreams#Public")
|
||||||
|
->addCC('https://' . $host . '/' . $article['profilename'] . '/followers.json');
|
||||||
|
$apArticle = new \Federator\Data\ActivityPub\Common\Article();
|
||||||
|
if (array_key_exists('tags', $article)) {
|
||||||
|
foreach ($article['tags'] as $tag) {
|
||||||
|
$href = 'https://' . $host . '/' . $article['language']
|
||||||
|
. '/search.htm?tagsearch=' . urlencode($tag);
|
||||||
|
$tagObj = new \Federator\Data\ActivityPub\Common\Tag();
|
||||||
|
$tagObj->setHref($href)
|
||||||
|
->setName('#' . urlencode(str_replace(' ', '', $tag)))
|
||||||
|
->setType('Hashtag');
|
||||||
|
$article->addTag($tagObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$apArticle->setPublished($article['published'])
|
||||||
|
->setName($article['title'])
|
||||||
|
->setAttributedTo('https://' . $host .'/' . $article['profilename'])
|
||||||
|
->setContent(
|
||||||
|
$article['teaser'] ??
|
||||||
|
$this->main->translate(
|
||||||
|
$article['language'],
|
||||||
|
'article',
|
||||||
|
'newarticle'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->addTo("https://www.w3.org/ns/activitystreams#Public")
|
||||||
|
->addCC('https://' . $host . '/' . $article['profilename'] . '/followers.json');
|
||||||
|
$articleimage = $article['imagealt'] ??
|
||||||
|
$this->main->translate($article['language'], 'article', 'image');
|
||||||
|
$idurl = 'https://' . $host . '/' . $article['language']
|
||||||
|
. '/' . $article['profilename'] . '/'. $article['name'];
|
||||||
|
$apArticle->setID($idurl)
|
||||||
|
->setURL($idurl);
|
||||||
|
$image = $article['image'] !== "" ? $article['image'] : $article['profileimg'];
|
||||||
|
$mediaType = @mime_content_type($imgpath . $article['profile'] . '/' . $image) | 'text/plain';
|
||||||
|
$img = new \Federator\Data\ActivityPub\Common\Image();
|
||||||
|
$img->setMediaType($mediaType)
|
||||||
|
->setName($articleimage)
|
||||||
|
->setURL($userdata . $article['profile'] . '/' . $image);
|
||||||
|
$apArticle->addImage($img);
|
||||||
|
$create->setObject($apArticle);
|
||||||
|
$posts[] = $create;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $posts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +145,6 @@ class ContentNation implements Connector
|
||||||
$remoteURL = $this->service . '/api/stats';
|
$remoteURL = $this->service . '/api/stats';
|
||||||
[$response, $info] = \Federator\Main::getFromRemote($remoteURL, []);
|
[$response, $info] = \Federator\Main::getFromRemote($remoteURL, []);
|
||||||
if ($info['http_code'] != 200) {
|
if ($info['http_code'] != 200) {
|
||||||
print_r($info);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$r = json_decode($response, true);
|
$r = json_decode($response, true);
|
||||||
|
@ -147,6 +244,6 @@ namespace Federator;
|
||||||
*/
|
*/
|
||||||
function contentnation_load($main)
|
function contentnation_load($main)
|
||||||
{
|
{
|
||||||
$cn = new Connector\ContentNation();
|
$cn = new Connector\ContentNation($main);
|
||||||
$main->setConnector($cn);
|
$main->setConnector($cn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,19 @@ class DummyConnector implements Connector
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get posts by given user
|
||||||
|
*
|
||||||
|
* @param string $id user id @unused-param
|
||||||
|
* @param string $minId min ID @unused-param
|
||||||
|
* @param string $maxId max ID @unused-param
|
||||||
|
* @return \Federator\Data\ActivityPub\Common\APObject[]|false
|
||||||
|
*/
|
||||||
|
public function getRemotePostsByUser($id, $minId, $maxId)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get statistics from remote system
|
* get statistics from remote system
|
||||||
*
|
*
|
||||||
|
|
|
@ -77,6 +77,21 @@ class RedisCache implements Cache
|
||||||
return $prefix . '_' . md5($input);
|
return $prefix . '_' . md5($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get posts by given user
|
||||||
|
*
|
||||||
|
* @param string $id user id @unused-param
|
||||||
|
* @param string $minId min ID @unused-param
|
||||||
|
* @param string $maxId max ID @unused-param
|
||||||
|
|
||||||
|
* @return \Federator\Data\ActivityPub\Common\APObject[]|false
|
||||||
|
*/
|
||||||
|
public function getRemotePostsByUser($id, $minId, $maxId)
|
||||||
|
{
|
||||||
|
error_log("rediscache::getRemotePostsByUser not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get statistics from remote system
|
* get statistics from remote system
|
||||||
*
|
*
|
||||||
|
@ -137,6 +152,18 @@ class RedisCache implements Cache
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* save remote posts by user
|
||||||
|
*
|
||||||
|
* @param string $user user name @unused-param
|
||||||
|
* @param \Federator\Data\ActivityPub\Common\APObject[]|false $posts user posts @unused-param
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function saveRemotePostsByUser($user, $posts)
|
||||||
|
{
|
||||||
|
error_log("rediscache::saveRemotePostsByUser not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save remote stats
|
* save remote stats
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ldelim}
|
{ldelim}
|
||||||
"subject": "acct:{$username}@{$domain}",
|
"subject": "acct:{$username}@{$domain}",
|
||||||
"aliases": [
|
"aliases": [
|
||||||
"https://{$domain}/@{$username}"
|
"https://{$domain}/@{$username}",
|
||||||
"https://{$domain}/users/{$username}"
|
"https://{$domain}/users/{$username}"
|
||||||
],
|
],
|
||||||
"links": [
|
"links": [
|
||||||
|
|
Loading…
Reference in New Issue