Group.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. declare(strict_types = 1);
  3. // {{{ License
  4. // This file is part of GNU social - https://www.gnu.org/software/social
  5. //
  6. // GNU social is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // GNU social is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
  18. // }}}
  19. namespace Component\Group;
  20. use App\Core\Event;
  21. use function App\Core\I18n\_m;
  22. use App\Core\Modules\Component;
  23. use App\Core\Router\RouteLoader;
  24. use App\Core\Router\Router;
  25. use App\Entity\Activity;
  26. use App\Entity\Actor;
  27. use App\Util\Common;
  28. use App\Util\HTML;
  29. use App\Util\Nickname;
  30. use Component\Group\Controller as C;
  31. use Component\Group\Entity\LocalGroup;
  32. use Component\Notification\Notification;
  33. use Symfony\Component\HttpFoundation\Request;
  34. class Group extends Component
  35. {
  36. public function onAddRoute(RouteLoader $r): bool
  37. {
  38. $r->connect(id: 'group_actor_view_id', uri_path: '/group/{id<\d+>}', target: [C\GroupFeed::class, 'groupViewId']);
  39. $r->connect(id: 'group_actor_view_nickname', uri_path: '/!{nickname<' . Nickname::DISPLAY_FMT . '>}', target: [C\GroupFeed::class, 'groupViewNickname']);
  40. $r->connect(id: 'group_create', uri_path: '/group/new', target: [C\Group::class, 'groupCreate']);
  41. $r->connect(id: 'group_actor_settings', uri_path: '/group/{id<\d+>}/settings', target: [C\Group::class, 'groupSettings']);
  42. return Event::next;
  43. }
  44. /**
  45. * Enqueues a notification for an Actor (such as person or group) which means
  46. * it shows up in their home feed and such.
  47. */
  48. public function onNewNotificationStart(Actor $sender, Activity $activity, array $targets = [], ?string $reason = null): bool
  49. {
  50. foreach ($targets as $target) {
  51. if ($target->isGroup()) {
  52. // The Group announces to its subscribers
  53. Notification::notify(
  54. sender: $target,
  55. activity: $activity,
  56. targets: $target->getSubscribers(),
  57. reason: $reason,
  58. );
  59. }
  60. }
  61. return Event::next;
  62. }
  63. /**
  64. * Add an <a href=group_actor_settings> to the profile card for groups, if the current actor can access them
  65. */
  66. public function onAppendCardProfile(array $vars, array &$res): bool
  67. {
  68. $actor = Common::actor();
  69. $group = $vars['actor'];
  70. if (!\is_null($actor) && $group->isGroup()) {
  71. if ($actor->canModerate($group)) {
  72. $url = Router::url('group_actor_settings', ['id' => $group->getId()]);
  73. $res[] = HTML::html(['a' => ['attrs' => ['href' => $url, 'title' => _m('Edit group settings'), 'class' => 'profile-extra-actions'], _m('Group settings')]]);
  74. }
  75. $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')]]);
  76. }
  77. return Event::next;
  78. }
  79. /**
  80. * If in a group route, get the current group
  81. */
  82. private function getGroupFromContext(Request $request): ?Actor
  83. {
  84. if (\is_array($request->get('post_note')) && \array_key_exists('_next', $request->get('post_note'))) {
  85. $next = parse_url($request->get('post_note')['_next']);
  86. $match = Router::match($next['path']);
  87. $route = $match['_route'];
  88. $identifier = $match['id'] ?? $match['nickname'] ?? null;
  89. } else {
  90. $route = $request->get('_route');
  91. $identifier = $request->get('id') ?? $request->get('nickname');
  92. }
  93. if (str_starts_with($route, 'group_actor_view_')) {
  94. switch ($route) {
  95. case 'group_actor_view_nickname':
  96. return LocalGroup::getActorByNickname($identifier);
  97. case 'group_actor_view_id':
  98. return Actor::getById($identifier);
  99. }
  100. }
  101. return null;
  102. }
  103. public function onPostingFillTargetChoices(Request $request, Actor $actor, array &$targets): bool
  104. {
  105. $group = $this->getGroupFromContext($request);
  106. if (!\is_null($group)) {
  107. $nick = "!{$group->getNickname()}";
  108. $targets[$nick] = $group->getId();
  109. }
  110. return Event::next;
  111. }
  112. /**
  113. * Indicates the context in which Posting's form is to be presented. Passing on $context_actor to Posting's
  114. * onAppendRightPostingBlock event, the Group a given $actor is currently browsing.
  115. *
  116. * Makes it possible to automagically fill in the targets (aka the Group which this $request route is connected to)
  117. * in the Posting's form.
  118. *
  119. * @param null|Actor $context_actor Actor group, if current route is part of an existing Group set of routes
  120. */
  121. public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor &$context_actor): bool
  122. {
  123. $ctx = $this->getGroupFromContext($request);
  124. if (!\is_null($ctx)) {
  125. $context_actor = $ctx;
  126. return Event::stop;
  127. }
  128. return Event::next;
  129. }
  130. }