[CORE][ActivityStreamsTwo][ActivityPub] Set all routes

Allow global routes to act for every actor
Fix Favoured stream query
This commit is contained in:
Diogo Peralta Cordeiro 2021-09-16 17:04:05 +01:00
parent 738168461c
commit d6f31d102a
No known key found for this signature in database
GPG Key ID: 18D2D35001FBFAB0
17 changed files with 308 additions and 58 deletions

View File

@ -38,7 +38,7 @@ class Avatar extends Component
public function onAddRoute($r): bool public function onAddRoute($r): bool
{ {
$r->connect('avatar', '/{gsactor_id<\d+>}/avatar/{size<full|big|medium|small>?full}', [Controller\Avatar::class, 'avatar_view']); $r->connect('avatar', '/actor/{gsactor_id<\d+>}/avatar/{size<full|big|medium|small>?full}', [Controller\Avatar::class, 'avatar_view']);
$r->connect('settings_avatar', '/settings/avatar', [Controller\Avatar::class, 'settings_avatar']); $r->connect('settings_avatar', '/settings/avatar', [Controller\Avatar::class, 'settings_avatar']);
return Event::next; return Event::next;
} }

View File

@ -33,6 +33,7 @@ class Left extends Component
$user = Common::user(); $user = Common::user();
if ($user != null) { if ($user != null) {
$actor = $user->getActor(); $actor = $user->getActor();
$vars['user_id'] = $user->getId();
$vars['user_nickname'] = $user->getNickname(); $vars['user_nickname'] = $user->getNickname();
$vars['user_tags'] = $actor->getSelfTags(); $vars['user_tags'] = $actor->getSelfTags();
$vars['user_followers'] = $actor->getFollowersCount(); $vars['user_followers'] = $actor->getFollowersCount();

View File

@ -26,9 +26,21 @@ class ActivityPub extends Plugin
*/ */
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(RouteLoader $r): bool
{ {
$r->connect(
'activitypub_actor_inbox',
'/actor/{gsactor_id<\d+>}/inbox.json',
[Inbox::class, 'handle'],
options: ['accept' => ActivityStreamsTwo::$accept_headers]
);
$r->connect(
'activitypub_actor_outbox',
'/actor/{gsactor_id<\d+>}/outbox.json',
[Inbox::class, 'handle'],
options: ['accept' => ActivityStreamsTwo::$accept_headers]
);
$r->connect( $r->connect(
'activitypub_inbox', 'activitypub_inbox',
'{gsactor_id<\d+>}/inbox', '/inbox.json',
[Inbox::class, 'handle'], [Inbox::class, 'handle'],
options: ['accept' => ActivityStreamsTwo::$accept_headers] options: ['accept' => ActivityStreamsTwo::$accept_headers]
); );
@ -48,12 +60,12 @@ class ActivityPub extends Plugin
public static function validateAcceptHeader(array|string|null $accept, bool $strict): bool public static function validateAcceptHeader(array|string|null $accept, bool $strict): bool
{ {
if (is_string($accept) if (is_string($accept)
&& in_array($accept, self::$accept_headers) && in_array($accept, ActivityStreamsTwo::$accept_headers)
) { ) {
return true; return true;
} elseif (is_array($accept) } elseif (is_array($accept)
&& count( && count(
array_intersect($accept, self::$accept_headers) array_intersect($accept, ActivityStreamsTwo::$accept_headers)
) > 0 ) > 0
) { ) {
return true; return true;

View File

@ -4,7 +4,6 @@ namespace Plugin\ActivityStreamsTwo;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Core\Router\RouteLoader;
use Exception; use Exception;
use Plugin\ActivityStreamsTwo\Util\Response\ActorResponse; use Plugin\ActivityStreamsTwo\Util\Response\ActorResponse;
use Plugin\ActivityStreamsTwo\Util\Response\NoteResponse; use Plugin\ActivityStreamsTwo\Util\Response\NoteResponse;
@ -41,33 +40,24 @@ class ActivityStreamsTwo extends Plugin
return Event::next; return Event::next;
} }
switch ($route) { switch ($route) {
case 'actor_view_id':
case 'actor_view_nickname':
$response = ActorResponse::handle($vars['gsactor']);
return Event::stop;
case 'note_view': case 'note_view':
$response = NoteResponse::handle($vars['note']); $response = NoteResponse::handle($vars['note']);
return Event::stop; return Event::stop;
case 'gsactor_view_id': case 'actor_favourites':
case 'gsactor_view_nickname': $response = LikeResponse::handle($vars['gsactor']);
$response = ActorResponse::handle($vars['gsactor']); return Event::stop;
case 'actor_subscriptions':
$response = FollowingResponse::handle($vars['gsactor']);
return Event::stop;
case 'actor_subscribers':
$response = FollowersResponse::handle($vars['gsactor']);
return Event::stop; return Event::stop;
default: default:
return Event::next; return Event::next;
} }
} }
/**
* This code executes when GNU social creates the page routing, and we hook
* on this event to add our action handler for Embed.
*
* @param RouteLoader $r the router that was initialized.
*
* @return bool
*/
public function onAddRoute(RouteLoader $r): bool
{
/*$r->connect('note_view_as2',
'/note/{id<\d+>}',
[NoteResponse::class, 'handle'],
options: ['accept' => self::$accept_headers]
);*/
return Event::next;
}
} }

View File

@ -19,7 +19,7 @@ class GSActorToType
*/ */
public static function translate(GSActor $gsactor) public static function translate(GSActor $gsactor)
{ {
$uri = Router::url('gsactor_view_id', ['id' => $gsactor->getId()], Router::ABSOLUTE_URL); $uri = Router::url('actor_view_id', ['id' => $gsactor->getId()], Router::ABSOLUTE_URL);
$attr = [ $attr = [
'@context' => 'https://www.w3.org/ns/activitystreams', '@context' => 'https://www.w3.org/ns/activitystreams',
'id' => $uri, 'id' => $uri,
@ -42,7 +42,7 @@ class GSActorToType
'summary' => $gsactor->getBio(), 'summary' => $gsactor->getBio(),
//'tag' => //'tag' =>
'updated' => $gsactor->getModified()->format(DateTimeInterface::RFC3339), 'updated' => $gsactor->getModified()->format(DateTimeInterface::RFC3339),
'url' => Router::url('gsactor_view_nickname', ['nickname' => $gsactor->getNickname()], Router::ABSOLUTE_URL), 'url' => Router::url('actor_view_nickname', ['nickname' => $gsactor->getNickname()], Router::ABSOLUTE_URL),
]; ];
return Type::create(type: 'Person', attributes: $attr); return Type::create(type: 'Person', attributes: $attr);
} }

View File

@ -23,17 +23,19 @@ namespace Plugin\Favourite\Controller;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Util\Common;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
class Favourite class Favourite
{ {
public function favourites(Request $request) public function favouritesByActorId(Request $request, int $id)
{ {
$actor_id = Common::ensureLoggedIn()->getId(); $notes = DB::dql(
$notes = DB::dql('select f from Plugin\Favourite\Entity\Favourite f ' . 'select n from App\Entity\Note n, Plugin\Favourite\Entity\Favourite f ' .
'where f.gsactor_id = :id ' . 'where n.id = f.note_id ' .
'order by f.created DESC', ['id' => $actor_id]); 'and f.gsactor_id = :id ' .
'order by f.created DESC',
['id' => $id]
);
$notes_out = null; $notes_out = null;
Event::handle('FormatNoteList', [$notes, &$notes_out]); Event::handle('FormatNoteList', [$notes, &$notes_out]);
@ -43,6 +45,11 @@ class Favourite
'notes' => $notes_out, 'notes' => $notes_out,
]; ];
} }
public function favouritesByActorNickname(Request $request, string $nickname)
{
$user = DB::findOneBy('local_user', ['nickname' => $nickname]);
return self::favouritesByActorId($request, $user->getId());
}
/** /**
* Reverse favourites stream * Reverse favourites stream
@ -53,15 +60,15 @@ class Favourite
* *
* @return array template * @return array template
*/ */
public function reverseFavourites(Request $request) public function reverseFavouritesByActorId(Request $request, int $id)
{ {
$actor_id = Common::ensureLoggedIn()->getId();
$notes = DB::dql('select n from App\Entity\Note n, Plugin\Favourite\Entity\Favourite f ' . $notes = DB::dql('select n from App\Entity\Note n, Plugin\Favourite\Entity\Favourite f ' .
'where n.id = f.note_id ' . 'where n.id = f.note_id ' .
'and f.gsactor_id != :id ' . 'and f.gsactor_id != :id ' .
'and n.gsactor_id = :id ' . 'and n.gsactor_id = :id ' .
'order by f.created DESC' , 'order by f.created DESC' ,
['id' => $actor_id]); ['id' => $id]
);
$notes_out = null; $notes_out = null;
Event::handle('FormatNoteList', [$notes, &$notes_out]); Event::handle('FormatNoteList', [$notes, &$notes_out]);
@ -71,4 +78,9 @@ class Favourite
'notes' => $notes, 'notes' => $notes,
]; ];
} }
public function reverseFavouritesByActorNickname(Request $request, string $nickname)
{
$user = DB::findOneBy('local_user', ['nickname' => $nickname]);
return self::reverseFavouritesByActorId($request, $user->getId());
}
} }

View File

@ -24,6 +24,7 @@ namespace Plugin\Favourite;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m;
use App\Core\Modules\NoteHandlerPlugin; use App\Core\Modules\NoteHandlerPlugin;
use App\Core\Router\RouteLoader; use App\Core\Router\RouteLoader;
use App\Entity\Note; use App\Entity\Note;
@ -36,7 +37,6 @@ use App\Util\Nickname;
use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use function App\Core\I18n\_m;
class Favourite extends NoteHandlerPlugin class Favourite extends NoteHandlerPlugin
{ {
@ -60,7 +60,7 @@ class Favourite extends NoteHandlerPlugin
return Event::next; return Event::next;
} }
// if note is favourited, "is_set" is 1 // if note is favoured, "is_set" is 1
$opts = ['note_id' => $note->getId(), 'gsactor_id' => $user->getId()]; $opts = ['note_id' => $note->getId(), 'gsactor_id' => $user->getId()];
$is_set = DB::find('favourite', $opts) !== null; $is_set = DB::find('favourite', $opts) !== null;
$form_fav = Form::create([ $form_fav = Form::create([
@ -83,7 +83,7 @@ class Favourite extends NoteHandlerPlugin
/** /**
* Called from form handler * Called from form handler
* *
* @param Note $note to be favourited * @param Note $note to be favoured
* @param Form $data input * @param Form $data input
* *
* @throws RedirectException Always thrown in order to prevent accidental form re-submit from browser * @throws RedirectException Always thrown in order to prevent accidental form re-submit from browser
@ -117,16 +117,18 @@ class Favourite extends NoteHandlerPlugin
public function onInsertLeftPanelLink(string $user_nickname, &$res): bool public function onInsertLeftPanelLink(string $user_nickname, &$res): bool
{ {
$res[] = Formatting::twigRenderString(<<<END $res[] = Formatting::twigRenderString(<<<END
<a href="{{ path("favourites", {'nickname' : user_nickname}) }}" class='hover-effect {{ active("favourites") }}'>Favourites</a> <a href="{{ path("actor_favourites_nickname", {'nickname' : user_nickname}) }}" class='hover-effect {{ active("favourites") }}'>Favourites</a>
<a href="{{ path("reverse_favourites", {'nickname' : user_nickname}) }}" class='hover-effect {{ active("reverse_favourites") }}'>Reverse Favs</a> <a href="{{ path("actor_reverse_favourites_nickname", {'nickname' : user_nickname}) }}" class='hover-effect {{ active("reverse_favourites") }}'>Reverse Favs</a>
END, ['user_nickname' => $user_nickname]); END, ['user_nickname' => $user_nickname]);
return Event::next; return Event::next;
} }
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(RouteLoader $r): bool
{ {
$r->connect('favourites', '/favourites/{nickname<' . Nickname::DISPLAY_FMT . '>}', [Controller\Favourite::class, 'favourites']); $r->connect(id: 'actor_favourites_id', uri_path: '/actor/{id<\d+>}/favourites', target: [Controller\Favourite::class, 'favouritesByActorId']);
$r->connect('reverse_favourites', '/reverse_favourites/{nickname<' . Nickname::DISPLAY_FMT . '>}', [Controller\Favourite::class, 'reverseFavourites']); $r->connect(id: 'actor_reverse_favourites_id', uri_path: '/actor/{id<\d+>}/reverse_favourites', target: [Controller\Favourite::class, 'reverseFavouritesByActorId']);
$r->connect('actor_favourites_nickname', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/favourites', [Controller\Favourite::class, 'favouritesByActorNickname']);
$r->connect('actor_reverse_favourites_nickname', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/reverse_favourites', [Controller\Favourite::class, 'reverseFavouritesByActorNickname']);
return Event::next; return Event::next;
} }
} }

View File

@ -56,7 +56,7 @@ class GSActor extends Controller
} }
/** /**
* The page where the note and it's info is shown * The page where the actor's info is shown
*/ */
public function GSActorShowId(Request $request, int $id) public function GSActorShowId(Request $request, int $id)
{ {

View File

@ -0,0 +1,69 @@
<?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\Controller;
use App\Core\Controller;
use App\Core\DB\DB;
use function App\Core\I18n\_m;
use App\Util\Exception\ClientException;
use Symfony\Component\HttpFoundation\Request;
class Subscribers extends Controller
{
/**
* Generic function that handles getting a representation for an actor from id
*/
private function GSActorById(int $id, callable $handle)
{
$gsactor = DB::findOneBy('gsactor', ['id' => $id]);
if (empty($gsactor)) {
throw new ClientException(_m('No such actor.'), 404);
} else {
return $handle($gsactor);
}
}
/**
* Generic function that handles getting a representation for an actor from nickname
*/
private function GSActorByNickname(string $nickname, callable $handle)
{
$user = DB::findOneBy('local_user', ['nickname' => $nickname]);
$gsactor = DB::findOneBy('gsactor', ['id' => $user->getId()]);
if (empty($gsactor)) {
throw new ClientException(_m('No such actor.'), 404);
} else {
return $handle($gsactor);
}
}
/**
* Collection of an actor's subscribers
*/
public function GSActorShowId(Request $request, int $id)
{
return $this->GSActorById($id, fn ($gsactor) => ['_template' => 'subscribers/view.html.twig', 'gsactor' => $gsactor]);
}
public function GSActorShowNickname(Request $request, string $nickname)
{
return $this->GSActorByNickname($nickname, fn ($gsactor) => ['_template' => 'subscribers/view.html.twig', 'gsactor' => $gsactor]);
}
}

View File

@ -0,0 +1,69 @@
<?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\Controller;
use App\Core\Controller;
use App\Core\DB\DB;
use function App\Core\I18n\_m;
use App\Util\Exception\ClientException;
use Symfony\Component\HttpFoundation\Request;
class Subscriptions extends Controller
{
/**
* Generic function that handles getting a representation for an actor from id
*/
private function GSActorById(int $id, callable $handle)
{
$gsactor = DB::findOneBy('gsactor', ['id' => $id]);
if (empty($gsactor)) {
throw new ClientException(_m('No such actor.'), 404);
} else {
return $handle($gsactor);
}
}
/**
* Generic function that handles getting a representation for an actor from nickname
*/
private function GSActorByNickname(string $nickname, callable $handle)
{
$user = DB::findOneBy('local_user', ['nickname' => $nickname]);
$gsactor = DB::findOneBy('gsactor', ['id' => $user->getId()]);
if (empty($gsactor)) {
throw new ClientException(_m('No such actor.'), 404);
} else {
return $handle($gsactor);
}
}
/**
* Collection of an actor's subscriptions
*/
public function GSActorShowId(Request $request, int $id)
{
return $this->GSActorById($id, fn ($gsactor) => ['_template' => 'subscriptions/view.html.twig', 'gsactor' => $gsactor]);
}
public function GSActorShowNickname(Request $request, string $nickname)
{
return $this->GSActorByNickname($nickname, fn ($gsactor) => ['_template' => 'subscriptions/view.html.twig', 'gsactor' => $gsactor]);
}
}

View File

@ -68,7 +68,6 @@ class RouteLoader extends Loader
} }
ksort($to_load); ksort($to_load);
foreach ($to_load as $ns) { foreach ($to_load as $ns) {
$ns::load($this); $ns::load($this);
} }

View File

@ -20,14 +20,14 @@
// }}} // }}}
/** /**
* Define social's attachment routes * Define social's Actor routes
* *
* @package GNUsocial * @package GNUsocial
* @category Router * @category Router
* *
* @author Diogo Cordeiro <mail@diogo.site> * @author Diogo Cordeiro <mail@diogo.site>
* @author Hugo Sales <hugo@hsal.es> * @author Hugo Sales <hugo@hsal.es>
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
@ -40,9 +40,10 @@ use App\Util\Nickname;
abstract class GSActor abstract class GSActor
{ {
const LOAD_ORDER = 30; const LOAD_ORDER = 30;
public static function load(RouteLoader $r): void public static function load(RouteLoader $r): void
{ {
$r->connect(id: 'gsactor_view_id', uri_path: '/actor/{id<\d+>}', target: [C\GSActor::class, 'GSActorShowId']); $r->connect(id: 'actor_view_id', uri_path: '/actor/{id<\d+>}', target: [C\GSActor::class, 'GSActorShowId']);
$r->connect(id: 'gsactor_view_nickname', uri_path: '/{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GSActor::class, 'GSActorShowNickname'], options: ['is_system_path' => false]); $r->connect(id: 'actor_view_nickname', uri_path: '/@{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GSActor::class, 'GSActorShowNickname'], options: ['is_system_path' => false]);
} }
} }

View File

@ -26,7 +26,8 @@
* @category Router * @category Router
* *
* @author Hugo Sales <hugo@hsal.es> * @author Hugo Sales <hugo@hsal.es>
* @author Eliseu Amaro <eliseu@fc.up.pt> * @author Eliseu Amaro <mail@eliseuama.ro>
* @author Diogo Cordeiro <mail@diogo.site>
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
@ -54,8 +55,8 @@ abstract class Main
$r->connect('root', '/', RedirectController::class, ['defaults' => ['route' => 'main_all']]); $r->connect('root', '/', RedirectController::class, ['defaults' => ['route' => 'main_all']]);
$r->connect('main_public', '/main/public', [C\Network::class, 'public']); $r->connect('main_public', '/main/public', [C\Network::class, 'public']);
$r->connect('main_all', '/main/all', [C\Network::class, 'network']); $r->connect('main_all', '/main/all', [C\Network::class, 'network']);
$r->connect('home_all', '/{nickname<' . Nickname::DISPLAY_FMT . '>}/all', [C\Network::class, 'home']); $r->connect('home_all', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/all', [C\Network::class, 'home']);
$r->connect('replies', '/{nickname<' . Nickname::DISPLAY_FMT . '>}/replies', [C\Network::class, 'replies']); $r->connect('replies', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/replies', [C\Network::class, 'replies']);
$r->connect('panel', '/panel', [C\AdminPanel::class, 'site']); $r->connect('panel', '/panel', [C\AdminPanel::class, 'site']);
$r->connect('panel_site', '/panel/site', [C\AdminPanel::class, 'site']); $r->connect('panel_site', '/panel/site', [C\AdminPanel::class, 'site']);

View File

@ -20,14 +20,14 @@
// }}} // }}}
/** /**
* Define social's attachment routes * Define social's Note routes
* *
* @package GNUsocial * @package GNUsocial
* @category Router * @category Router
* *
* @author Diogo Cordeiro <mail@diogo.site> * @author Diogo Cordeiro <mail@diogo.site>
* @author Hugo Sales <hugo@hsal.es> * @author Hugo Sales <hugo@hsal.es>
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
@ -41,6 +41,6 @@ abstract class Note
const LOAD_ORDER = 40; const LOAD_ORDER = 40;
public static function load(RouteLoader $r): void public static function load(RouteLoader $r): void
{ {
$r->connect('note_view', '/note/{id<\d+>}', [C\Note::class, 'NoteShow']); $r->connect('note_view', '/object/note/{id<\d+>}', [C\Note::class, 'NoteShow']);
} }
} }

View File

@ -0,0 +1,47 @@
<?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/>.
// }}}
/**
* Define social's GSActor's subscribers routes
*
* @package GNUsocial
* @category Router
*
* @author Diogo Cordeiro <mail@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
namespace App\Routes;
use App\Controller as C;
use App\Core\Router\RouteLoader;
use App\Util\Nickname;
abstract class Subscribers
{
const LOAD_ORDER = 31;
public static function load(RouteLoader $r): void
{
$r->connect(id: 'actor_subscribers_id', uri_path: '/actor/{id<\d+>}/subscribers', target: [C\Subscribers::class, 'SubscribersByActorId']);
$r->connect(id: 'actor_subscribers_nickname', uri_path: '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/subscribers', target: [C\Subscribers::class, 'SubscribersByActorNickname']);
}
}

View File

@ -0,0 +1,47 @@
<?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/>.
// }}}
/**
* Define social's GSActor's subscriptions routes
*
* @package GNUsocial
* @category Router
*
* @author Diogo Cordeiro <mail@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
namespace App\Routes;
use App\Controller as C;
use App\Core\Router\RouteLoader;
use App\Util\Nickname;
abstract class Subscriptions
{
const LOAD_ORDER = 32;
public static function load(RouteLoader $r): void
{
$r->connect(id: 'actor_subscriptions_id', uri_path: '/actor/{id<\d+>}/subscriptions', target: [C\Subscriptions::class, 'SubscriptionsByActorId']);
$r->connect(id: 'actor_subscriptions_nickname', uri_path: '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/subscriptions', target: [C\Subscriptions::class, 'SubscriptionsByActorNickname']);
}
}

View File

@ -6,7 +6,7 @@
<aside class="panel-content accessibility-target"> <aside class="panel-content accessibility-target">
{% if app.user %} {% if app.user %}
<section class='section-widget section-widget-padded' title="{{ 'Your profile information.' | trans }}"> <section class='section-widget section-widget-padded' title="{{ 'Your profile information.' | trans }}">
<a id="user" href="{{ path('settings') }}"> <a id="user" href="{{ path('actor_view_nickname', {'nickname' : user_nickname}) }}">
<img src='{{ user_avatar }}' class="icon icon-avatar" alt="{{ 'Your account\'s avatar.' | trans }}"> <img src='{{ user_avatar }}' class="icon icon-avatar" alt="{{ 'Your account\'s avatar.' | trans }}">
<div class="user-info"> <div class="user-info">
<strong id="user-nickname" title="{{ 'Your account\' nickname.' | trans }}">{{ user_nickname }}</strong> <strong id="user-nickname" title="{{ 'Your account\' nickname.' | trans }}">{{ user_nickname }}</strong>