. // }}} namespace Component\Group; use App\Core\Event; use function App\Core\I18n\_m; use App\Core\Modules\Component; use App\Core\Router\RouteLoader; use App\Core\Router\Router; use App\Entity\Activity; use App\Entity\Actor; use App\Util\Common; use App\Util\HTML; use App\Util\Nickname; use Component\Group\Controller as C; use Component\Group\Entity\LocalGroup; use Component\Notification\Notification; use Symfony\Component\HttpFoundation\Request; class Group extends Component { public function onAddRoute(RouteLoader $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_nickname', uri_path: '/!{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GroupFeed::class, 'groupViewNickname']); $r->connect(id: 'group_create', uri_path: '/group/new', target: [C\Group::class, 'groupCreate']); $r->connect(id: 'group_actor_settings', uri_path: '/group/{id<\d+>}/settings', target: [C\Group::class, 'groupSettings']); return Event::next; } /** * Enqueues a notification for an Actor (such as person or group) which means * it shows up in their home feed and such. */ public function onNewNotificationStart(Actor $sender, Activity $activity, array $targets = [], ?string $reason = null): bool { foreach ($targets as $target) { if ($target->isGroup()) { // The Group announces to its subscribers Notification::notify( sender: $target, activity: $activity, targets: $target->getSubscribers(), reason: $reason, ); } } return Event::next; } /** * Add an to the profile card for groups, if the current actor can access them */ public function onAppendCardProfile(array $vars, array &$res): bool { $actor = Common::actor(); $group = $vars['actor']; if (!\is_null($actor) && $group->isGroup()) { if ($actor->canModerate($group)) { $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' => 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; } /** * If in a group route, get the current group */ private function getGroupFromContext(Request $request): ?Actor { if (\is_array($request->get('post_note')) && \array_key_exists('_next', $request->get('post_note'))) { $next = parse_url($request->get('post_note')['_next']); $match = Router::match($next['path']); $route = $match['_route']; $identifier = $match['id'] ?? $match['nickname'] ?? null; } else { $route = $request->get('_route'); $identifier = $request->get('id') ?? $request->get('nickname'); } if (str_starts_with($route, 'group_actor_view_')) { switch ($route) { case 'group_actor_view_nickname': return LocalGroup::getActorByNickname($identifier); case 'group_actor_view_id': return Actor::getById((int) $identifier); } } return null; } public function onPostingFillTargetChoices(Request $request, Actor $actor, array &$targets): bool { $group = $this->getGroupFromContext($request); if (!\is_null($group)) { $nick = "!{$group->getNickname()}"; $targets[$nick] = $group->getId(); } return Event::next; } /** * Indicates the context in which Posting's form is to be presented. Passing on $context_actor to Posting's * onAppendRightPostingBlock event, the Group a given $actor is currently browsing. * * Makes it possible to automagically fill in the targets (aka the Group which this $request route is connected to) * in the Posting's form. * * @param null|Actor $context_actor Actor group, if current route is part of an existing Group set of routes */ public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor &$context_actor): bool { $ctx = $this->getGroupFromContext($request); if (!\is_null($ctx)) { $context_actor = $ctx; return Event::stop; } return Event::next; } }