34 Commits

Author SHA1 Message Date
539104ec33 [PLUGIN][Pinboard] Refactor and cleanup code 2022-04-01 00:17:57 +01:00
74ffd261b8 [PLUGIN][Pinboard] Implement tag handling 2022-04-01 00:16:04 +01:00
ca9945a4be [ENTITY][Actor][COMPONENT][Tag] Add Actor->getNoteTags(?string $note_type) which gets a cached list of NoteTags for notes of type $note_type for the actor 2022-04-01 00:11:01 +01:00
08587b6942 [COMPONENT][Link][Tag] Refactor to make it easier to create links or tags from other places 2022-04-01 00:09:25 +01:00
1664293cf7 [PLUGIN][Pinboard] Change token to user user ID rather than nickname, to avoid complications with it possibly changing 2022-03-31 22:06:37 +01:00
94ab4ce8c4 [PLUGIN][Pinboard] Invalidate token and it's cache when actor information is changed via ActorForms 2022-03-31 03:47:14 +01:00
dd70de20da [PLUGIN][Pinboard] Implement token authentication and settings page, allowing the user to enable, disable, refresh or consult their token 2022-03-31 03:29:31 +01:00
ded9c86054 [CORE][DB] Add DB::refetch, which refetches an entity from the database, so it's managed and definitely up to date (use when wanting to update entities from cache) 2022-03-31 03:29:31 +01:00
20e07c9140 [CORE][DB] Make DB::dql return an object rather than an array if limit 1 is specified 2022-03-31 03:29:31 +01:00
4e2f6545ec [COMPONENT][Person][PLUGIN][WebHooks] Rename person settings section from 'others' to 'api' 2022-03-31 03:29:31 +01:00
f6a8f44420 [COMPONENT][Person][TEMPLATES] Move persosn settings template from core to the component 2022-03-31 03:29:31 +01:00
fd71d6ee7d [PLUGIN][UnboundGroup] Finish implementation 2022-03-29 00:57:41 +01:00
dfc5918c2c [PLUGIN][ActivityPub] Federate out Service information in Activities 2022-03-28 23:54:19 +01:00
83599ef866 [CORE][Modules][Plugin] version should be static 2022-03-28 23:54:18 +01:00
fa82306f6f [COMPONENT][Posting] Blog posts should be Articles by default 2022-03-28 23:54:18 +01:00
10f71e9fed [UI][TEMPLATES] Fix note text template. Use rendered content directly 2022-03-28 23:23:07 +01:00
e2501ee927 [PLUGIN][Pinboard] Implement remaining API endpoints, restructure, fix template 2022-03-28 23:23:07 +01:00
a9665177ea [PLUGIN][Blog] Move to plugins, mistakenly was in components 2022-03-28 20:59:16 +01:00
41861d284c [COMPONENT][Circle] Correct self tags settings text 2022-03-28 20:59:16 +01:00
bd868a2675 [PLUGINS][Pinboard] Add initial implementation of Pinboard API, lacking authentication, tags and feed endpoints 2022-03-28 20:59:16 +01:00
87e35716c1 [UTIL] Add Formatting::explode(array , string ) 2022-03-28 20:59:16 +01:00
dac94f53cd [CORE][Entity] Rename createOrUpdate to 'checkExistingAndCreateOrUpdate', remove update feature from 'create' and add 'createOrUpdate' and fix users 2022-03-28 20:59:15 +01:00
b10c359dec [DEPENDENCIES] Update dependencies 2022-03-28 20:59:15 +01:00
483983790a [CORE][Router] Rename \App\Core\Router\Router to \App\Core\Router and merge \App\Core\Router\RouteLoader with \App\Core\Router 2022-03-28 20:59:15 +01:00
60af9f5e9b [CORE][Queue] Rename App\Core\Queue\Queue to App\Core\Queue 2022-03-28 20:59:15 +01:00
abe35428da [CORE][DB] Rename App\Core\DB\DB to App\Core\DB 2022-03-28 20:59:14 +01:00
ca5520edbf [PLUGIN][WebHooks] Add hook for subscriptions 2022-03-28 20:59:14 +01:00
e3e14c53ef [PLUGIN][ActivityPub] Model/Note->toJson federate the url, even though it's the same as the id 2022-03-28 20:59:14 +01:00
be33c20614 [PLUGIN][ActivityPub] Improve flexibility of Type layer, accomodate more elaborate understanding of Group Announces after FEP-2100 development 2022-03-28 20:58:48 +01:00
7305a725cb [PLUGIN][UnboundGroup] First steps on implementing AP FEP-2100 2022-03-28 20:57:43 +01:00
fd4c3b0e68 [PLUGIN][Embed][Test] Move Test to correct location 2022-03-28 20:53:50 +01:00
16f51e5143 [COMPONENT][Notification] ->getSubscribers() should not be pre-included
Notification bug fix on Subscription component
Correct docblock
2022-03-28 20:53:19 +01:00
ba4230447e [COMPONENT][Group] Add orderBy to query, as otherwise the feed order is wrong 2022-03-28 20:49:28 +01:00
7463044971 [COMPONENT][Circle] Ensure strict typing on getter 2022-03-28 20:48:29 +01:00
192 changed files with 2197 additions and 701 deletions

View File

@@ -22,10 +22,10 @@ declare(strict_types = 1);
namespace Component\Attachment; namespace Component\Attachment;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Formatting; use App\Util\Formatting;
@@ -37,7 +37,7 @@ use Doctrine\ORM\QueryBuilder;
class Attachment extends Component class Attachment extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('note_attachment_show', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}', [C\Attachment::class, 'attachmentShowWithNote']); $r->connect('note_attachment_show', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}', [C\Attachment::class, 'attachmentShowWithNote']);
$r->connect('note_attachment_view', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}/view', [C\Attachment::class, 'attachmentViewWithNote']); $r->connect('note_attachment_view', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}/view', [C\Attachment::class, 'attachmentViewWithNote']);

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Attachment\Controller; namespace Component\Attachment\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -24,13 +24,13 @@ declare(strict_types = 1);
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -24,12 +24,12 @@ declare(strict_types = 1);
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Component\Attachment\tests\Controller; namespace Component\Attachment\tests\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Component\Attachment\Entity\Attachment; use Component\Attachment\Entity\Attachment;
use Component\Attachment\Entity\AttachmentToNote; use Component\Attachment\Entity\AttachmentToNote;

View File

@@ -21,10 +21,10 @@ declare(strict_types = 1);
namespace Component\Attachment\tests\Entity; namespace Component\Attachment\tests\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Note; use App\Entity\Note;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use App\Util\TemporaryFile; use App\Util\TemporaryFile;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Attachment\tests\Entity; namespace Component\Attachment\tests\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Util\Exception\NotStoredLocallyException; use App\Util\Exception\NotStoredLocallyException;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;

View File

@@ -22,12 +22,11 @@ declare(strict_types = 1);
namespace Component\Avatar; namespace Component\Avatar;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Util\Common; use App\Util\Common;
use Component\Attachment\Entity\Attachment; use Component\Attachment\Entity\Attachment;
use Component\Attachment\Entity\AttachmentThumbnail; use Component\Attachment\Entity\AttachmentThumbnail;
@@ -41,7 +40,7 @@ class Avatar extends Component
{ {
} }
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('avatar_actor', '/actor/{actor_id<\d+>}/avatar/{size<full|big|medium|small>?medium}', [Controller\Avatar::class, 'avatar_view']); $r->connect('avatar_actor', '/actor/{actor_id<\d+>}/avatar/{size<full|big|medium|small>?medium}', [Controller\Avatar::class, 'avatar_view']);
$r->connect('avatar_default', '/avatar/default/{size<full|big|medium|small>?medium}', [Controller\Avatar::class, 'default_avatar_view']); $r->connect('avatar_default', '/avatar/default/{size<full|big|medium|small>?medium}', [Controller\Avatar::class, 'default_avatar_view']);

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Avatar\Controller; namespace Component\Avatar\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use App\Core\GSFile; use App\Core\GSFile;

View File

@@ -24,10 +24,10 @@ declare(strict_types = 1);
namespace Component\Avatar\Entity; namespace Component\Avatar\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use App\Core\Router\Router; use App\Core\Router;
use App\Util\Common; use App\Util\Common;
use Component\Attachment\Entity\Attachment; use Component\Attachment\Entity\Attachment;
use Component\Attachment\Entity\AttachmentThumbnail; use Component\Attachment\Entity\AttachmentThumbnail;

View File

@@ -24,16 +24,14 @@ declare(strict_types = 1);
namespace Component\Circle; namespace Component\Circle;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Feed; use App\Entity\Feed;
use App\Entity\LocalUser; use App\Entity\LocalUser;
use App\Util\Common;
use App\Util\Nickname; use App\Util\Nickname;
use Component\Circle\Controller as CircleController; use Component\Circle\Controller as CircleController;
use Component\Circle\Entity\ActorCircle; use Component\Circle\Entity\ActorCircle;
@@ -60,7 +58,7 @@ class Circle extends Component
protected const SLUG = 'circle'; protected const SLUG = 'circle';
protected const PLURAL_SLUG = 'circles'; protected const PLURAL_SLUG = 'circles';
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('actor_circle_view_by_circle_id', '/circle/{circle_id<\d+>}', [CircleController\Circle::class, 'circleById']); $r->connect('actor_circle_view_by_circle_id', '/circle/{circle_id<\d+>}', [CircleController\Circle::class, 'circleById']);
// View circle members by (tagger id or nickname) and tag // View circle members by (tagger id or nickname) and tag
@@ -99,10 +97,10 @@ class Circle extends Component
{ {
if ($section === 'profile' && \in_array($request->get('_route'), ['person_actor_settings', 'group_actor_settings'])) { if ($section === 'profile' && \in_array($request->get('_route'), ['person_actor_settings', 'group_actor_settings'])) {
$tabs[] = [ $tabs[] = [
'title' => 'Self tags', 'title' => _m('Self tags'),
'desc' => 'Add or remove tags on yourself', 'desc' => _m('Add or remove tags to this actor'),
'id' => 'settings-self-tags', 'id' => 'settings-self-tags',
'controller' => CircleController\SelfTagsSettings::settingsSelfTags($request, Common::actor(), 'settings-self-tags-details'), 'controller' => CircleController\SelfTagsSettings::settingsSelfTags($request, Actor::getById((int) $request->get('id')), 'settings-self-tags-details'),
]; ];
} }
return Event::next; return Event::next;

View File

@@ -24,8 +24,8 @@ declare(strict_types = 1);
namespace Component\Circle\Controller; namespace Component\Circle\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;
use Component\Circle\Entity\ActorCircle; use Component\Circle\Entity\ActorCircle;

View File

@@ -6,7 +6,7 @@ namespace Component\Circle\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Entity as E; use App\Entity as E;
use App\Util\Common; use App\Util\Common;
@@ -45,7 +45,7 @@ class SelfTagsSettings extends Controller
foreach ($tags as $tag) { foreach ($tags as $tag) {
$tag = CompTag::sanitize($tag); $tag = CompTag::sanitize($tag);
[$actor_tag, $actor_tag_existed] = ActorTag::createOrUpdate([ [$actor_tag, $actor_tag_existed] = ActorTag::checkExistingAndCreateOrUpdate([
'tagger' => $target->getId(), // self tag means tagger = tagger in ActorTag 'tagger' => $target->getId(), // self tag means tagger = tagger in ActorTag
'tagged' => $target->getId(), 'tagged' => $target->getId(),
'tag' => $tag, 'tag' => $tag,

View File

@@ -22,9 +22,9 @@ declare(strict_types = 1);
namespace Component\Circle\Entity; namespace Component\Circle\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Router\Router; use App\Core\Router;
use DateTimeInterface; use DateTimeInterface;
/** /**

View File

@@ -21,9 +21,9 @@ declare(strict_types = 1);
namespace Component\Circle\Entity; namespace Component\Circle\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use Component\Tag\Tag; use Component\Tag\Tag;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -34,7 +34,7 @@ abstract class SelfTagsForm
$existing_form = !empty($form_definition) ? Form::create($form_definition) : null; $existing_form = !empty($form_definition) ? Form::create($form_definition) : null;
$add_form = Form::create([ $add_form = Form::create([
['new-tags', TextType::class, ['label' => ' ', 'data' => [], 'required' => false, 'help' => _m('Tags for yourself (letters, numbers, -, ., and _), comma- or space-separated.'), 'transformer' => ArrayTransformer::class]], ['new-tags', TextType::class, ['label' => ' ', 'data' => [], 'required' => false, 'help' => _m('Tags for this actor (letters, numbers, -, ., and _), comma- or space-separated.'), 'transformer' => ArrayTransformer::class]],
[$add_form_name = 'new-tags-add', SubmitType::class, ['label' => $add_label]], [$add_form_name = 'new-tags-add', SubmitType::class, ['label' => $add_label]],
]); ]);

View File

@@ -4,7 +4,7 @@ declare(strict_types = 1);
namespace Component\Collection; namespace Component\Collection;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -31,7 +31,7 @@ declare(strict_types = 1);
namespace Component\Collection\Util\Controller; namespace Component\Collection\Util\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Entity\LocalUser; use App\Entity\LocalUser;

View File

@@ -31,7 +31,7 @@ declare(strict_types = 1);
namespace Component\Collection\Util; namespace Component\Collection\Util;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;

View File

@@ -28,11 +28,11 @@ declare(strict_types = 1);
namespace Component\Conversation\Controller; namespace Component\Conversation\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -28,12 +28,11 @@ declare(strict_types = 1);
namespace Component\Conversation; namespace Component\Conversation;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
@@ -46,7 +45,7 @@ use Symfony\Component\HttpFoundation\Request;
class Conversation extends Component class Conversation extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('conversation', '/conversation/{conversation_id<\d+>}', [Controller\Conversation::class, 'showConversation']); $r->connect('conversation', '/conversation/{conversation_id<\d+>}', [Controller\Conversation::class, 'showConversation']);
$r->connect('conversation_mute', '/conversation/{conversation_id<\d+>}/mute', [Controller\Conversation::class, 'muteConversation']); $r->connect('conversation_mute', '/conversation/{conversation_id<\d+>}/mute', [Controller\Conversation::class, 'muteConversation']);

View File

@@ -23,9 +23,9 @@ declare(strict_types = 1);
namespace Component\Conversation\Entity; namespace Component\Conversation\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Router\Router; use App\Core\Router;
/** /**
* Entity class for Conversations * Entity class for Conversations

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Conversation\Entity; namespace Component\Conversation\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -25,12 +25,12 @@ namespace Component\Feed;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use Component\Feed\Controller as C; use Component\Feed\Controller as C;
class Feed extends Component class Feed extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('feed_public', '/feed/public', [C\Feeds::class, 'public']); $r->connect('feed_public', '/feed/public', [C\Feeds::class, 'public']);
$r->connect('feed_home', '/feed/home', [C\Feeds::class, 'home']); $r->connect('feed_home', '/feed/home', [C\Feeds::class, 'home']);

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Component\Feed\tests\Controller; namespace Component\Feed\tests\Controller;
use App\Core\Router\Router; use App\Core\Router;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Component\Feed\Controller\Feeds; use Component\Feed\Controller\Feeds;
use Jchook\AssertThrows\AssertThrows; use Jchook\AssertThrows\AssertThrows;

View File

@@ -34,7 +34,7 @@ declare(strict_types = 1);
namespace Component\FreeNetwork\Controller; namespace Component\FreeNetwork\Controller;
use App\Core\DB\DB; use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Util\Common; use App\Util\Common;
use Component\Collection\Util\Controller\FeedController; use Component\Collection\Util\Controller\FeedController;

View File

@@ -32,7 +32,7 @@ declare(strict_types = 1);
namespace Component\FreeNetwork\Entity; namespace Component\FreeNetwork\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Actor; use App\Entity\Actor;
use Component\FreeNetwork\Util\Discovery; use Component\FreeNetwork\Util\Discovery;

View File

@@ -21,15 +21,14 @@ declare(strict_types = 1);
namespace Component\FreeNetwork; namespace Component\FreeNetwork;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;
@@ -86,7 +85,7 @@ class FreeNetwork extends Component
return Event::next; return Event::next;
} }
public function onAddRoute(RouteLoader $m): bool public function onAddRoute(Router $m): bool
{ {
// Feeds // Feeds
$m->connect('feed_network', '/feed/network', [Feeds::class, 'network']); $m->connect('feed_network', '/feed/network', [Feeds::class, 'network']);

View File

@@ -6,7 +6,7 @@ namespace Component\FreeNetwork\Util\WebfingerResource;
use App\Core\Event; use App\Core\Event;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Common; use App\Util\Common;
use Component\FreeNetwork\Exception\WebfingerReconstructionException; use Component\FreeNetwork\Exception\WebfingerReconstructionException;

View File

@@ -26,7 +26,7 @@ namespace Component\Group\Controller;
use App\Core\ActorLocalRoles; use App\Core\ActorLocalRoles;
use App\Core\Cache; use App\Core\Cache;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;

View File

@@ -24,10 +24,10 @@ declare(strict_types = 1);
namespace Component\Group\Controller; namespace Component\Group\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity as E; use App\Entity as E;
use App\Util\Common; use App\Util\Common;
@@ -80,6 +80,7 @@ class GroupFeed extends FeedController
WHERE act.object_type = 'note' AND act.id IN WHERE act.object_type = 'note' AND act.id IN
(SELECT att.activity_id FROM \Component\Notification\Entity\Notification AS att WHERE att.target_id = :id) (SELECT att.activity_id FROM \Component\Notification\Entity\Notification AS att WHERE att.target_id = :id)
) )
ORDER BY n.created DESC
EOF, ['id' => $group->getId()]); EOF, ['id' => $group->getId()]);
return [ return [

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Group\Entity; namespace Component\Group\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Exception\NicknameEmptyException; use App\Util\Exception\NicknameEmptyException;

View File

@@ -24,8 +24,7 @@ namespace Component\Group;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Common; use App\Util\Common;
@@ -38,7 +37,7 @@ use Symfony\Component\HttpFoundation\Request;
class Group extends Component class Group extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect(id: 'group_actor_view_id', uri_path: '/group/{id<\d+>}', target: [C\GroupFeed::class, 'groupViewId']); $r->connect(id: 'group_actor_view_id', uri_path: '/group/{id<\d+>}', target: [C\GroupFeed::class, 'groupViewId']);
$r->connect(id: 'group_actor_view_nickname', uri_path: '/!{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GroupFeed::class, 'groupViewNickname']); $r->connect(id: 'group_actor_view_nickname', uri_path: '/!{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GroupFeed::class, 'groupViewNickname']);
@@ -80,7 +79,6 @@ class Group extends Component
$url = Router::url('group_actor_settings', ['id' => $group->getId()]); $url = Router::url('group_actor_settings', ['id' => $group->getId()]);
$res[] = HTML::html(['a' => ['attrs' => ['href' => $url, 'title' => _m('Edit group settings'), 'class' => 'profile-extra-actions'], _m('Group settings')]]); $res[] = HTML::html(['a' => ['attrs' => ['href' => $url, 'title' => _m('Edit group settings'), 'class' => 'profile-extra-actions'], _m('Group settings')]]);
} }
$res[] = HTML::html(['a' => ['attrs' => ['href' => Router::url('blog_post', ['in' => $group->getId()]), 'title' => _m('Make a new blog post'), 'class' => 'profile-extra-actions'], _m('Post in blog')]]);
} }
return Event::next; return Event::next;
} }

View File

@@ -7,7 +7,7 @@
<h1>Settings</h1> <h1>Settings</h1>
<ul> <ul>
<li> <li>
{% set profile_tabs = [{'title': 'Personal Info', 'desc': 'Nickname, Homepage, Bio, Self Tags and more.', 'id': 'settings-personal-info', 'form': personal_info_form}] %} {% set profile_tabs = [{'title': 'Personal Info', 'desc': 'Nickname, Homepage, Bio and more.', 'id': 'settings-personal-info', 'form': personal_info_form}] %}
{% set profile_tabs = profile_tabs|merge(handle_event('PopulateSettingsTabs', app.request, 'profile')) %} {% set profile_tabs = profile_tabs|merge(handle_event('PopulateSettingsTabs', app.request, 'profile')) %}
{{ macros.settings_details_container('Profile', 'Personal Information, Avatar and Profile', 'settings-profile-details', profile_tabs, _context) }} {{ macros.settings_details_container('Profile', 'Personal Information, Avatar and Profile', 'settings-profile-details', profile_tabs, _context) }}
</li> </li>

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Group\tests\Entity; namespace Component\Group\tests\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Component\Group\Entity\LocalGroup; use Component\Group\Entity\LocalGroup;

View File

@@ -25,7 +25,7 @@ namespace Component\Language\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Util\Common; use App\Util\Common;

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Language\Entity; namespace Component\Language\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Language\Entity; namespace Component\Language\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -23,7 +23,7 @@ namespace Component\Language;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Formatting; use App\Util\Formatting;
@@ -38,7 +38,7 @@ use Symfony\Component\HttpFoundation\Request;
class Language extends Component class Language extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('settings_sort_languages', '/settings/sort_languages', [C\Language::class, 'sortLanguages']); $r->connect('settings_sort_languages', '/settings/sort_languages', [C\Language::class, 'sortLanguages']);
return Event::next; return Event::next;

View File

@@ -25,10 +25,10 @@ namespace Component\LeftPanel\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Feed; use App\Entity\Feed;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -22,12 +22,11 @@ declare(strict_types = 1);
namespace Component\LeftPanel; namespace Component\LeftPanel;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Feed; use App\Entity\Feed;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
@@ -36,7 +35,7 @@ use Component\LeftPanel\Controller as C;
class LeftPanel extends Component class LeftPanel extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('edit_feeds', '/edit-feeds', C\EditFeeds::class); $r->connect('edit_feeds', '/edit-feeds', C\EditFeeds::class);
return Event::next; return Event::next;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Link\Entity; namespace Component\Link\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Link\Entity; namespace Component\Link\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use DateTimeInterface; use DateTimeInterface;
@@ -84,16 +84,14 @@ class NoteToLink extends Entity
* Create an instance of NoteToLink or fill in the * Create an instance of NoteToLink or fill in the
* properties of $obj with the associative array $args. Doesn't * properties of $obj with the associative array $args. Doesn't
* persist the result * persist the result
*
* @param null|mixed $obj
*/ */
public static function create(array $args, $obj = null) public static function create(array $args, bool $_delegated_call = false): static
{ {
$link = DB::find('link', ['id' => $args['link_id']]); $link = DB::find('link', ['id' => $args['link_id']]);
$note = DB::find('note', ['id' => $args['note_id']]); $note = DB::find('note', ['id' => $args['note_id']]);
Event::handle('NewLinkFromNote', [$link, $note]); Event::handle('NewLinkFromNote', [$link, $note]);
$obj = new self(); $obj = new self();
return parent::create($args, $obj); return parent::createOrUpdate(obj: $obj, args: $args);
} }
public static function removeWhereNoteId(int $note_id): mixed public static function removeWhereNoteId(int $note_id): mixed

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Component\Link; namespace Component\Link;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Entity\Actor; use App\Entity\Actor;
@@ -35,6 +35,22 @@ use InvalidArgumentException;
class Link extends Component class Link extends Component
{ {
/**
* Note that this persists both a Link and a NoteToLink
*
* @return [Entity\Link, NoteToLink]
*/
public static function maybeCreateLink(string $url, int $note_id): array
{
try {
$link = Entity\Link::getOrCreate($url);
DB::persist($note_link = NoteToLink::create(['link_id' => $link->getId(), 'note_id' => $note_id]));
return ['link' => $link, 'note_to_link' => $note_link];
} catch (InvalidArgumentException) {
return ['link' => null, 'note_to_link' => null];
}
}
/** /**
* Extract URLs from $content and create the appropriate Link and NoteToLink entities * Extract URLs from $content and create the appropriate Link and NoteToLink entities
*/ */
@@ -49,12 +65,7 @@ class Link extends Component
if (\in_array($match, $ignore)) { if (\in_array($match, $ignore)) {
continue; continue;
} }
try { self::maybeCreateLink($match, $note_id);
$link_id = Entity\Link::getOrCreate($match)->getId();
DB::persist(NoteToLink::create(['link_id' => $link_id, 'note_id' => $note->getId()]));
} catch (InvalidArgumentException) {
continue;
}
} }
} }
return Event::next; return Event::next;

View File

@@ -35,7 +35,7 @@ declare(strict_types = 1);
namespace Component\Notification\Controller; namespace Component\Notification\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Util\Common; use App\Util\Common;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
namespace Component\Notification\Entity; namespace Component\Notification\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -21,14 +21,13 @@ declare(strict_types = 1);
namespace Component\Notification; namespace Component\Notification;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Queue\Queue; use App\Core\Queue;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;
@@ -40,7 +39,7 @@ use Throwable;
class Notification extends Component class Notification extends Component
{ {
public function onAddRoute(RouteLoader $m): bool public function onAddRoute(Router $m): bool
{ {
$m->connect('feed_notifications', '/feed/notifications', [Feed::class, 'notifications']); $m->connect('feed_notifications', '/feed/notifications', [Feed::class, 'notifications']);
return Event::next; return Event::next;
@@ -65,25 +64,21 @@ class Notification extends Component
* Enqueues a notification for an Actor (such as person or group) which means * Enqueues a notification for an Actor (such as person or group) which means
* it shows up in their home feed and such. * it shows up in their home feed and such.
* WARNING: It's highly advisable to have flushed any relevant objects before triggering this event. * WARNING: It's highly advisable to have flushed any relevant objects before triggering this event.
* OBSERVATION: $sender->getSubscribers() will always be pre-included, thus why $targets=[] is normal
* *
* $targets should be of the shape: * $targets should be of the shape:
* ['source' => (int|Actor)[]] // Prefer Actor whenever possible * (int|Actor)[] // Prefer Actor whenever possible
* Example of $targets: * Example of $targets:
* [[42, $actor_alice, $actor_bob]] // Avoid repeating actors or ids * [42, $actor_alice, $actor_bob] // Avoid repeating actors or ids
* *
* @param Actor $sender The one responsible for this activity, take care not to include it in targets * @param Actor $sender The one responsible for this activity, take care not to include it in targets
* @param Activity $activity The activity responsible for the object being given to known to targets * @param Activity $activity The activity responsible for the object being given to known to targets
* @param array $targets attentions, Mentions, any other source * @param array $targets Attentions, Mentions, any other source. Should never be empty, you usually want to register an attention to every $sender->getSubscribers()
* @param null|string $reason An optional reason explaining why this notification exists * @param null|string $reason An optional reason explaining why this notification exists
*/ */
public function onNewNotification(Actor $sender, Activity $activity, array $targets = [], ?string $reason = null): bool public function onNewNotification(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool
{ {
// Ensure targets are all actor objects and unique // Ensure targets are all actor objects and unique
$effective_targets = []; $effective_targets = [];
foreach ($sender->getSubscribers() as $subscriber) {
$effective_targets[$subscriber->getId()] = $subscriber;
}
foreach ($targets as $target) { foreach ($targets as $target) {
if (\is_int($target)) { if (\is_int($target)) {
$target_id = $target; $target_id = $target;

View File

@@ -24,7 +24,7 @@ declare(strict_types = 1);
namespace Component\Person\Controller; namespace Component\Person\Controller;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity as E; use App\Entity as E;
use App\Entity\LocalUser; use App\Entity\LocalUser;

View File

@@ -38,7 +38,7 @@ namespace Component\Person\Controller;
// {{{ Imports // {{{ Imports
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
@@ -103,7 +103,7 @@ class PersonSettings extends Controller
$language_form = $language->settings($request); $language_form = $language->settings($request);
return [ return [
'_template' => 'settings/base.html.twig', '_template' => 'person/settings.html.twig',
'personal_info_form' => $personal_form->createView(), 'personal_info_form' => $personal_form->createView(),
'email_form' => $email_form->createView(), 'email_form' => $email_form->createView(),
'password_form' => $password_form->createView(), 'password_form' => $password_form->createView(),
@@ -286,7 +286,7 @@ class PersonSettings extends Controller
$data = $form->getData(); $data = $form->getData();
unset($data['translation_domain']); unset($data['translation_domain']);
try { try {
[$entity, $is_update] = UserNotificationPrefs::createOrUpdate( [$entity, $is_update] = UserNotificationPrefs::checkExistingAndCreateOrUpdate(
array_merge(['user_id' => $user->getId(), 'transport' => $transport_name], $data), array_merge(['user_id' => $user->getId(), 'transport' => $transport_name], $data),
find_by_keys: ['user_id', 'transport'], find_by_keys: ['user_id', 'transport'],
); );

View File

@@ -23,13 +23,13 @@ namespace Component\Person;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Util\Nickname; use App\Util\Nickname;
use Component\Person\Controller as C; use Component\Person\Controller as C;
class Person extends Component class Person extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect(id: 'person_actor_view_id', uri_path: '/person/{id<\d+>}', target: [C\PersonFeed::class, 'personViewId']); $r->connect(id: 'person_actor_view_id', uri_path: '/person/{id<\d+>}', target: [C\PersonFeed::class, 'personViewId']);
$r->connect(id: 'person_actor_view_nickname', uri_path: '/@{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\PersonFeed::class, 'personViewNickname'], options: ['is_system_path' => false]); $r->connect(id: 'person_actor_view_nickname', uri_path: '/@{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\PersonFeed::class, 'personViewNickname'], options: ['is_system_path' => false]);

View File

@@ -34,8 +34,8 @@
{{ macros.settings_details_container('Notifications', 'Enable/disable notifications (Email, XMPP, Replies...)', 'notifications', tabbed_forms_notify, _context) }} {{ macros.settings_details_container('Notifications', 'Enable/disable notifications (Email, XMPP, Replies...)', 'notifications', tabbed_forms_notify, _context) }}
</li> </li>
<li> <li>
{% set other_tabs = handle_event('PopulateSettingsTabs', app.request, 'others') %} {% set other_tabs = handle_event('PopulateSettingsTabs', app.request, 'api') %}
{{ macros.settings_details_container('Others', 'Other settings (plugins, etc.)', 'settings-other-details', other_tabs, _context) }} {{ macros.settings_details_container('API', 'API settings', 'settings-other-details', other_tabs, _context) }}
</li> </li>
</ul> </ul>
</nav> </nav>

View File

@@ -23,8 +23,8 @@ declare(strict_types = 1);
namespace Component\Person\tests\Controller; namespace Component\Person\tests\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\LocalUser; use App\Entity\LocalUser;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Jchook\AssertThrows\AssertThrows; use Jchook\AssertThrows\AssertThrows;

View File

@@ -8,7 +8,7 @@ use App\Core\ActorLocalRoles;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router\Router; use App\Core\Router;
use App\Core\VisibilityScope; use App\Core\VisibilityScope;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Common; use App\Util\Common;

View File

@@ -24,13 +24,12 @@ declare(strict_types = 1);
namespace Component\Posting; namespace Component\Posting;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Core\VisibilityScope; use App\Core\VisibilityScope;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
@@ -55,7 +54,7 @@ class Posting extends Component
{ {
public const route = 'posting_form_action'; public const route = 'posting_form_action';
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect(self::route, '/form/posting', Controller\Posting::class); $r->connect(self::route, '/form/posting', Controller\Posting::class);
return Event::next; return Event::next;
@@ -87,7 +86,7 @@ class Posting extends Component
* @throws DuplicateFoundException * @throws DuplicateFoundException
* @throws ServerException * @throws ServerException
*/ */
public static function storeLocalPage( public static function storeLocalArticle(
Actor $actor, Actor $actor,
?string $content, ?string $content,
string $content_type, string $content_type,
@@ -118,7 +117,7 @@ class Posting extends Component
rendered: $rendered, rendered: $rendered,
source: $source, source: $source,
); );
$note->setType('page'); $note->setType('article');
$note->setTitle($title); $note->setTitle($title);
if ($flush_and_notify) { if ($flush_and_notify) {
@@ -128,7 +127,7 @@ class Posting extends Component
$actor, $actor,
$activity, $activity,
$effective_attentions, $effective_attentions,
_m('Actor {actor_id} created page {note_id}.', [ _m('Actor {actor_id} created article {note_id}.', [
'{actor_id}' => $actor->getId(), '{actor_id}' => $actor->getId(),
'{note_id}' => $activity->getObjectId(), '{note_id}' => $activity->getObjectId(),
]), ]),

View File

@@ -23,11 +23,11 @@ declare(strict_types = 1);
namespace Component\Subscription\Controller; namespace Component\Subscription\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -24,12 +24,11 @@ declare(strict_types = 1);
namespace Component\Subscription; namespace Component\Subscription;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;
@@ -40,12 +39,11 @@ use App\Util\Exception\ServerException;
use Component\Notification\Entity\Attention; use Component\Notification\Entity\Attention;
use Component\Subscription\Controller\Subscribers as SubscribersController; use Component\Subscription\Controller\Subscribers as SubscribersController;
use Component\Subscription\Controller\Subscriptions as SubscriptionsController; use Component\Subscription\Controller\Subscriptions as SubscriptionsController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
class Subscription extends Component class Subscription extends Component
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect(id: 'actor_subscribe_add', uri_path: '/actor/subscribe/{object_id<\d+>}', target: [SubscribersController::class, 'subscribersAdd']); $r->connect(id: 'actor_subscribe_add', uri_path: '/actor/subscribe/{object_id<\d+>}', target: [SubscribersController::class, 'subscribersAdd']);
$r->connect(id: 'actor_subscribe_remove', uri_path: '/actor/unsubscribe/{object_id<\d+>}', target: [SubscribersController::class, 'subscribersRemove']); $r->connect(id: 'actor_subscribe_remove', uri_path: '/actor/unsubscribe/{object_id<\d+>}', target: [SubscribersController::class, 'subscribersRemove']);
@@ -113,8 +111,9 @@ class Subscription extends Component
\is_int($subject) ? $subject : Actor::getById($subscriber_id), \is_int($subject) ? $subject : Actor::getById($subscriber_id),
$activity, $activity,
[$subscribed_id], [$subscribed_id],
_m('{subject} subscribed to {object}.', ['{subject}' => $activity->getActorId(), '{object}' => $activity->getObjectId()]), $reason = _m('{subject} subscribed to {object}.', ['{subject}' => $activity->getActorId(), '{object}' => $activity->getObjectId()]),
]); ]);
Event::handle('NewSubscriptionEnd', [$subject, $activity, $object, $reason]);
} }
return $activity; return $activity;
} }
@@ -163,7 +162,7 @@ class Subscription extends Component
Event::handle('NewNotification', [ Event::handle('NewNotification', [
\is_int($subject) ? $subject : Actor::getById($subscriber_id), \is_int($subject) ? $subject : Actor::getById($subscriber_id),
$activity, $activity,
[], [$subscribed_id],
_m('{subject} unsubscribed from {object}.', ['{subject}' => $activity->getActorId(), '{object}' => $previous_follow_activity->getObjectId()]), _m('{subject} unsubscribed from {object}.', ['{subject}' => $activity->getActorId(), '{object}' => $previous_follow_activity->getObjectId()]),
]); ]);
} }

View File

@@ -22,9 +22,9 @@ declare(strict_types = 1);
namespace Component\Tag\Entity; namespace Component\Tag\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
use Component\Language\Entity\Language; use Component\Language\Entity\Language;

View File

@@ -22,7 +22,7 @@ declare(strict_types = 1);
namespace Component\Tag\Entity; namespace Component\Tag\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use Component\Tag\Tag; use Component\Tag\Tag;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -24,11 +24,11 @@ declare(strict_types = 1);
namespace Component\Tag; namespace Component\Tag;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
@@ -67,6 +67,54 @@ class Tag extends Component
return Event::next; return Event::next;
} }
public static function maybeCreateTag(string $tag, int $note_id, ?int $lang_id): ?NoteTag
{
if (!self::validate($tag)) {
return null; // Ignore invalid tag candidates
}
$canonical_tag = self::canonicalTag($tag, \is_null($lang_id) ? null : Language::getById($lang_id)->getLocale());
DB::persist($note_tag = NoteTag::create([
'tag' => $tag,
'canonical' => $canonical_tag,
'note_id' => $note_id,
'use_canonical' => $extra_args['tag_use_canonical'] ?? false,
'language_id' => $lang_id,
]));
foreach (self::cacheKeys($canonical_tag) as $key) {
Cache::delete($key);
}
return $note_tag;
}
/**
* @return NoteTag[]
*/
public static function getNoteTags(int $actor_id, ?string $note_type): array
{
$query = <<<'EOF'
select nt from \App\Entity\Note n
join \Component\Tag\Entity\NoteTag nt with n.id = nt.note_id
where n.actor_id = :id
EOF;
if (\is_null($note_type)) {
return Cache::getList(
Actor::cacheKeys($actor_id, 'any')['note-tags'],
fn () => DB::dql(
$query,
['id' => $actor_id],
),
);
} else {
return Cache::getList(
Actor::cacheKeys($actor_id, $note_type)['note-tags'],
fn () => DB::dql(
$query . ' and n.type = :type',
['id' => $actor_id, 'type' => $note_type],
),
);
}
}
/** /**
* Process note by extracting any tags present * Process note by extracting any tags present
*/ */
@@ -82,21 +130,7 @@ class Tag extends Component
$matched_tags = array_unique(F\map($matched_tags, fn ($m) => $m[2])); $matched_tags = array_unique(F\map($matched_tags, fn ($m) => $m[2]));
foreach ($matched_tags as $match) { foreach ($matched_tags as $match) {
$tag = self::extract($match); $tag = self::extract($match);
if (!self::validate($tag)) { self::maybeCreateTag(tag: $tag, note_id: $note->getId(), lang_id: $note->getLanguageId());
continue; // Ignore invalid tag candidates
}
$canonical_tag = self::canonicalTag($tag, \is_null($lang_id = $note->getLanguageId()) ? null : Language::getById($lang_id)->getLocale());
DB::persist(NoteTag::create([
'tag' => $tag,
'canonical' => $canonical_tag,
'note_id' => $note->getId(),
'use_canonical' => $extra_args['tag_use_canonical'] ?? false,
'language_id' => $lang_id,
]));
Cache::listPushLeft("tag-{$canonical_tag}", $note);
foreach (self::cacheKeys($canonical_tag) as $key) {
Cache::delete($key);
}
} }
return Event::next; return Event::next;
} }

147
composer.lock generated
View File

@@ -553,16 +553,16 @@
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
"version": "3.3.3", "version": "3.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/dbal.git", "url": "https://github.com/doctrine/dbal.git",
"reference": "82331b861727c15b1f457ef05a8729e508e7ead5" "reference": "83f779beaea1893c0bece093ab2104c6d15a7f26"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/82331b861727c15b1f457ef05a8729e508e7ead5", "url": "https://api.github.com/repos/doctrine/dbal/zipball/83f779beaea1893c0bece093ab2104c6d15a7f26",
"reference": "82331b861727c15b1f457ef05a8729e508e7ead5", "reference": "83f779beaea1893c0bece093ab2104c6d15a7f26",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -644,7 +644,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/dbal/issues", "issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.3.3" "source": "https://github.com/doctrine/dbal/tree/3.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -660,7 +660,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-03-09T15:39:50+00:00" "time": "2022-03-20T18:37:29+00:00"
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
@@ -1440,16 +1440,16 @@
}, },
{ {
"name": "doctrine/persistence", "name": "doctrine/persistence",
"version": "2.3.0", "version": "2.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/persistence.git", "url": "https://github.com/doctrine/persistence.git",
"reference": "f8af155c1e7963f3d2b4415097d55757bbaa53d8" "reference": "092a52b71410ac1795287bb5135704ef07d18dd0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/persistence/zipball/f8af155c1e7963f3d2b4415097d55757bbaa53d8", "url": "https://api.github.com/repos/doctrine/persistence/zipball/092a52b71410ac1795287bb5135704ef07d18dd0",
"reference": "f8af155c1e7963f3d2b4415097d55757bbaa53d8", "reference": "092a52b71410ac1795287bb5135704ef07d18dd0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1462,23 +1462,23 @@
}, },
"conflict": { "conflict": {
"doctrine/annotations": "<1.0 || >=2.0", "doctrine/annotations": "<1.0 || >=2.0",
"doctrine/common": "<2.10@dev" "doctrine/common": "<2.10"
}, },
"require-dev": { "require-dev": {
"composer/package-versions-deprecated": "^1.11", "composer/package-versions-deprecated": "^1.11",
"doctrine/annotations": "^1.0", "doctrine/annotations": "^1.0",
"doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/coding-standard": "^9.0",
"doctrine/common": "^3.0", "doctrine/common": "^3.0",
"phpstan/phpstan": "1.2.0", "phpstan/phpstan": "1.4.6",
"phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.5",
"symfony/cache": "^4.4 || ^5.0 || ^6.0", "symfony/cache": "^4.4 || ^5.4 || ^6.0",
"vimeo/psalm": "4.13.1" "vimeo/psalm": "4.21.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common", "Doctrine\\Common\\": "src/Common",
"Doctrine\\Persistence\\": "lib/Doctrine/Persistence" "Doctrine\\Persistence\\": "src/Persistence"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -1522,9 +1522,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/persistence/issues", "issues": "https://github.com/doctrine/persistence/issues",
"source": "https://github.com/doctrine/persistence/tree/2.3.0" "source": "https://github.com/doctrine/persistence/tree/2.4.1"
}, },
"time": "2022-01-09T19:58:46+00:00" "time": "2022-03-22T06:44:40+00:00"
}, },
{ {
"name": "doctrine/sql-formatter", "name": "doctrine/sql-formatter",
@@ -2043,16 +2043,16 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.4.1", "version": "7.4.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79" "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ac1ec1cd9b5624694c3a40be801d94137afb12b4",
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79", "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2147,7 +2147,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.4.1" "source": "https://github.com/guzzle/guzzle/tree/7.4.2"
}, },
"funding": [ "funding": [
{ {
@@ -2163,7 +2163,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-12-06T18:43:05+00:00" "time": "2022-03-20T14:16:28+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
@@ -2251,16 +2251,16 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.1.0", "version": "2.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2",
"reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2284,7 +2284,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.1-dev" "dev-master": "2.2-dev"
} }
}, },
"autoload": { "autoload": {
@@ -2346,7 +2346,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.1.0" "source": "https://github.com/guzzle/psr7/tree/2.2.1"
}, },
"funding": [ "funding": [
{ {
@@ -2362,7 +2362,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-10-06T17:43:30+00:00" "time": "2022-03-20T21:55:58+00:00"
}, },
{ {
"name": "jcupitt/vips", "name": "jcupitt/vips",
@@ -3321,16 +3321,16 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "2.3.5", "version": "2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "fd4380d6fc37626e2f799f29d91195040137eba9" "reference": "d7fd7450628561ba697b7097d86db72662f54aef"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/d7fd7450628561ba697b7097d86db72662f54aef",
"reference": "fd4380d6fc37626e2f799f29d91195040137eba9", "reference": "d7fd7450628561ba697b7097d86db72662f54aef",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3352,7 +3352,7 @@
"phpstan/phpstan": "^0.12.91", "phpstan/phpstan": "^0.12.91",
"phpunit/phpunit": "^8.5", "phpunit/phpunit": "^8.5",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"rollbar/rollbar": "^1.3", "rollbar/rollbar": "^1.3 || ^2 || ^3",
"ruflin/elastica": ">=0.90@dev", "ruflin/elastica": ">=0.90@dev",
"swiftmailer/swiftmailer": "^5.3|^6.0" "swiftmailer/swiftmailer": "^5.3|^6.0"
}, },
@@ -3404,7 +3404,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/2.3.5" "source": "https://github.com/Seldaek/monolog/tree/2.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -3416,7 +3416,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-10-01T21:08:31+00:00" "time": "2022-03-14T12:44:37+00:00"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
@@ -10715,16 +10715,16 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c" "reference": "6ff9b0e440fa66f97f207e181c41340ddfa5683d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c", "url": "https://api.github.com/repos/twigphp/Twig/zipball/6ff9b0e440fa66f97f207e181c41340ddfa5683d",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c", "reference": "6ff9b0e440fa66f97f207e181c41340ddfa5683d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10775,7 +10775,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.3.8" "source": "https://github.com/twigphp/Twig/tree/v3.3.9"
}, },
"funding": [ "funding": [
{ {
@@ -10787,7 +10787,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-02-04T06:59:48+00:00" "time": "2022-03-25T09:37:52+00:00"
}, },
{ {
"name": "voku/portable-ascii", "name": "voku/portable-ascii",
@@ -11242,16 +11242,16 @@
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.2.9", "version": "3.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649" "reference": "5d8e574bb0e69188786b8ef77d43341222a41a71"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649", "url": "https://api.github.com/repos/composer/semver/zipball/5d8e574bb0e69188786b8ef77d43341222a41a71",
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649", "reference": "5d8e574bb0e69188786b8ef77d43341222a41a71",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11303,7 +11303,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.9" "source": "https://github.com/composer/semver/tree/3.3.1"
}, },
"funding": [ "funding": [
{ {
@@ -11319,7 +11319,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-02-04T13:58:43+00:00" "time": "2022-03-16T11:22:07+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
@@ -11554,16 +11554,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.7.0", "version": "v3.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
"reference": "7705d5a985132a40282d18a176eb9a4a0497747c" "reference": "cbad1115aac4b5c3c5540e7210d3c9fba2f81fa3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/7705d5a985132a40282d18a176eb9a4a0497747c", "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/cbad1115aac4b5c3c5540e7210d3c9fba2f81fa3",
"reference": "7705d5a985132a40282d18a176eb9a4a0497747c", "reference": "cbad1115aac4b5c3c5540e7210d3c9fba2f81fa3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11631,7 +11631,7 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"support": { "support": {
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.7.0" "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.8.0"
}, },
"funding": [ "funding": [
{ {
@@ -11639,7 +11639,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-03-07T16:59:59+00:00" "time": "2022-03-18T17:20:59+00:00"
}, },
{ {
"name": "jchook/phpunit-assert-throws", "name": "jchook/phpunit-assert-throws",
@@ -12012,7 +12012,6 @@
"conflict": { "conflict": {
"phpstan/phpstan-shim": "*" "phpstan/phpstan-shim": "*"
}, },
"default-branch": true,
"bin": [ "bin": [
"phpstan", "phpstan",
"phpstan.phar" "phpstan.phar"
@@ -12372,16 +12371,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "9.5.18", "version": "9.5.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "1b5856028273bfd855e60a887278857d872ec67a" "reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b5856028273bfd855e60a887278857d872ec67a", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35ea4b7f3acabb26f4bb640f8c30866c401da807",
"reference": "1b5856028273bfd855e60a887278857d872ec67a", "reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -12411,7 +12410,7 @@
"sebastian/global-state": "^5.0.1", "sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3", "sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3", "sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^2.3.4", "sebastian/type": "^3.0",
"sebastian/version": "^3.0.2" "sebastian/version": "^3.0.2"
}, },
"require-dev": { "require-dev": {
@@ -12459,7 +12458,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.18" "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.19"
}, },
"funding": [ "funding": [
{ {
@@ -12471,7 +12470,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-03-08T06:52:28+00:00" "time": "2022-03-15T09:57:31+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@@ -13330,28 +13329,28 @@
}, },
{ {
"name": "sebastian/type", "name": "sebastian/type",
"version": "2.3.4", "version": "3.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/type.git", "url": "https://github.com/sebastianbergmann/type.git",
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.3" "php": ">=7.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9.3" "phpunit/phpunit": "^9.5"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.3-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@@ -13374,7 +13373,7 @@
"homepage": "https://github.com/sebastianbergmann/type", "homepage": "https://github.com/sebastianbergmann/type",
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/type/issues", "issues": "https://github.com/sebastianbergmann/type/issues",
"source": "https://github.com/sebastianbergmann/type/tree/2.3.4" "source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
}, },
"funding": [ "funding": [
{ {
@@ -13382,7 +13381,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-06-15T12:49:02+00:00" "time": "2022-03-15T09:54:48+00:00"
}, },
{ {
"name": "sebastian/version", "name": "sebastian/version",

View File

@@ -24,7 +24,7 @@ services:
resource: '../src/Controller' resource: '../src/Controller'
tags: ['controller.service_arguments'] tags: ['controller.service_arguments']
App\Core\Router\RouteLoader: App\Core\Router:
tags: ['routing.loader'] tags: ['routing.loader']
# Wrapper around Doctrine's StaticPHP metadata driver # Wrapper around Doctrine's StaticPHP metadata driver

View File

@@ -34,15 +34,14 @@ namespace Plugin\ActivityPub;
use ActivityPhp\Type; use ActivityPhp\Type;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Core\Queue\Queue; use App\Core\Queue;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
@@ -104,7 +103,7 @@ class ActivityPub extends Plugin
'User-Agent' => 'GNUsocialBot ' . GNUSOCIAL_VERSION . ' - ' . GNUSOCIAL_PROJECT_URL, 'User-Agent' => 'GNUsocialBot ' . GNUSOCIAL_VERSION . ' - ' . GNUSOCIAL_PROJECT_URL,
]; ];
public function version(): string public static function version(): string
{ {
return '3.0.0'; return '3.0.0';
} }
@@ -156,9 +155,9 @@ class ActivityPub extends Plugin
* This code executes when GNU social creates the page routing, and we hook * This code executes when GNU social creates the page routing, and we hook
* on this event to add our Inbox and Outbox handler for ActivityPub. * on this event to add our Inbox and Outbox handler for ActivityPub.
* *
* @param RouteLoader $r the router that was initialized * @param Router $r the router that was initialized
*/ */
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect( $r->connect(
'activitypub_inbox', 'activitypub_inbox',
@@ -324,12 +323,22 @@ class ActivityPub extends Plugin
array &$retry_args, array &$retry_args,
): bool { ): bool {
try { try {
$data = Model::toJson($activity); $data = Model::toType($activity);
if ($sender->isGroup()) { if ($sender->isGroup()) { // When the sender is a group,
// When the sender is a group, we have to wrap it in an Announce activity if ($activity->getVerb() === 'subscribe') {
$data = Type::create('Announce', ['object' => $data])->toJson(); // Regular postman happens
} elseif ($activity->getVerb() === 'undo' && $data->get('object')->get('type') === 'Follow') {
// Regular postman happens
} else {
// For every other activity sent by a Group, we have to wrap it in a transient Announce activity
$data = Type::create('Announce', [
'@context' => 'https:\/\/www.w3.org\/ns\/activitystreams',
'actor' => $sender->getUri(type: Router::ABSOLUTE_URL),
'object' => $data,
]);
} }
$res = self::postman($sender, $data, $inbox); }
$res = self::postman($sender, $data->toJson(), $inbox);
// accumulate errors for later use, if needed // accumulate errors for later use, if needed
$status_code = $res->getStatusCode(); $status_code = $res->getStatusCode();
@@ -377,6 +386,7 @@ class ActivityPub extends Plugin
// the actor, that could for example mean that OStatus handled this actor while we were deactivated // the actor, that could for example mean that OStatus handled this actor while we were deactivated
// On next interaction this should be resolved, for now continue // On next interaction this should be resolved, for now continue
if (\is_null($ap_target = DB::findOneBy(ActivitypubActor::class, ['actor_id' => $actor->getId()], return_null: true))) { if (\is_null($ap_target = DB::findOneBy(ActivitypubActor::class, ['actor_id' => $actor->getId()], return_null: true))) {
Log::info('FreeNetwork wrongly told ActivityPub that it can handle actor id: ' . $actor->getId() . ' you might want to keep an eye on it.');
continue; continue;
} }
$to_addr[$ap_target->getInboxSharedUri() ?? $ap_target->getInboxUri()][] = $actor; $to_addr[$ap_target->getInboxSharedUri() ?? $ap_target->getInboxUri()][] = $actor;

View File

@@ -33,11 +33,11 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Controller; namespace Plugin\ActivityPub\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Queue\Queue; use App\Core\Queue;
use App\Core\Router\Router; use App\Core\Router;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use Exception; use Exception;

View File

@@ -34,7 +34,7 @@ namespace Plugin\ActivityPub\Controller;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -32,7 +32,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Entity; namespace Plugin\ActivityPub\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Entity\Activity; use App\Entity\Activity;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -33,7 +33,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Entity; namespace Plugin\ActivityPub\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;

View File

@@ -32,7 +32,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Entity; namespace Plugin\ActivityPub\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use DateTimeInterface; use DateTimeInterface;

View File

@@ -32,7 +32,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Entity; namespace Plugin\ActivityPub\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Log; use App\Core\Log;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -4,7 +4,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Test\Fixtures; namespace Plugin\ActivityPub\Test\Fixtures;
use App\Core\DB\DB; use App\Core\DB;
use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Plugin\ActivityPub\Util\Model\Activity; use Plugin\ActivityPub\Util\Model\Activity;
@@ -43,8 +43,8 @@ class ActivityPubFixtures extends Fixture
$note_path = self::fixturesPath('objects/note.jsonld', $ontology); $note_path = self::fixturesPath('objects/note.jsonld', $ontology);
$note = Note::fromJson(fread(fopen($note_path, 'r'), filesize($note_path))); $note = Note::fromJson(fread(fopen($note_path, 'r'), filesize($note_path)));
DB::flush(); DB::flush();
$page_path = self::fixturesPath('objects/page.jsonld', $ontology); $article_path = self::fixturesPath('objects/article.jsonld', $ontology);
$page = Note::fromJson(fread(fopen($page_path, 'r'), filesize($page_path))); $article = Note::fromJson(fread(fopen($article_path, 'r'), filesize($article_path)));
DB::flush(); DB::flush();
$reply_path = self::fixturesPath('objects/reply.jsonld', $ontology); $reply_path = self::fixturesPath('objects/reply.jsonld', $ontology);
$reply = Note::fromJson(fread(fopen($reply_path, 'r'), filesize($reply_path))); $reply = Note::fromJson(fread(fopen($reply_path, 'r'), filesize($reply_path)));
@@ -57,8 +57,8 @@ class ActivityPubFixtures extends Fixture
$create_note_path = self::fixturesPath('activities/create_note.jsonld', $ontology); $create_note_path = self::fixturesPath('activities/create_note.jsonld', $ontology);
$create_note = Activity::fromJson(fread(fopen($create_note_path, 'r'), filesize($create_note_path))); $create_note = Activity::fromJson(fread(fopen($create_note_path, 'r'), filesize($create_note_path)));
DB::flush(); DB::flush();
$create_page_path = self::fixturesPath('activities/create_page.jsonld', $ontology); $create_article_path = self::fixturesPath('activities/create_article.jsonld', $ontology);
$create_page = Activity::fromJson(fread(fopen($create_page_path, 'r'), filesize($create_page_path))); $create_article = Activity::fromJson(fread(fopen($create_article_path, 'r'), filesize($create_article_path)));
DB::flush(); DB::flush();
$create_reply_path = self::fixturesPath('activities/create_reply.jsonld', $ontology); $create_reply_path = self::fixturesPath('activities/create_reply.jsonld', $ontology);
$create_reply = Activity::fromJson(fread(fopen($create_reply_path, 'r'), filesize($create_reply_path))); $create_reply = Activity::fromJson(fread(fopen($create_reply_path, 'r'), filesize($create_reply_path)));

View File

@@ -29,15 +29,15 @@
"https://instance.gnusocial.test/actor/21" "https://instance.gnusocial.test/actor/21"
], ],
"object": { "object": {
"type": "Page", "type": "Article",
"id": "https://instance.gnusocial.test/object/note/1338", "id": "https://instance.gnusocial.test/object/note/1338",
"published": "2022-03-17T23:30:26+00:00", "published": "2022-03-17T23:30:26+00:00",
"attributedTo": "https://instance.gnusocial.test/actor/42", "attributedTo": "https://instance.gnusocial.test/actor/42",
"name": "hello, world.", "name": "hello, world.",
"content": "<p>This is an interesting page.</p>", "content": "<p>This is an interesting article.</p>",
"mediaType": "text/html", "mediaType": "text/html",
"source": { "source": {
"content": "This is an interesting page.", "content": "This is an interesting article.",
"mediaType": "text/markdown" "mediaType": "text/markdown"
}, },
"attachment": [], "attachment": [],

View File

@@ -1,5 +1,5 @@
{ {
"type": "Page", "type": "Article",
"@context": [ "@context": [
"https://www.w3.org/ns/activitystreams", "https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1", "https://w3id.org/security/v1",
@@ -23,10 +23,10 @@
"published": "2022-03-17T23:30:26+00:00", "published": "2022-03-17T23:30:26+00:00",
"attributedTo": "https://instance.gnusocial.test/actor/42", "attributedTo": "https://instance.gnusocial.test/actor/42",
"name": "hello, world.", "name": "hello, world.",
"content": "<p>This is an interesting page.</p>", "content": "<p>This is an interesting article.</p>",
"mediaType": "text/html", "mediaType": "text/html",
"source": { "source": {
"content": "This is an interesting page.", "content": "This is an interesting article.",
"mediaType": "text/markdown" "mediaType": "text/markdown"
}, },
"attachment": [], "attachment": [],

View File

@@ -30,7 +30,7 @@ use Plugin\ActivityPub\ActivityPub;
use Plugin\ActivityPub\Entity\ActivitypubObject; use Plugin\ActivityPub\Entity\ActivitypubObject;
use Plugin\ActivityPub\Util\Explorer; use Plugin\ActivityPub\Util\Explorer;
class GSObjectPageTest extends GNUsocialTestCase class GSObjectArticleTest extends GNUsocialTestCase
{ {
public function testNoteFromJson() public function testNoteFromJson()
{ {
@@ -39,29 +39,29 @@ class GSObjectPageTest extends GNUsocialTestCase
$actor_uri = 'https://instance.gnusocial.test/actor/42'; $actor_uri = 'https://instance.gnusocial.test/actor/42';
$object_uri = 'https://instance.gnusocial.test/object/note/1338'; $object_uri = 'https://instance.gnusocial.test/object/note/1338';
$group_uri = 'https://instance.gnusocial.test/actor/21'; $group_uri = 'https://instance.gnusocial.test/actor/21';
$page = ActivityPub::getObjectByUri($object_uri, try_online: false); $article = ActivityPub::getObjectByUri($object_uri, try_online: false);
static::assertInstanceOf(Note::class, $page); static::assertInstanceOf(Note::class, $article);
static::assertSame(Explorer::getOneFromUri($actor_uri)->getId(), $page->getActorId()); static::assertSame(Explorer::getOneFromUri($actor_uri)->getId(), $article->getActorId());
static::assertSame('text/markdown', $page->getContentType()); static::assertSame('text/markdown', $article->getContentType());
static::assertSame('This is an interesting page.', $page->getContent()); static::assertSame('This is an interesting article.', $article->getContent());
static::assertSame('<p>This is an interesting page.</p>', $page->getRendered()); static::assertSame('<p>This is an interesting article.</p>', $article->getRendered());
static::assertSame('ActivityPub', $page->getSource()); static::assertSame('ActivityPub', $article->getSource());
static::assertNull($page->getReplyTo()); static::assertNull($article->getReplyTo());
static::assertFalse($page->getIsLocal()); static::assertFalse($article->getIsLocal());
static::assertSame(VisibilityScope::EVERYWHERE, $page->getScope()); static::assertSame(VisibilityScope::EVERYWHERE, $article->getScope());
static::assertSame($object_uri, $page->getUrl()); static::assertSame($object_uri, $article->getUrl());
static::assertNull($page->getLanguageLocale()); static::assertNull($article->getLanguageLocale());
static::assertSame('page', $page->getType()); static::assertSame('article', $article->getType());
static::assertSame('hello, world.', $page->getTitle()); static::assertSame('hello, world.', $article->getTitle());
$ap_object = ActivitypubObject::getByPK(['object_uri' => $object_uri]); $ap_object = ActivitypubObject::getByPK(['object_uri' => $object_uri]);
static::assertSame(Note::schemaName(), $ap_object->getObjectType()); static::assertSame(Note::schemaName(), $ap_object->getObjectType());
static::assertSame($object_uri, $ap_object->getObjectUri()); static::assertSame($object_uri, $ap_object->getObjectUri());
static::assertSame($page->getId(), $ap_object->getObjectId()); static::assertSame($article->getId(), $ap_object->getObjectId());
static::assertCount(1, $attT = $page->getAttentionTargets()); static::assertCount(1, $attT = $article->getAttentionTargets());
static::assertObjectEquals(Explorer::getOneFromUri($group_uri, try_online: false), $attT[0]); static::assertObjectEquals(Explorer::getOneFromUri($group_uri, try_online: false), $attT[0]);
static::assertSame([], $page->getMentionTargets()); static::assertSame([], $article->getMentionTargets());
} }
} }

View File

@@ -32,7 +32,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Util; namespace Plugin\ActivityPub\Util;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use App\Core\Log; use App\Core\Log;
use App\Entity\Actor; use App\Entity\Actor;

View File

@@ -30,6 +30,7 @@ namespace Plugin\ActivityPub\Util;
use App\Entity\Actor; use App\Entity\Actor;
use DateTime; use DateTime;
use Exception; use Exception;
use Plugin\ActivityPub\ActivityPub;
use Plugin\ActivityPub\Entity\ActivitypubRsa; use Plugin\ActivityPub\Entity\ActivitypubRsa;
class HTTPSignature class HTTPSignature
@@ -91,7 +92,7 @@ class HTTPSignature
'Date' => $date->format('D, d M Y H:i:s \G\M\T'), 'Date' => $date->format('D, d M Y H:i:s \G\M\T'),
'Host' => parse_url($url, \PHP_URL_HOST), 'Host' => parse_url($url, \PHP_URL_HOST),
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json, application/json', '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, 'User-Agent' => 'GNU social ActivityPub Plugin - v' . ActivityPub::version() . ' - ' . GNUSOCIAL_ENGINE_URL,
'Content-Type' => 'application/activity+json', 'Content-Type' => 'application/activity+json',
]; ];

View File

@@ -114,24 +114,36 @@ abstract class Model
*/ */
abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity; abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity;
/**
* Get a Type
*
* @throws \App\Util\Exception\ServerException
* @throws ClientException
*/
public static function toType(mixed $object): Type\AbstractObject
{
switch ($object::class) {
case \App\Entity\Activity::class:
return Activity::toType($object);
case \App\Entity\Note::class:
return Note::toType($object);
default:
$type = self::jsonToType($object);
Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]);
return $type;
}
}
/** /**
* Get a JSON * Get a JSON
* *
* @param ?int $options PHP JSON options * @param int $options PHP JSON options
* *
* @throws \App\Util\Exception\ServerException
* @throws ClientException * @throws ClientException
*/ */
public static function toJson(mixed $object, int $options = \JSON_UNESCAPED_SLASHES): string public static function toJson(mixed $object, int $options = \JSON_UNESCAPED_SLASHES): string
{ {
switch ($object::class) { return self::toType($object)->toJson($options);
case \App\Entity\Activity::class:
return Activity::toJson($object, $options);
case \App\Entity\Note::class:
return Note::toJson($object, $options);
default:
$type = self::jsonToType($object);
Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]);
return $type->toJson($options);
}
} }
} }

View File

@@ -34,11 +34,12 @@ namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type; use ActivityPhp\Type;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Activity as GSActivity; use App\Entity\Activity as GSActivity;
use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NoSuchActorException; use App\Util\Exception\NoSuchActorException;
use App\Util\Exception\NotFoundException; use App\Util\Exception\NotFoundException;
@@ -46,7 +47,6 @@ use App\Util\Exception\NotImplementedException;
use DateTimeInterface; use DateTimeInterface;
use Exception; use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use const JSON_UNESCAPED_SLASHES;
use Plugin\ActivityPub\ActivityPub; use Plugin\ActivityPub\ActivityPub;
use Plugin\ActivityPub\Entity\ActivitypubActivity; use Plugin\ActivityPub\Entity\ActivitypubActivity;
use Plugin\ActivityPub\Util\Explorer; use Plugin\ActivityPub\Util\Explorer;
@@ -90,9 +90,14 @@ class Activity extends Model
// Find Actor and Object // Find Actor and Object
$actor = Explorer::getOneFromUri($type_activity->get('actor')); $actor = Explorer::getOneFromUri($type_activity->get('actor'));
$type_object = $type_activity->get('object'); $type_object = $type_activity->get('object');
if (\is_string($type_object)) { // Retrieve it if (\is_string($type_object)) {
if (Common::isValidHttpUrl($type_object)) { // Retrieve it
$type_object = ActivityPub::getObjectByUri($type_object, try_online: true); $type_object = ActivityPub::getObjectByUri($type_object, try_online: true);
} else { // Encapsulated, if we have it locally, prefer it } else {
$type_object = Type::fromJson($type_object);
}
}
if ($type_object instanceof AbstractObject) { // Encapsulated, if we have it locally, prefer it
// TODO: Test authority of activity over object // TODO: Test authority of activity over object
try { try {
$type_object = ActivityPub::getObjectByUri($type_object->get('id'), try_online: false); $type_object = ActivityPub::getObjectByUri($type_object->get('id'), try_online: false);
@@ -153,7 +158,7 @@ class Activity extends Model
* *
* @throws ClientException * @throws ClientException
*/ */
public static function toJson(mixed $object, int $options = JSON_UNESCAPED_SLASHES): string public static function toType(mixed $object): AbstractObject
{ {
if ($object::class !== GSActivity::class) { if ($object::class !== GSActivity::class) {
throw new InvalidArgumentException('First argument type must be an Activity.'); throw new InvalidArgumentException('First argument type must be an Activity.');
@@ -172,6 +177,10 @@ class Activity extends Model
$attr = [ $attr = [
'type' => $gs_verb_to_activity_streams_two_verb, 'type' => $gs_verb_to_activity_streams_two_verb,
'@context' => ActivityPub::$activity_streams_two_context, '@context' => ActivityPub::$activity_streams_two_context,
'instrument' => Type::create('Service', [
'name' => 'GNU social ActivityPub Plugin - v' . ActivityPub::version(),
'url' => GNUSOCIAL_ENGINE_URL,
]),
'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL),
'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339),
'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL), 'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL),
@@ -186,7 +195,8 @@ class Activity extends Model
// Get object or Tombstone // Get object or Tombstone
try { try {
$child = $object->getObject(); // Throws NotFoundException $child = $object->getObject(); // Throws NotFoundException
$attr['object'] = ($attr['type'] === 'Create') ? self::jsonToType(Model::toJson($child)) : ActivityPub::getUriByObject($child); $prefer_embed = ['Create', 'Undo'];
$attr['object'] = \in_array($attr['type'], $prefer_embed) ? self::jsonToType(Model::toJson($child)) : ActivityPub::getUriByObject($child);
} catch (NotFoundException) { } catch (NotFoundException) {
// It seems this object was deleted, refer to it as a Tombstone // It seems this object was deleted, refer to it as a Tombstone
$uri = match ($object->getObjectType()) { $uri = match ($object->getObjectType()) {
@@ -203,6 +213,6 @@ class Activity extends Model
} }
$type = self::jsonToType($attr); $type = self::jsonToType($attr);
Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]);
return $type->toJson($options); return $type;
} }
} }

View File

@@ -33,6 +33,8 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Util\Model; namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use Exception;
use InvalidArgumentException;
use Plugin\ActivityPub\Entity\ActivitypubActivity; use Plugin\ActivityPub\Entity\ActivitypubActivity;
/** /**
@@ -45,27 +47,15 @@ class ActivityAnnounce extends Activity
{ {
protected static function handle_core_activity(\App\Entity\Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): ActivitypubActivity protected static function handle_core_activity(\App\Entity\Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): ActivitypubActivity
{ {
// The only core Announce we recognise is for (transitive) activities coming from Group actors // The only core Announce we recognise is for (transient) activities coming from Group actors
if ($actor->isGroup()) { if ($actor->isGroup()) {
if ($type_object instanceof AbstractObject) { if ($type_object instanceof AbstractObject) {
$actual_to = array_flip(\is_string($type_object->get('to')) ? [$type_object->get('to')] : $type_object->get('to')); return $ap_act = Activity::fromJson($type_object);
$actual_cc = array_flip(\is_string($type_object->get('cc')) ? [$type_object->get('cc')] : $type_object->get('cc')); } else {
$actual_cc[$type_activity->get('actor')] = true; // Add group to targets throw new Exception('Already handled.');
foreach (\is_string($type_activity->get('to')) ? [$type_activity->get('to')] : $type_activity->get('to') as $to) {
if ($to !== 'https://www.w3.org/ns/activitystreams#Public') {
$actual_to[$to] = true;
} }
} else {
throw new InvalidArgumentException('Unsupported Announce Activity.');
} }
foreach (\is_string($type_activity->get('cc')) ? [$type_activity->get('cc')] : $type_activity->get('cc') as $cc) {
if ($cc !== 'https://www.w3.org/ns/activitystreams#Public') {
$actual_cc[$cc] = true;
}
}
$type_object->set('to', array_keys($actual_to));
$type_object->set('cc', array_keys($actual_cc));
$ap_act = self::fromJson($type_object);
}
}
return $ap_act ?? ($ap_act = $type_object);
} }
} }

View File

@@ -33,7 +33,7 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Util\Model; namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\DB\DB; use App\Core\DB;
use App\Entity\Activity as GSActivity; use App\Entity\Activity as GSActivity;
use App\Util\Exception\NotImplementedException; use App\Util\Exception\NotImplementedException;
use DateTime; use DateTime;

View File

@@ -33,10 +33,11 @@ declare(strict_types = 1);
namespace Plugin\ActivityPub\Util\Model; namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\DB\DB; use App\Core\DB;
use App\Entity\Activity as GSActivity; use App\Entity\Activity as GSActivity;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use Component\Subscription\Subscription; use Component\Subscription\Subscription;
use Component\Subscription\Subscription as SubscriptionComponent;
use DateTime; use DateTime;
use InvalidArgumentException; use InvalidArgumentException;
use Plugin\ActivityPub\Entity\ActivitypubActivity; use Plugin\ActivityPub\Entity\ActivitypubActivity;
@@ -63,6 +64,8 @@ class ActivityFollow extends Activity
if (\is_null($act)) { if (\is_null($act)) {
throw new ClientException('You are already subscribed to this actor.'); throw new ClientException('You are already subscribed to this actor.');
} }
SubscriptionComponent::refreshSubscriptionCount($actor, $subscribed);
// Store ActivityPub Activity // Store ActivityPub Activity
$ap_act = ActivitypubActivity::create([ $ap_act = ActivitypubActivity::create([
'activity_id' => $act->getId(), 'activity_id' => $act->getId(),

View File

@@ -34,12 +34,12 @@ namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\ActorLocalRoles; use App\Core\ActorLocalRoles;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Actor as GSActor; use App\Entity\Actor as GSActor;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use App\Util\TemporaryFile; use App\Util\TemporaryFile;
@@ -198,6 +198,7 @@ class Actor extends Model
} }
} }
Event::handle('ActivityPubCreateOrUpdateActor', [$object, &$actor, &$ap_actor]);
return $ap_actor; return $ap_actor;
} }

View File

@@ -35,13 +35,13 @@ namespace Plugin\ActivityPub\Util\Model;
use ActivityPhp\Type; use ActivityPhp\Type;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Core\VisibilityScope; use App\Core\VisibilityScope;
use App\Entity\Note as GSNote; use App\Entity\Note as GSNote;
use App\Util\Common; use App\Util\Common;
@@ -166,8 +166,9 @@ class Note extends Model
'reply_to' => $reply_to = $handleInReplyTo($type_note), 'reply_to' => $reply_to = $handleInReplyTo($type_note),
'modified' => new DateTime(), 'modified' => new DateTime(),
'type' => match ($type_note->get('type')) { 'type' => match ($type_note->get('type')) {
'Article' => 'article',
'Page' => 'page', 'Page' => 'page',
default => 'note' default => 'note' // graceful degradation
}, },
'source' => $source, 'source' => $source,
]; ];
@@ -361,7 +362,7 @@ class Note extends Model
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @throws ServerException * @throws ServerException
*/ */
public static function toJson(mixed $object, int $options = \JSON_UNESCAPED_SLASHES): string public static function toType(mixed $object): AbstractObject
{ {
if ($object::class !== GSNote::class) { if ($object::class !== GSNote::class) {
throw new InvalidArgumentException('First argument type must be a Note.'); throw new InvalidArgumentException('First argument type must be a Note.');
@@ -371,10 +372,12 @@ class Note extends Model
'@context' => ActivityPub::$activity_streams_two_context, '@context' => ActivityPub::$activity_streams_two_context,
'type' => $object->getScope() === VisibilityScope::MESSAGE ? 'ChatMessage' : (match ($object->getType()) { 'type' => $object->getScope() === VisibilityScope::MESSAGE ? 'ChatMessage' : (match ($object->getType()) {
'note' => 'Note', 'note' => 'Note',
'article' => 'Article',
'page' => 'Page', 'page' => 'Page',
default => throw new Exception('Unsupported note type.') default => throw new Exception('Unsupported note type.')
}), }),
'id' => $object->getUrl(), 'id' => $object->getUrl(),
'url' => $object->getUrl(),
'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339),
'attributedTo' => $object->getActor()->getUri(Router::ABSOLUTE_URL), 'attributedTo' => $object->getActor()->getUri(Router::ABSOLUTE_URL),
'name' => $object->getTitle(), 'name' => $object->getTitle(),
@@ -469,6 +472,6 @@ class Note extends Model
$type = self::jsonToType($attr); $type = self::jsonToType($attr);
Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]);
return $type->toJson($options); return $type;
} }
} }

View File

@@ -34,7 +34,7 @@ namespace Plugin\ActivityPub\Util;
use ActivityPhp\Type\Core\OrderedCollection; use ActivityPhp\Type\Core\OrderedCollection;
use ActivityPhp\Type\Core\OrderedCollectionPage; use ActivityPhp\Type\Core\OrderedCollectionPage;
use App\Core\Router\Router; use App\Core\Router;
use Component\Collection\Util\Controller\CircleController; use Component\Collection\Util\Controller\CircleController;
use Component\Collection\Util\Controller\FeedController; use Component\Collection\Util\Controller\FeedController;
use Component\Collection\Util\Controller\OrderedCollection as GSOrderedCollection; use Component\Collection\Util\Controller\OrderedCollection as GSOrderedCollection;

View File

@@ -31,12 +31,11 @@ declare(strict_types = 1);
namespace Plugin\AttachmentCollections; namespace Plugin\AttachmentCollections;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Core\Router\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Feed; use App\Entity\Feed;
use App\Entity\LocalUser; use App\Entity\LocalUser;
@@ -123,7 +122,7 @@ class AttachmentCollections extends Plugin
return array_map(fn ($x) => $x['attachment_collection_id'], $res); return array_map(fn ($x) => $x['attachment_collection_id'], $res);
} }
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
// View all collections by actor id and nickname // View all collections by actor id and nickname
$r->connect( $r->connect(

View File

@@ -23,8 +23,8 @@ declare(strict_types = 1);
namespace Plugin\AttachmentCollections\Controller; namespace Plugin\AttachmentCollections\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Router\Router; use App\Core\Router;
use Component\Collection\Util\Controller\MetaCollectionController; use Component\Collection\Util\Controller\MetaCollectionController;
use Plugin\AttachmentCollections\Entity\AttachmentCollection; use Plugin\AttachmentCollections\Entity\AttachmentCollection;

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Plugin\AttachmentShowRelated; namespace Plugin\AttachmentShowRelated;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Util\Common; use App\Util\Common;

View File

@@ -43,7 +43,7 @@ use SplFileInfo;
class AudioEncoder extends Plugin class AudioEncoder extends Plugin
{ {
public function version(): string public static function version(): string
{ {
return '0.1.0'; return '0.1.0';
} }

View File

@@ -20,18 +20,31 @@ declare(strict_types = 1);
// }}} // }}}
namespace Component\Blog; namespace Plugin\Blog;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Core\Router\RouteLoader; use App\Core\Router;
use Component\Blog\Controller as C; use App\Util\Common;
use App\Util\HTML;
use Plugin\Blog\Controller as C;
use function App\Core\I18n\_m;
class Blog extends Plugin class Blog extends Plugin
{ {
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect(id: 'blog_post', uri_path: '/blog/post', target: [C\Post::class, 'makePost']); $r->connect(id: 'blog_post', uri_path: '/blog/post', target: [C\Post::class, 'makePost']);
return Event::next; return Event::next;
} }
public function onAppendCardProfile(array $vars, array &$res): bool
{
$actor = Common::actor();
$group = $vars['actor'];
if (!\is_null($actor) && $group->isGroup()) {
$res[] = HTML::html(['a' => ['attrs' => ['href' => Router::url('blog_post', ['in' => $group->getId()]), 'title' => _m('Make a new blog post'), 'class' => 'profile-extra-actions'], _m('Post in blog')]]);
}
return Event::next;
}
} }

View File

@@ -21,7 +21,7 @@ declare(strict_types = 1);
// }}} // }}}
namespace Component\Blog\Controller; namespace Plugin\Blog\Controller;
use App\Core\ActorLocalRoles; use App\Core\ActorLocalRoles;
use App\Core\Controller; use App\Core\Controller;
@@ -139,7 +139,7 @@ class Post extends Controller
$extra_args = []; $extra_args = [];
Event::handle('AddExtraArgsToNoteContent', [$request, $actor, $data, &$extra_args, $form_params, $form]); Event::handle('AddExtraArgsToNoteContent', [$request, $actor, $data, &$extra_args, $form_params, $form]);
[,$note,] = Posting::storeLocalPage( [,$note,] = Posting::storeLocalArticle(
actor: $actor, actor: $actor,
content: $data['content'], content: $data['content'],
content_type: $content_type, content_type: $content_type,

View File

@@ -22,7 +22,7 @@ declare(strict_types = 1);
namespace Plugin\Bundles; namespace Plugin\Bundles;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Entity\Actor; use App\Entity\Actor;
use Component\Collection\Util\MetaCollectionTrait; use Component\Collection\Util\MetaCollectionTrait;

View File

@@ -23,8 +23,8 @@ declare(strict_types = 1);
namespace Plugin\Bundles\Controller; namespace Plugin\Bundles\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Router\Router; use App\Core\Router;
use Component\Collection\Util\Controller\MetaCollectionController; use Component\Collection\Util\Controller\MetaCollectionController;
use Plugin\Bundles\Entity\BundleCollection; use Plugin\Bundles\Entity\BundleCollection;

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Plugin\Cover\Controller; namespace Plugin\Cover\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;

View File

@@ -22,10 +22,10 @@ declare(strict_types = 1);
namespace Plugin\Cover; namespace Plugin\Cover;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Core\Router\RouteLoader; use App\Core\Router;
use App\Util\Common; use App\Util\Common;
use Plugin\Cover\Controller as C; use Plugin\Cover\Controller as C;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -47,7 +47,7 @@ class Cover extends Plugin
* *
* @return bool hook value; true means continue processing, false means stop * @return bool hook value; true means continue processing, false means stop
*/ */
public function onAddRoute(RouteLoader $r): bool public function onAddRoute(Router $r): bool
{ {
$r->connect('settings_profile_cover', 'settings/cover', [Controller\Cover::class, 'coversettings']); $r->connect('settings_profile_cover', 'settings/cover', [Controller\Cover::class, 'coversettings']);
$r->connect('cover', '/cover', [Controller\Cover::class, 'cover']); $r->connect('cover', '/cover', [Controller\Cover::class, 'cover']);

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Plugin\Cover\Entity; namespace Plugin\Cover\Entity;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Util\Common; use App\Util\Common;
use Component\Attachment\Entity\Attachment; use Component\Attachment\Entity\Attachment;

View File

@@ -24,11 +24,11 @@ declare(strict_types = 1);
namespace Plugin\DeleteNote\Controller; namespace Plugin\DeleteNote\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;

View File

@@ -23,12 +23,11 @@ namespace Plugin\DeleteNote;
use ActivityPhp\Type\AbstractObject; use ActivityPhp\Type\AbstractObject;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use function App\Core\I18n\_m; 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;
use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
@@ -47,7 +46,7 @@ use Symfony\Component\HttpFoundation\Request;
* @category DeleteNote * @category DeleteNote
* *
* @author Eliseu Amaro <mail@eliseuama.ro> * @author Eliseu Amaro <mail@eliseuama.ro>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021-2022 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
*/ */
class DeleteNote extends NoteHandlerPlugin class DeleteNote extends NoteHandlerPlugin
@@ -136,7 +135,7 @@ class DeleteNote extends NoteHandlerPlugin
* *
* @return bool Event hook * @return bool Event hook
*/ */
public function onAddRoute(RouteLoader $r) public function onAddRoute(Router $r)
{ {
$r->connect(id: 'delete_note_action', uri_path: '/object/note/{note_id<\d+>}/delete', target: Controller\DeleteNote::class); $r->connect(id: 'delete_note_action', uri_path: '/object/note/{note_id<\d+>}/delete', target: Controller\DeleteNote::class);

View File

@@ -23,7 +23,7 @@ declare(strict_types = 1);
namespace Plugin\Directory\Controller; namespace Plugin\Directory\Controller;
use App\Core\DB\DB; use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Entity\Actor; use App\Entity\Actor;
use App\Util\Common; use App\Util\Common;

Some files were not shown because too many files have changed in this diff Show More