diff --git a/components/Posting/Posting.php b/components/Posting/Posting.php index db51381096..b5c96ff0b2 100644 --- a/components/Posting/Posting.php +++ b/components/Posting/Posting.php @@ -34,9 +34,6 @@ use App\Core\Router\Router; use App\Core\Security; use App\Entity\Activity; use App\Entity\Actor; -use Component\Attachment\Entity\ActorToAttachment; -use Component\Attachment\Entity\Attachment; -use Component\Attachment\Entity\AttachmentToNote; use App\Entity\Language; use App\Entity\Note; use App\Util\Common; @@ -46,6 +43,9 @@ use App\Util\Exception\RedirectException; use App\Util\Exception\ServerException; use App\Util\Form\FormFields; use App\Util\Formatting; +use Component\Attachment\Entity\ActorToAttachment; +use Component\Attachment\Entity\Attachment; +use Component\Attachment\Entity\AttachmentToNote; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -113,6 +113,9 @@ class Posting extends Component ], ]; } + + Event::handle('PostingAddFormEntries', [$request, $actor, &$form_params]); + $form_params[] = ['post_note', SubmitType::class, ['label' => _m('Post')]]; $form = Form::create($form_params); @@ -122,7 +125,16 @@ class Posting extends Component if ($form->isValid()) { $data = $form->getData(); $content_type = $data['content_type'] ?? $available_content_types[array_key_first($available_content_types)]; - self::storeLocalNote($user->getActor(), $data['content'], $content_type, $data['language'], $data['attachments']); + $extra_args = []; + Event::handle('PostingHandleForm', [$request, $actor, $data, &$extra_args, $form_params, $form]); + self::storeLocalNote( + $user->getActor(), + $data['content'], + $content_type, + $data['language'], + $data['attachments'], + process_note_content_extra_args: $extra_args, + ); throw new RedirectException(); } } catch (FormSizeFileException $sizeFileException) { @@ -142,8 +154,9 @@ class Posting extends Component * $actor_id, possibly as a reply to note $reply_to and with flag * $is_local. Sanitizes $content and $attachments * - * @param array $attachments Array of UploadedFile to be stored as GSFiles associated to this note - * @param array $processed_attachments Array of [Attachment, Attachment's name] to be associated to this $actor and Note + * @param array $attachments Array of UploadedFile to be stored as GSFiles associated to this note + * @param array $processed_attachments Array of [Attachment, Attachment's name] to be associated to this $actor and Note + * @param array $process_note_content_extra_args Extra arguments for the event ProcessNoteContent * * @throws \App\Util\Exception\DuplicateFoundException * @throws ClientException @@ -151,8 +164,15 @@ class Posting extends Component * * @return \App\Core\Entity|mixed */ - public static function storeLocalNote(Actor $actor, string $content, string $content_type, string $language, array $attachments = [], $processed_attachments = []) - { + public static function storeLocalNote( + Actor $actor, + string $content, + string $content_type, + string $language, + array $attachments = [], + array $processed_attachments = [], + array $process_note_content_extra_args = [], + ) { $rendered = null; $mentions = []; Event::handle('RenderNoteContent', [$content, $content_type, &$rendered, $actor, $language, &$mentions]); @@ -181,7 +201,7 @@ class Posting extends Component // Need file and note ids for the next step $note->setUrl(Router::url('note_view', ['id' => $note->getId()], Router::ABSOLUTE_URL)); - Event::handle('ProcessNoteContent', [$note, $content, $content_type]); + Event::handle('ProcessNoteContent', [$note, $content, $content_type, $process_note_content_extra_args]); if ($processed_attachments !== []) { foreach ($processed_attachments as [$a, $fname]) { diff --git a/components/Tag/Tag.php b/components/Tag/Tag.php index 1e81042733..6771f2e095 100644 --- a/components/Tag/Tag.php +++ b/components/Tag/Tag.php @@ -26,8 +26,10 @@ namespace Component\Tag; use App\Core\Cache; use App\Core\DB\DB; use App\Core\Event; +use function App\Core\I18n\_m; use App\Core\Modules\Component; use App\Core\Router\Router; +use App\Entity\Actor; use App\Entity\Language; use App\Entity\Note; use App\Entity\NoteTag; @@ -36,6 +38,8 @@ use App\Util\HTML; use Doctrine\Common\Collections\ExpressionBuilder; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\HttpFoundation\Request; /** * Component responsible for extracting tags from posted notes, as well as normalizing them @@ -62,15 +66,20 @@ class Tag extends Component /** * Process note by extracting any tags present */ - public function onProcessNoteContent(Note $note, string $content): bool + public function onProcessNoteContent(Note $note, string $content, string $content_type, array $extra_args): bool { $matched_tags = []; $processed_tags = false; preg_match_all(self::TAG_REGEX, $content, $matched_tags, \PREG_SET_ORDER); foreach ($matched_tags as $match) { - $tag = str_replace('#', '', self::ensureLength($match[2])); + $tag = self::ensureValid($match[2]); $canonical_tag = self::canonicalTag($tag, Language::getFromId($note->getLanguageId())->getLocale()); - DB::persist(NoteTag::create(['tag' => $tag, 'canonical' => $canonical_tag, 'note_id' => $note->getId()])); + DB::persist(NoteTag::create([ + 'tag' => $tag, + 'canonical' => $canonical_tag, + 'note_id' => $note->getId(), + 'use_canonical' => $extra_args['tag_use_canonical'], + ])); Cache::pushList("tag-{$canonical_tag}", $note); $processed_tags = true; } @@ -94,6 +103,11 @@ class Tag extends Component return HTML::html(['a' => ['attrs' => ['href' => $url, 'title' => $tag, 'rel' => 'tag'], $tag]], options: ['indent' => false]); } + public static function ensureValid(string $tag) + { + return self::ensureLength(str_replace('#', '', $tag)); + } + public static function ensureLength(string $tag): string { return mb_substr($tag, 0, self::MAX_TAG_LENGTH); @@ -147,4 +161,19 @@ class Tag extends Component $actor_qb->join('App\Entity\ActorTag', 'actor_tag', Expr\Join::WITH, 'actor_tag.tagger = actor.id'); return Event::next; } + + public function onPostingAddFormEntries(Request $request, Actor $actor, array &$form_params) + { + $form_params[] = ['tag_use_canonical', CheckboxType::class, ['required' => false, 'data' => true, 'label' => _m('Make note tags canonical')]]; + return Event::next; + } + + public function onPostingHandleForm(Request $request, Actor $actor, array $data, array &$extra_args) + { + if (!isset($data['tag_use_canonical'])) { + throw new ClientException; + } + $extra_args['tag_use_canonical'] = $data['tag_use_canonical']; + return Event::next; + } }