[TESTS] Added unit tests

This commit is contained in:
Daniel 2020-10-16 01:07:01 +01:00 committed by Hugo Sales
parent d53fef09a8
commit 95f95d2dd8
No known key found for this signature in database
GPG Key ID: 7D0C7EAFC9D835A0
29 changed files with 716 additions and 477 deletions

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -42,8 +44,10 @@ class apActorFollowersAction extends ManagedAction
/**
* Handle the Followers Collection request
*
* @return void
* @throws Exception
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle()
@ -56,13 +60,13 @@ class apActorFollowersAction extends ManagedAction
}
if (!$profile->isLocal()) {
ActivityPubReturn::error("This is not a local user.", 403);
ActivityPubReturn::error('This is not a local user.', 403);
}
if (!isset($_GET["page"])) {
if (!isset($_GET['page'])) {
$page = 0;
} else {
$page = intval($this->trimmed('page'));
$page = (int) ($this->trimmed('page'));
}
if ($page < 0) {
@ -72,18 +76,18 @@ class apActorFollowersAction extends ManagedAction
$since = ($page - 1) * PROFILES_PER_MINILIST;
$limit = PROFILES_PER_MINILIST;
/* Calculate total items */
// Calculate total items
$total_subs = Activitypub_profile::subscriberCount($profile);
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
$res = [
'@context' => [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
'id' => common_local_url('apActorFollowers', ['id' => $profile_id]) . (($page != 0) ? '?page=' . $page : ''),
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
'totalItems' => $total_subs
'totalItems' => $total_subs,
];
if ($page == 0) {
@ -110,8 +114,11 @@ class apActorFollowersAction extends ManagedAction
* @param Profile $profile
* @param int $since
* @param int $limit
* @return array of URIs
*
* @throws Exception
*
* @return array of URIs
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function generate_followers($profile, $since, $limit)
@ -120,7 +127,7 @@ class apActorFollowersAction extends ManagedAction
try {
$sub = Activitypub_profile::getSubscribers($profile, $since, $limit);
/* Get followers' URLs */
// Get followers' URLs
foreach ($sub as $s) {
$subs[] = $s->getUri();
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -42,8 +44,10 @@ class apActorFollowingAction extends ManagedAction
/**
* Handle the Following Collection request
*
* @return void
* @throws Exception
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle()
@ -56,13 +60,13 @@ class apActorFollowingAction extends ManagedAction
}
if (!$profile->isLocal()) {
ActivityPubReturn::error("This is not a local user.", 403);
ActivityPubReturn::error('This is not a local user.', 403);
}
if (!isset($_GET["page"])) {
if (!isset($_GET['page'])) {
$page = 0;
} else {
$page = intval($this->trimmed('page'));
$page = (int) ($this->trimmed('page'));
}
if ($page < 0) {
@ -72,18 +76,18 @@ class apActorFollowingAction extends ManagedAction
$since = ($page - 1) * PROFILES_PER_MINILIST;
$limit = PROFILES_PER_MINILIST;
/* Calculate total items */
// Calculate total items
$total_subs = Activitypub_profile::subscriptionCount($profile);
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
$res = [
'@context' => [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
'id' => common_local_url('apActorFollowing', ['id' => $profile_id]) . (($page != 0) ? '?page=' . $page : ''),
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
'totalItems' => $total_subs
'totalItems' => $total_subs,
];
if ($page == 0) {
@ -110,8 +114,11 @@ class apActorFollowingAction extends ManagedAction
* @param Profile $profile
* @param int $since
* @param int $limit
* @return array of URIs
*
* @throws Exception
*
* @return array of URIs
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function generate_following($profile, $since, $limit)
@ -120,7 +127,7 @@ class apActorFollowingAction extends ManagedAction
try {
$sub = Activitypub_profile::getSubscribed($profile, $since, $limit);
/* Get followed' URLs */
// Get followed' URLs
foreach ($sub as $s) {
$subs[] = $s->getUri();
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -42,9 +44,11 @@ class apActorLikedAction extends ManagedAction
/**
* Handle the Liked Collection request
*
* @return void
* @throws EmptyPkeyValueException
* @throws ServerException
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle()
@ -57,12 +61,12 @@ class apActorLikedAction extends ManagedAction
}
if (!$profile->isLocal()) {
ActivityPubReturn::error("This is not a local user.", 403);
ActivityPubReturn::error('This is not a local user.', 403);
}
$limit = intval($this->trimmed('limit'));
$since_id = intval($this->trimmed('since_id'));
$max_id = intval($this->trimmed('max_id'));
$limit = (int) ($this->trimmed('limit'));
$since_id = (int) ($this->trimmed('since_id'));
$max_id = (int) ($this->trimmed('max_id'));
$limit = empty($limit) ? 40 : $limit; // Default is 40
$since_id = empty($since_id) ? null : $since_id;
@ -75,20 +79,20 @@ class apActorLikedAction extends ManagedAction
$fave = $this->fetch_faves($profile_id, $limit, $since_id, $max_id);
$faves = array();
$faves = [];
while ($fave->fetch()) {
$faves[] = $this->pretty_fave(clone ($fave));
$faves[] = $this->pretty_fave(clone $fave);
}
$res = [
'@context' => [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
'id' => common_local_url('apActorLiked', ['id' => $profile_id]),
'type' => 'OrderedCollection',
'totalItems' => Fave::countByProfile($profile),
'orderedItems' => $faves
'orderedItems' => $faves,
];
ActivityPubReturn::answer($res);
@ -99,16 +103,19 @@ class apActorLikedAction extends ManagedAction
* as a plugin answer
*
* @param Fave $fave_object
* @return array pretty array representating a Fave
*
* @throws EmptyPkeyValueException
* @throws ServerException
*
* @return array pretty array representating a Fave
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function pretty_fave($fave_object)
{
$res = [
'created' => $fave_object->created,
'object' => Activitypub_notice::notice_to_array(Notice::getByID($fave_object->notice_id))
'object' => Activitypub_notice::notice_to_array(Notice::getByID($fave_object->notice_id)),
];
return $res;
@ -118,10 +125,12 @@ class apActorLikedAction extends ManagedAction
* Fetch faves
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param int $user_id
* @param int $limit
* @param int $since_id
* @param int $max_id
*
* @return Fave fetchable fave collection
*/
private static function fetch_faves(

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -54,13 +56,13 @@ class apActorOutboxAction extends ManagedAction
}
if (!$profile->isLocal()) {
ActivityPubReturn::error("This is not a local user.", 403);
ActivityPubReturn::error('This is not a local user.', 403);
}
if (!isset($_GET["page"])) {
if (!isset($_GET['page'])) {
$page = 0;
} else {
$page = intval($this->trimmed('page'));
$page = (int) ($this->trimmed('page'));
}
if ($page < 0) {
@ -70,18 +72,18 @@ class apActorOutboxAction extends ManagedAction
$since = ($page - 1) * PROFILES_PER_MINILIST;
$limit = (($page - 1) == 0 ? 1 : $page) * PROFILES_PER_MINILIST;
/* Calculate total items */
// Calculate total items
$total_notes = $profile->noticeCount();
$total_pages = ceil($total_notes / PROFILES_PER_MINILIST);
$res = [
'@context' => [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
'id' => common_local_url('apActorOutbox', ['id' => $profile_id]) . (($page != 0) ? '?page=' . $page : ''),
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
'totalItems' => $total_notes
'totalItems' => $total_notes,
];
if ($page == 0) {
@ -106,15 +108,18 @@ class apActorOutboxAction extends ManagedAction
* Generates a list of people following given profile.
*
* @param Profile $profile
* @return array of Notices
*
* @throws EmptyPkeyValueException
* @throws InvalidUrlException
* @throws ServerException
*
* @return array of Notices
*
* @author Daniel Supernault <danielsupernault@gmail.com>
*/
public function generate_outbox($profile)
{
/* Fetch Notices */
// Fetch Notices
$notices = [];
$notice = $profile->getNotices();
while ($notice->fetch()) {

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -42,9 +44,11 @@ class apActorProfileAction extends ManagedAction
/**
* Handle the Actor Profile request
*
* @return void
* @throws InvalidUrlException
* @throws ServerException
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle()
@ -65,7 +69,7 @@ class apActorProfileAction extends ManagedAction
}
if (!$profile->isLocal()) {
ActivityPubReturn::error("This is not a local user.", 403);
ActivityPubReturn::error('This is not a local user.', 403);
}
$res = Activitypub_profile::profile_to_array($profile);

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -42,8 +44,10 @@ class apInboxAction extends ManagedAction
/**
* Handle the Inbox request
*
* @return void
* @throws ServerException
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle()

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -132,10 +134,12 @@ class apNoticeAction extends ManagedAction
/**
* Handle the Notice request
*
* @return void
* @throws EmptyPkeyValueException
* @throws InvalidUrlException
* @throws ServerException
*
* @return void
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
protected function handle(): void
@ -143,9 +147,9 @@ class apNoticeAction extends ManagedAction
if (is_null($this->notice)) {
ActivityPubReturn::error('Invalid Activity URI.', 404);
}
if (!$this->notice->isLocal()) {
// We have no authority on the requested activity.
ActivityPubReturn::error("This is not a local activity.", 403);
if (!$notice->isLocal()) {
ActivityPubReturn::error('This is not a local notice.', 403);
}
$res = Activitypub_notice::notice_to_array($this->notice);

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,13 +32,13 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
class Activitypub_activityverb2 extends Managed_DataObject
{
const FULL_LIST =
[
const FULL_LIST = [
'Accept' => 'https://www.w3.org/ns/activitystreams#Accept',
'TentativeAccept' => 'https://www.w3.org/ns/activitystreams#TentativeAccept',
'Add' => 'https://www.w3.org/ns/activitystreams#Add',
@ -65,25 +66,26 @@ class Activitypub_activityverb2 extends Managed_DataObject
'Block' => 'https://www.w3.org/ns/activitystreams#Block',
'Flag' => 'https://www.w3.org/ns/activitystreams#Flag',
'Dislike' => 'https://www.w3.org/ns/activitystreams#Dislike',
'Question' => 'https://www.w3.org/ns/activitystreams#Question'
'Question' => 'https://www.w3.org/ns/activitystreams#Question',
];
const KNOWN =
[
const KNOWN = [
'Accept',
'Create',
'Delete',
'Follow',
'Like',
'Undo',
'Announce'
'Announce',
];
/**
* Converts canonical into verb.
*
* @author GNU social
*
* @param string $verb
*
* @return string
*/
public static function canonical($verb)

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -33,6 +34,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -45,16 +47,19 @@ class Activitypub_explorer
*
* @param string $url
* @param bool $grab_online whether to try online grabbing, defaults to true
* @return Profile
*
* @throws HTTP_Request2_Exception Network issues
* @throws NoProfileException This won't happen
* @throws Exception Invalid request
* @throws ServerException Error storing remote actor
*
* @return Profile
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function get_profile_from_url(string $url, bool $grab_online = true): Profile
{
$discovery = new Activitypub_explorer();
$discovery = new self();
// Get valid Actor object
$actor_profile = $discovery->lookup($url, $grab_online);
if (!empty($actor_profile)) {
@ -70,11 +75,14 @@ class Activitypub_explorer
*
* @param string $url User's url
* @param bool $grab_online whether to try online grabbing, defaults to true
* @return array of Profile objects
*
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws Exception
* @throws ServerException
*
* @return array of Profile objects
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function lookup(string $url, bool $grab_online = true)
@ -96,11 +104,14 @@ class Activitypub_explorer
*
* @param string $url User's url
* @param bool $grab_online whether to try online grabbing, defaults to true
* @return array of Profile objects
*
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @return array of Profile objects
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function _lookup(string $url, bool $grab_online = true): array
@ -122,9 +133,12 @@ class Activitypub_explorer
*
* @param string $uri Actor's uri
* @param bool $online
* @return bool success state
*
* @throws NoProfileException
* @throws Exception
*
* @return bool success state
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function grab_local_user(string $uri, bool $online = false): bool
@ -155,7 +169,7 @@ class Activitypub_explorer
$disco = new Discovery();
$xrd = $disco->lookup($aprofile->getUri());
$doublecheck_aliases = array_merge(array($xrd->subject), $xrd->aliases);
$doublecheck_aliases = array_merge([$xrd->subject], $xrd->aliases);
if (in_array($uri, $doublecheck_aliases)) {
// the original URI is present, we're sure now!
@ -208,11 +222,14 @@ class Activitypub_explorer
* $this->discovered_actor_profiles
*
* @param string $url User's url
* @return bool success state
*
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @return bool success state
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function grab_remote_user(string $url): bool
@ -251,10 +268,13 @@ class Activitypub_explorer
* Save remote user profile in local instance
*
* @param array $res remote response
* @return Profile remote Profile object
*
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @return Profile remote Profile object
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function store_profile(array $res): Profile
@ -296,7 +316,9 @@ class Activitypub_explorer
* response is a valid profile or not
*
* @param array $res remote response
*
* @return bool success state
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function validate_remote_response(array $res): bool
@ -315,15 +337,17 @@ class Activitypub_explorer
* this hacky workaround (at least for now)
*
* @param string $v URL
* @return bool|Activitypub_profile false if fails | Aprofile object if successful
*
* @return Activitypub_profile|bool false if fails | Aprofile object if successful
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function get_aprofile_by_url(string $v)
{
$i = Managed_DataObject::getcached("Activitypub_profile", "uri", $v);
$i = Managed_DataObject::getcached('Activitypub_profile', 'uri', $v);
if (empty($i)) { // false = cache miss
$i = new Activitypub_profile;
$result = $i->get("uri", $v);
$result = $i->get('uri', $v);
if ($result) {
// Hit!
$i->encache();
@ -338,9 +362,12 @@ class Activitypub_explorer
* Given a valid actor profile url returns its inboxes
*
* @param string $url of Actor profile
* @return bool|array false if fails to validate the answer | array with inbox and shared inbox if successful
*
* @throws HTTP_Request2_Exception
* @throws Exception If an irregular error happens (status code, body format or GONE)
*
* @return array|bool false if fails to validate the answer | array with inbox and shared inbox if successful
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function get_actor_inboxes_uri(string $url)
@ -360,7 +387,7 @@ class Activitypub_explorer
if (self::validate_remote_response($res)) {
return [
'inbox' => $res['inbox'],
'sharedInbox' => isset($res['endpoints']['sharedInbox']) ? $res['endpoints']['sharedInbox'] : $res['inbox']
'sharedInbox' => isset($res['endpoints']['sharedInbox']) ? $res['endpoints']['sharedInbox'] : $res['inbox'],
];
}
@ -374,8 +401,11 @@ class Activitypub_explorer
*
* @param Profile $profile
* @param string $url
* @return Avatar The Avatar we have on disk. (seldom used)
*
* @throws Exception in various failure cases
*
* @return Avatar The Avatar we have on disk. (seldom used)
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function update_avatar(Profile $profile, string $url): Avatar
@ -412,10 +442,13 @@ class Activitypub_explorer
* Allows the Explorer to transverse a collection of persons.
*
* @param string $url
* @return bool
*
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function travel_collection(string $url): bool
@ -428,15 +461,15 @@ class Activitypub_explorer
return false;
}
foreach ($res["orderedItems"] as $profile) {
foreach ($res['orderedItems'] as $profile) {
if ($this->_lookup($profile) == false) {
common_debug('ActivityPub Explorer: Found an invalid actor for ' . $profile);
// TODO: Invalid actor found, fallback to OStatus
}
}
// Go through entire collection
if (!is_null($res["next"])) {
$this->travel_collection($res["next"]);
if (!is_null($res['next'])) {
$this->travel_collection($res['next']);
}
return true;
@ -447,8 +480,11 @@ class Activitypub_explorer
* profile updating and shall not be used for anything else)
*
* @param string $url User's url
* @return array|false If it is able to fetch, false if it's gone
*
* @throws Exception Either network issues or unsupported Activity format
*
* @return array|false If it is able to fetch, false if it's gone
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function get_remote_user_activity(string $url)
@ -466,7 +502,7 @@ class Activitypub_explorer
common_debug('ActivityPub Explorer: Invalid JSON returned from given Actor URL: ' . $response->getBody());
throw new Exception('Given Actor URL didn\'t return a valid JSON.');
}
if (Activitypub_explorer::validate_remote_response($res)) {
if (self::validate_remote_response($res)) {
common_debug('ActivityPub Explorer: Found a valid remote actor for ' . $url);
return $res;
}

View File

@ -14,22 +14,25 @@
*
* @category Network
* @package Nautilus
*
* @author Aaron Parecki <aaron@parecki.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://github.com/aaronpk/Nautilus/blob/master/app/ActivityPub/HTTPSignature.php
*
* @see https://github.com/aaronpk/Nautilus/blob/master/app/ActivityPub/HTTPSignature.php
*/
class HttpSignature
class httpsignature
{
/**
* Sign a message with an Actor
*
* @param Profile $user Actor signing
* @param string $url Inbox url
* @param string|bool $body Data to sign (optional)
* @param bool|string $body Data to sign (optional)
* @param array $addlHeaders Additional headers (optional)
* @return array Headers to be used in curl
*
* @throws Exception Attempted to sign something that belongs to an Actor we don't own
*
* @return array Headers to be used in curl
*/
public static function sign(Profile $user, string $url, $body = false, array $addlHeaders = []): array
{
@ -56,6 +59,7 @@ class HttpSignature
/**
* @param mixed $body
*
* @return string
*/
private static function _digest($body): string
@ -69,8 +73,10 @@ class HttpSignature
/**
* @param string $url
* @param mixed $digest
* @return array
*
* @throws Exception
*
* @return array
*/
protected static function _headersToSign(string $url, $digest = false): array
{
@ -82,7 +88,7 @@ class HttpSignature
'Host' => parse_url($url, PHP_URL_HOST),
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json, application/json',
'User-Agent' => 'GNU social ActivityPub Plugin - ' . GNUSOCIAL_ENGINE_URL,
'Content-Type' => 'application/activity+json'
'Content-Type' => 'application/activity+json',
];
if ($digest) {
@ -94,6 +100,7 @@ class HttpSignature
/**
* @param array $headers
*
* @return string
*/
private static function _headersToSigningString(array $headers): string
@ -105,17 +112,19 @@ class HttpSignature
/**
* @param array $headers
*
* @return array
*/
private static function _headersToCurlArray(array $headers): array
{
return array_map(function ($k, $v) {
return "$k: $v";
return "{$k}: {$v}";
}, array_keys($headers), $headers);
}
/**
* @param string $signature
*
* @return array
*/
public static function parseSignatureHeader(string $signature): array
@ -131,19 +140,19 @@ class HttpSignature
if (!isset($signatureData['keyId'])) {
return [
'error' => 'No keyId was found in the signature header. Found: ' . implode(', ', array_keys($signatureData))
'error' => 'No keyId was found in the signature header. Found: ' . implode(', ', array_keys($signatureData)),
];
}
if (!filter_var($signatureData['keyId'], FILTER_VALIDATE_URL)) {
return [
'error' => 'keyId is not a URL: ' . $signatureData['keyId']
'error' => 'keyId is not a URL: ' . $signatureData['keyId'],
];
}
if (!isset($signatureData['headers']) || !isset($signatureData['signature'])) {
return [
'error' => 'Signature is missing headers or signature parts'
'error' => 'Signature is missing headers or signature parts',
];
}
@ -156,6 +165,7 @@ class HttpSignature
* @param $inputHeaders
* @param $path
* @param $body
*
* @return array
*/
public static function verify($publicKey, $signatureData, $inputHeaders, $path, $body): array

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -45,7 +47,9 @@ class Activitypub_inbox_handler
*
* @param array $activity Activity we are receiving
* @param Profile $actor_profile Actor originating the activity
*
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function __construct($activity, $actor_profile = null)
@ -73,7 +77,9 @@ class Activitypub_inbox_handler
* Validates if a given Activity is valid. Throws exception if not.
*
* @throws Exception if invalid
*
* @return bool true if valid and acceptable, false if unsupported
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function validate_activity(): bool
@ -127,6 +133,7 @@ class Activitypub_inbox_handler
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function process()
@ -162,6 +169,7 @@ class Activitypub_inbox_handler
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_accept()
@ -180,6 +188,7 @@ class Activitypub_inbox_handler
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_accept_follow()
@ -200,6 +209,7 @@ class Activitypub_inbox_handler
* Handles a Create Activity received by our inbox.
*
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_create()
@ -215,6 +225,7 @@ class Activitypub_inbox_handler
* Handle a Create Note Activity received by our inbox.
*
* @throws Exception
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
private function handle_create_note()
@ -229,6 +240,9 @@ class Activitypub_inbox_handler
/**
* Handles a Delete Activity received by our inbox.
*
* @throws NoProfileException
* @throws Exception
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
@ -238,8 +252,8 @@ class Activitypub_inbox_handler
if (is_string($object)) {
$client = new HTTPClient();
$response = $client->get($object, ACTIVITYPUB_HTTP_CLIENT_HEADERS);
$not_gone = $response->isOk();
if ($not_gone) { // It's not gone, we're updating it.
$gone = !$response->isOk();
if (!$gone) { // It's not gone, we're updating it.
$object = json_decode($response->getBody(), true);
switch ($object['type']) {
case 'Person':
@ -269,15 +283,36 @@ class Activitypub_inbox_handler
common_log(LOG_INFO, "Ignoring Delete activity, we do not understand for {$object['type']}.");
}
}
} else {
// We don't know the type of the deleted object :(
// Nor if it's gone or not.
try {
if (is_array($object)) {
$object = $object['id'];
}
$aprofile = Activitypub_profile::fromUri($object, false);
$res = Activitypub_explorer::get_remote_user_activity($object);
Activitypub_profile::update_profile($aprofile, $res);
return;
} catch (Exception $e) {
// Means this wasn't a profile
}
// IFF we reached this point, it either is gone or it's an array
// If it's gone, we don't know the type of the deleted object, we only have a Tombstone
// If we were given an array, we don't know if it's Gone or not via status code...
// In both cases, we will want to fetch the ID and act on that as it is easier than updating the fields
$object = $object['id'] ?? null;
if (is_null($object)) {
try {
$client = new HTTPClient();
$response = $client->get($object, ACTIVITYPUB_HTTP_CLIENT_HEADERS);
// If it was deleted
if ($response->getStatus() == 410) {
$notice = ActivityPubPlugin::grab_notice_from_url($object, false);
if ($notice instanceof Notice) {
$notice->delete();
}
} else {
// We can't update a note's contents so, we'll ignore it for now...
}
return;
} catch (Exception $e) {
// Means we didn't have this note already
}
// Was it a profile?
@ -316,6 +351,7 @@ class Activitypub_inbox_handler
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_follow()
@ -327,6 +363,7 @@ class Activitypub_inbox_handler
* Handles a Like Activity received by our inbox.
*
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_like()
@ -342,6 +379,7 @@ class Activitypub_inbox_handler
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_undo()
@ -364,6 +402,7 @@ class Activitypub_inbox_handler
* @throws NoProfileException
* @throws ServerException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_undo_follow()
@ -387,6 +426,7 @@ class Activitypub_inbox_handler
* @throws AlreadyFulfilledException
* @throws ServerException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_undo_like()
@ -399,6 +439,7 @@ class Activitypub_inbox_handler
* Handles a Announce Activity received by our inbox.
*
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function handle_announce()

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,7 +42,9 @@ class Activitypub_accept
* Generates an ActivityPub representation of a Accept
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param array $object
*
* @return array pretty array to be used in a response
*/
public static function accept_to_array($object)
@ -50,7 +54,7 @@ class Activitypub_accept
'id' => common_root_url() . 'accept_follow_from_' . urlencode($object['actor']) . '_to_' . urlencode($object['object']),
'type' => 'Accept',
'actor' => $object['object'],
'object' => $object
'object' => $object,
];
return $res;
}
@ -59,8 +63,11 @@ class Activitypub_accept
* Verifies if a given object is acceptable for an Accept Activity.
*
* @param array $object
* @return bool
*
* @throws Exception
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function validate_object($object)
@ -75,7 +82,7 @@ class Activitypub_accept
case 'Follow':
// Validate data
if (!filter_var($object['object'], FILTER_VALIDATE_URL)) {
throw new Exception("Object is not a valid Object URI for Activity.");
throw new Exception('Object is not a valid Object URI for Activity.');
}
break;
default:

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -41,16 +43,15 @@ class Activitypub_announce
*
* @param Profile $actor
* @param Notice $notice
* @param Notice $repeat_of
*
* @return array pretty array to be used in a response
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function announce_to_array(
Profile $actor,
Notice $notice,
Notice $repeat_of
): array {
public static function announce_to_array(Profile $actor, Notice $notice): array
{
$actor_uri = $actor->getUri();
$notice_url = Activitypub_notice::getUrl($notice);
$to = [common_local_url('apActorFollowers', ['id' => $actor->getID()])];
foreach ($notice->getAttentionProfiles() as $to_profile) {
@ -61,10 +62,10 @@ class Activitypub_announce
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => Activitypub_notice::getUri($notice),
'id' => common_root_url() . 'share_from_' . urlencode($actor_uri) . '_to_' . urlencode($notice_url),
'type' => 'Announce',
'actor' => $actor_uri,
'object' => Activitypub_notice::getUri($repeat_of),
'object' => $notice_url,
'to' => $to,
'cc' => $cc,
];

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,7 +42,9 @@ class Activitypub_attachment
* Generates a pretty array from an Attachment object
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param Attachment $attachment
*
* @return array pretty array to be used in a response
*/
public static function attachment_to_array($attachment)
@ -55,10 +59,10 @@ class Activitypub_attachment
];
// Image
if (substr($res["mediaType"], 0, 5) == "image") {
$res["meta"]= [
if (substr($res['mediaType'], 0, 5) == 'image') {
$res['meta'] = [
'width' => $attachment->width,
'height' => $attachment->height
'height' => $attachment->height,
];
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,23 +42,24 @@ class Activitypub_create
* Generates an ActivityPub representation of a Create
*
* @param string $actor
* @param string $uri
* @param mixed $object
* @param array $object
* @param bool $directMessage whether it is a private Create activity or not
*
* @return array pretty array to be used in a response
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function create_to_array(string $actor, string $uri, $object, bool $directMessage = false): array
{
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => $uri,
'id' => $object['id'] . '/create',
'type' => 'Create',
'directMessage' => $directMessage,
'to' => $object['to'],
'cc' => $object['cc'],
'actor' => $actor,
'object' => $object
'object' => $object,
];
return $res;
}
@ -65,8 +68,11 @@ class Activitypub_create
* Verifies if a given object is acceptable for a Create Activity.
*
* @param array $object
* @return bool True if acceptable, false if valid but unsupported
*
* @throws Exception if invalid
*
* @return bool True if acceptable, false if valid but unsupported
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function validate_object($object): bool
@ -100,7 +106,9 @@ class Activitypub_create
* https://github.com/w3c/activitypub/issues/196#issuecomment-304958984
*
* @param array $activity received Create-Note activity
*
* @return bool true if note is private, false otherwise
*
* @author Bruno casteleiro <brunoccast@fc.up.pt>
*/
public static function isPrivateNote(array $activity): bool

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -39,35 +41,35 @@ class Activitypub_delete
/**
* Generates an ActivityStreams 2.0 representation of a Delete
*
* @param Notice $object
* @param string $actor actor URI
* @param string $object object URI
*
* @return array pretty array to be used in a response
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function delete_to_array($object): array
{
if ($object instanceof Notice) {
return Activitypub_notice::notice_to_array($object);
} else if ($object instanceof Profile) {
$actor_uri = $object->getUri();
return [
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => $actor_uri . '#delete',
'id' => $object . '/delete',
'type' => 'Delete',
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
'actor' => $actor_uri,
'object' => $object
'actor' => $actor,
'object' => $object,
];
} else {
throw new InvalidArgumentException();
}
return $res;
}
/**
* Verifies if a given object is acceptable for a Delete Activity.
*
* @param array|string $object
* @return bool
*
* @throws Exception
*
* @return bool
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
public static function validate_object($object): bool
@ -80,7 +82,7 @@ class Activitypub_delete
if (!isset($object['type'])) {
throw new Exception('Object type was not specified for Delete Activity.');
}
if ($object['type'] !== "Tombstone" && $object['type'] !== "Person") {
if ($object['type'] !== 'Tombstone' && $object['type'] !== 'Person') {
throw new Exception('Invalid Object type for Delete Activity.');
}
if (!isset($object['id'])) {

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,13 +42,15 @@ class Activitypub_error
* Generates a pretty error from a string
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param string $m
*
* @return array pretty array to be used in a response
*/
public static function error_message_to_array(string $m): array
{
return [
'error'=> $m
$res = [
'error' => $m,
];
}
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,9 +42,11 @@ class Activitypub_follow
* Generates an ActivityPub representation of a subscription
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param string $actor
* @param string $object
* @param string|null $id Activity id, to be used when generating for an Accept Activity
* @param null|string $id Activity id, to be used when generating for an Accept Activity
*
* @return array pretty array to be used in a response
*/
public static function follow_to_array(string $actor, string $object, ?string $id = null): array
@ -56,7 +60,7 @@ class Activitypub_follow
'id' => $id,
'type' => 'Follow',
'actor' => $actor,
'object' => $object
'object' => $object,
];
return $res;
}
@ -67,10 +71,12 @@ class Activitypub_follow
* @param Profile $actor_profile Remote Actor
* @param string $object Local Actor
* @param string $id Activity id
*
* @throws AlreadyFulfilledException
* @throws HTTP_Request2_Exception
* @throws NoProfileException
* @throws ServerException
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function follow(Profile $actor_profile, string $object, string $id)

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -39,8 +41,11 @@ class Activitypub_like
/**
* Generates an ActivityPub representation of a Like
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param string $actor Actor URI
* @param Notice $notice Notice URI
* @param string $object Notice URI
*
* @return array pretty array to be used in a response
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
@ -48,10 +53,10 @@ class Activitypub_like
{
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => Activitypub_notice::getUri($notice),
'id' => common_root_url() . 'like_from_' . urlencode($actor) . '_to_' . urlencode($object),
'type' => 'Like',
'actor' => $actor,
'object' => Activitypub_notice::getUri($notice->getParent()),
'object' => $object,
];
return $res;
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,17 +42,19 @@ class Activitypub_mention_tag
* Generates an ActivityPub representation of a Mention Tag
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param string $href Actor Uri
* @param string $name Mention name
*
* @return array pretty array to be used in a response
*/
public static function mention_tag_to_array_from_values(string $href, string $name): array
{
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
"type" => "Mention",
"href" => $href,
"name" => $name
'type' => 'Mention',
'href' => $href,
'name' => $name,
];
return $res;
}

View File

@ -18,11 +18,11 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
defined('GNUSOCIAL') || die();
/**
@ -38,7 +38,9 @@ class Activitypub_message
* Generates a pretty message from a Notice object
*
* @param Notice $message
*
* @return array array to be used in a response
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
public static function message_to_array(Notice $message): array
@ -68,7 +70,7 @@ class Activitypub_message
'cc' => [],
'content' => $message->getRendered(),
'attachment' => [],
'tag' => $tags
'tag' => $tags,
];
return $item;
@ -79,10 +81,13 @@ class Activitypub_message
* Returns created Notice.
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*
* @param array $object
* @param Profile $actor_profile
* @return Notice
*
* @throws Exception
*
* @return Notice
*/
public static function create_message(array $object, Profile $actor_profile = null): Notice
{

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,11 +42,14 @@ class Activitypub_notice
* Generates a pretty notice from a Notice object
*
* @param Notice $notice
* @return array array to be used in a response
*
* @throws EmptyPkeyValueException
* @throws InvalidUrlException
* @throws ServerException
* @throws Exception
*
* @return array array to be used in a response
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function notice_to_array(Notice $notice): array
@ -57,7 +62,7 @@ class Activitypub_notice
$tags = [];
foreach ($notice->getTags() as $tag) {
if ($tag != "") { // Hacky workaround to avoid stupid outputs
if ($tag != '') { // Hacky workaround to avoid stupid outputs
$tags[] = Activitypub_tag::tag_to_array($tag);
}
}
@ -79,42 +84,21 @@ class Activitypub_notice
$tags[] = Activitypub_mention_tag::mention_tag_to_array_from_values($href, $to_profile->getNickname() . '@' . parse_url($href, PHP_URL_HOST));
}
if (ActivityUtils::compareVerbs($notice->getVerb(), ActivityVerb::DELETE)) {
$item = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => self::getUri($notice),
'type' => 'Delete',
// XXX: A bit of ugly code here
'object' => array_merge(Activitypub_tombstone::tombstone_to_array((int)substr(explode(':', $notice->getUri())[2], 9)), ['deleted' => str_replace(' ', 'T', $notice->getCreated()) . 'Z']),
'url' => $notice->getUrl(),
'actor' => $profile->getUri(),
'to' => $to,
'cc' => $cc,
'conversationId' => $notice->getConversationUrl(false),
'conversationUrl' => $notice->getConversationUrl(),
'content' => $notice->getRendered(),
'isLocal' => $notice->isLocal(),
'attachment' => $attachments,
'tag' => $tags
];
} else { // Note
$item = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => self::note_uri($notice->getID()),
'id' => self::getUrl($notice),
'type' => 'Note',
'published' => str_replace(' ', 'T', $notice->getCreated()) . 'Z',
'url' => $notice->getUrl(),
'url' => self::getUrl($notice),
'attributedTo' => $profile->getUri(),
'to' => $to,
'cc' => $cc,
'conversationId' => $notice->getConversationUrl(false),
'conversationUrl' => $notice->getConversationUrl(),
'conversation' => $notice->getConversationUrl(),
'content' => $notice->getRendered(),
'isLocal' => $notice->isLocal(),
'attachment' => $attachments,
'tag' => $tags
'tag' => $tags,
];
}
// Is this a reply?
if (!empty($notice->reply_to)) {
@ -140,8 +124,11 @@ class Activitypub_notice
* @param array $object
* @param Profile $actor_profile
* @param bool $directMessage
* @return Notice
*
* @throws Exception
*
* @return Notice
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function create_notice(array $object, Profile $actor_profile, bool $directMessage = false): Notice
@ -170,7 +157,7 @@ class Activitypub_notice
$options = ['source' => 'ActivityPub',
'uri' => $id,
'url' => $url,
'is_local' => self::getNotePolicyType($object, $actor_profile)];
'is_local' => self::getNotePolicyType($object, $actor_profile), ];
if ($directMessage) {
$options['scope'] = Notice::MESSAGE_SCOPE;
@ -240,32 +227,10 @@ class Activitypub_notice
&& $attachment['type'] === 'Document'
&& array_key_exists('url', $attachment)) {
try {
$file = new File();
$file->url = $attachment['url'];
$file->title = array_key_exists('type', $attachment) ? $attachment['name'] : null;
if (array_key_exists('type', $attachment)) {
$file->mimetype = $attachment['mediaType'];
} else {
$http = new HTTPClient();
common_debug(
'Performing HEAD request for incoming activity '
. 'to avoid unnecessarily downloading too '
. 'large files. URL: ' . $file->url
);
$head = $http->head($file->url);
$headers = $head->getHeader();
$headers = array_change_key_case($headers, CASE_LOWER);
if (array_key_exists('content-type', $headers)) {
$file->mimetype = $headers['content-type'];
} else {
continue;
}
if (array_key_exists('content-length', $headers)) {
$file->size = $headers['content-length'];
}
}
$file->saveFile();
$attachments[] = $file;
// throws exception on failure
$attachment = MediaFile::fromUrl($attachment['url'], $actor_profile, $attachment['name']);
$act->enclosures[] = $attachment->getEnclosure();
$attachments[] = $attachment;
} catch (Exception $e) {
// Whatever.
continue;
@ -276,7 +241,7 @@ class Activitypub_notice
$actobj = new ActivityObject();
$actobj->type = ActivityObject::NOTE;
$actobj->content = strip_tags($content, '<p><b><i><u><a><ul><ol><li><br>');
$actobj->content = strip_tags($content, '<p><b><i><u><a><ul><ol><li>');
// Finally add the activity object to our activity
$act->objects[] = $actobj;
@ -284,8 +249,8 @@ class Activitypub_notice
$note = Notice::saveActivity($act, $actor_profile, $options);
// Attachments (last part)
foreach ($attachments as $file) {
File_to_post::processNew($file, $note);
foreach ($attachments as $attachment) {
$attachment->attachToNotice($note);
}
return $note;
@ -295,8 +260,11 @@ class Activitypub_notice
* Validates a note.
*
* @param array $object
* @return bool false if unacceptable for GS but valid ActivityPub object
*
* @throws Exception if invalid ActivityPub object
*
* @return bool false if unacceptable for GS but valid ActivityPub object
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function validate_note(array $object): bool
@ -316,7 +284,7 @@ class Activitypub_notice
common_debug('ActivityPub Notice Validator: Rejected because Object URL is invalid.');
throw new Exception('Invalid Object URL.');
}
if (!(isset($object['to']) && isset($object['cc']))) {
if (!(isset($object['to'], $object['cc']))) {
common_debug('ActivityPub Notice Validator: Rejected because either Object CC or TO wasn\'t specified.');
throw new Exception('Either Object CC or TO wasn\'t specified.');
}
@ -331,9 +299,12 @@ class Activitypub_notice
* Get the original representation URL of a given notice.
*
* @param Notice $notice notice from which to retrieve the URL
* @return string URL
*
* @throws InvalidUrlException
* @throws Exception
*
* @return string URL
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
* @see note_uri when it's not a generic activity but a object type note
*/
@ -364,7 +335,9 @@ class Activitypub_notice
*
* @param array $note received Note
* @param Profile $actor_profile Note author
*
* @return int Notice policy type
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
public static function getNotePolicyType(array $note, Profile $actor_profile): int

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,7 +42,9 @@ class Activitypub_reject
* Generates an ActivityPub representation of a Reject
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param array $object
*
* @return array pretty array to be used in a response
*/
public static function reject_to_array(array $object): array
@ -48,7 +52,7 @@ class Activitypub_reject
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Reject',
'object' => $object
'object' => $object,
];
return $res;
}

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,7 +42,9 @@ class Activitypub_tag
* Generates a pretty tag from a Tag object
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @param string $tag
*
* @param array Tag $tag
*
* @return array pretty array to be used in a response
*/
public static function tag_to_array(string $tag): array

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -31,6 +32,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -40,17 +42,19 @@ class Activitypub_undo
* Generates an ActivityPub representation of a Undo
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*
* @param array $object
*
* @return array pretty array to be used in a response
*/
public static function undo_to_array(array $object): array
{
$res = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => $object['id'] . '#undo',
'id' => $object['id'] . '/undo',
'type' => 'Undo',
'actor' => $object['actor'],
'object' => $object
'object' => $object,
];
return $res;
}
@ -59,8 +63,11 @@ class Activitypub_undo
* Verifies if a given object is acceptable for a Undo Activity.
*
* @param array $object
* @return bool
*
* @throws Exception
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public static function validate_object(array $object): bool

View File

@ -18,12 +18,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
defined('GNUSOCIAL') || die();
/**
@ -34,6 +35,7 @@ defined('GNUSOCIAL') || die();
*
* @category Plugin
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
@ -50,8 +52,10 @@ class Activitypub_postman
* Create a postman to deliver something to someone
*
* @param Profile $from sender Profile
* @param array $to receiver AProfiles
* @param array $to receiver Profiles
*
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function __construct(Profile $from, array $to = [])
@ -85,9 +89,12 @@ class Activitypub_postman
* @param string $data request body
* @param string $inbox url of remote inbox
* @param string $method request method
* @return GNUsocial_HTTPResponse
*
* @throws HTTP_Request2_Exception
* @throws HTTP_Request2_LogicException
* @throws Exception
*
* @return GNUsocial_HTTPResponse
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function send($data, $inbox, $method = 'POST')
@ -108,7 +115,7 @@ class Activitypub_postman
$response = $this->client->get($inbox, $headers);
break;
default:
throw new Exception("Unsupported request method for postman.");
throw new Exception('Unsupported request method for postman.');
}
common_debug('ActivityPub Postman: Delivery result with status code ' . $response->getStatus() . ': ' . $response->getBody());
@ -118,9 +125,11 @@ class Activitypub_postman
/**
* Send a follow notification to remote instance
*
* @return bool
* @throws HTTP_Request2_Exception
* @throws Exception
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function follow()
@ -137,18 +146,20 @@ class Activitypub_postman
throw new Exception($res_body['error']);
}
throw new Exception("An unknown error occurred.");
throw new Exception('An unknown error occurred.');
}
/**
* Send a Undo Follow notification to remote instance
*
* @return bool
* @throws HTTP_Request2_Exception
* @throws Exception
* @throws Exception
* @throws Exception
* @throws Exception
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function undo_follow()
@ -171,16 +182,19 @@ class Activitypub_postman
if (isset($res_body['error'])) {
throw new Exception($res_body['error']);
}
throw new Exception("An unknown error occurred.");
throw new Exception('An unknown error occurred.');
}
/**
* Send a Accept Follow notification to remote instance
*
* @param string $id Follow activity id
* @return bool
*
* @throws HTTP_Request2_Exception
* @throws Exception Description of HTTP Response error or generic error message.
*
* @return bool
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function accept_follow(string $id): bool
@ -203,16 +217,18 @@ class Activitypub_postman
if (isset($res_body['error'])) {
throw new Exception($res_body['error']);
}
throw new Exception("An unknown error occurred.");
throw new Exception('An unknown error occurred.');
}
/**
* Send a Like notification to remote instances holding the notice
*
* @param Notice $notice
*
* @throws HTTP_Request2_Exception
* @throws InvalidUrlException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function like(Notice $notice): void
@ -239,7 +255,7 @@ class Activitypub_postman
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the like activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the like activity!');
}
}
@ -247,9 +263,11 @@ class Activitypub_postman
* Send a Undo Like notification to remote instances holding the notice
*
* @param Notice $notice
*
* @throws HTTP_Request2_Exception
* @throws InvalidUrlException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function undo_like($notice)
@ -279,7 +297,7 @@ class Activitypub_postman
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the undo-like activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the undo-like activity!');
}
}
@ -287,10 +305,12 @@ class Activitypub_postman
* Send a Create notification to remote instances
*
* @param Notice $notice
*
* @throws EmptyPkeyValueException
* @throws HTTP_Request2_Exception
* @throws InvalidUrlException
* @throws ServerException
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function create_note($notice)
@ -319,7 +339,7 @@ class Activitypub_postman
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the create-note activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the create-note activity!');
}
}
@ -327,6 +347,7 @@ class Activitypub_postman
* Send a Create direct-notification to remote instances
*
* @param Notice $message
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
public function create_direct_note(Notice $message)
@ -346,13 +367,12 @@ class Activitypub_postman
if (!($res->getStatus() == 200 || $res->getStatus() == 202 || $res->getStatus() == 409)) {
$res_body = json_decode($res->getBody(), true);
$errors[] = isset($res_body['error']) ?
$res_body['error'] : "An unknown error occurred.";
$to_failed[$inbox] = $message;
$res_body['error'] : 'An unknown error occurred.';
}
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the create-note activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the create-note activity!');
}
}
@ -360,8 +380,10 @@ class Activitypub_postman
* Send a Announce notification to remote instances
*
* @param Notice $notice
* @param Notice $repeat_of
*
* @throws HTTP_Request2_Exception
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function announce(Notice $notice, Notice $repeat_of): void
@ -388,7 +410,7 @@ class Activitypub_postman
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the announce activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the announce activity!');
}
}
@ -396,9 +418,11 @@ class Activitypub_postman
* Send a Delete notification to remote instances holding the notice
*
* @param Notice $notice
*
* @throws HTTP_Request2_Exception
* @throws InvalidUrlException
* @throws Exception
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
public function delete_note($notice)
@ -427,8 +451,12 @@ class Activitypub_postman
/**
* Send a Delete notification to remote followers of some deleted profile
*
* @param Profile $deleted_profile
* @param Notice $notice
*
* @throws HTTP_Request2_Exception
* @throws InvalidUrlException
* @throws Exception
*
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
*/
public function delete_profile(Profile $deleted_profile)
@ -453,7 +481,7 @@ class Activitypub_postman
}
if (!empty($errors)) {
common_log(LOG_ERR, sizeof($errors) . " instance/s failed to handle the delete_profile activity!");
common_log(LOG_ERR, sizeof($errors) . ' instance/s failed to handle the delete_profile activity!');
}
}
@ -461,8 +489,11 @@ class Activitypub_postman
* Clean list of inboxes to deliver messages
*
* @param bool $actorFollowers whether to include the actor's follower collection
* @return array To Inbox URLs
*
* @throws Exception
*
* @return array To Inbox URLs
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
*/
private function to_inbox(bool $actorFollowers = true): array

View File

@ -19,12 +19,13 @@
* ActivityPub implementation for GNU social
*
* @package GNUsocial
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*
* @see http://www.gnu.org/software/social/
*/
define('INSTALLDIR', dirname(__DIR__, 3));
define('PUBLICDIR', INSTALLDIR . DIRECTORY_SEPARATOR . 'public');

View File

@ -44,7 +44,7 @@
<a href="{{ path("favourites", {'nickname' : user_nickname}) }}" class='hover-effect {{ active("favourites") }}'>Favourites</a>
<a href='#'>Reverse Favs</a>
<a href="{{ path('settings_personal_info') }}" class='hover-effect {{ active('settings_') }}'>Settings</a>
<a href='#'>Logout</a>
<a href='{{ path('logout') }}'>Logout</a>
</div>
<div class="footer">
<a href="{{ path('doc_faq') }}" class='hover-effect {{ active('doc_faq') }}'>FAQ</a>

View File

@ -0,0 +1,44 @@
<?php
// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
// }}}
namespace App\Tests\Util\Form\ActorArrayTransformer;
use App\Entity\GSActor;
use App\Util\Form\ActorArrayTransformer;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ActorArrayTransformerTest extends WebTestCase
{
public function testTransform()
{
static::assertSame('', (new ActorArrayTransformer)->transform([]));
$user1 = GSActor::create(['nickname' => 'user1']);
$user2 = GSActor::create(['nickname' => 'user2']);
$user3 = GSActor::create(['nickname' => 'user3']);
$testArr = [$user1, $user2, $user3];
static::assertSame('user1 user2 user3', (new ActorArrayTransformer)->transform($testArr));
}
public function testReverseTransform()
{
$testString = '';
static::assertSame([], (new ActorArrayTransformer)->reverseTransform($testString));
}
}