From 7c465bba5f42de75ab98e5e7011948a487b7eef8 Mon Sep 17 00:00:00 2001 From: Diogo Peralta Cordeiro Date: Thu, 9 Sep 2021 03:46:30 +0100 Subject: [PATCH] [NOTE] Add mimetype to notes --- components/Posting/Posting.php | 41 +++++++++++++++++++----------- plugins/Reply/Controller/Reply.php | 21 +++++++-------- src/Entity/Note.php | 37 +++++++++++++++++---------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/components/Posting/Posting.php b/components/Posting/Posting.php index e6df45ae46..69369456f4 100644 --- a/components/Posting/Posting.php +++ b/components/Posting/Posting.php @@ -73,20 +73,30 @@ class Posting extends Component Event::handle('PostingPlaceHolderString', [&$placeholder_strings]); $placeholder = $placeholder_strings[array_rand($placeholder_strings)]; - $request = $vars['request']; - $form = Form::create([ - ['content', TextareaType::class, ['label' => ' ', 'data' => '', 'attr' => ['placeholder' => _m($placeholder)]]], - ['attachments', FileType::class, ['label' => ' ', 'data' => null, 'multiple' => true, 'required' => false]], - ['visibility', ChoiceType::class, ['label' => _m('Visibility:'), 'multiple' => false, 'expanded' => false, 'data' => 'public', 'choices' => [_m('Public') => 'public', _m('Instance') => 'instance', _m('Private') => 'private']]], - ['to', ChoiceType::class, ['label' => _m('To:'), 'multiple' => false, 'expanded' => false, 'choices' => $to_tags]], - ['post_note', SubmitType::class, ['label' => _m('Post')]], - ]); + $initial_content = ''; + Event::handle('PostingInitialContent', [&$initial_content]); + + $content_type = ['Plain Text' => 'text/plain']; + Event::handle('PostingAvailableContentTypes', [&$content_type]); + + $request = $vars['request']; + $form_params = [ + ['content', TextareaType::class, ['label' => _m('Content') . ':', 'data' => $initial_content, 'attr' => ['placeholder' => _m($placeholder)]]], + ['attachments', FileType::class, ['label' => _m('Attachments') . ':', 'data' => null, 'multiple' => true, 'required' => false]], + ['visibility', ChoiceType::class, ['label' => _m('Visibility') . ':', 'multiple' => false, 'expanded' => false, 'data' => 'public', 'choices' => [_m('Public') => 'public', _m('Instance') => 'instance', _m('Private') => 'private']]], + ['to', ChoiceType::class, ['label' => _m('To') . ':', 'multiple' => false, 'expanded' => false, 'choices' => $to_tags]], + ]; + if (count($content_type) > 1) { + $form_params[] = ['content_type', ChoiceType::class, ['label' => _m('Text format') . ':', 'multiple' => false, 'expanded' => false, 'data' => 'text/plain', 'choices' => $content_type]]; + } + $form_params[] = ['post_note', SubmitType::class, ['label' => _m('Post')]]; + $form = Form::create($form_params); $form->handleRequest($request); if ($form->isSubmitted()) { $data = $form->getData(); if ($form->isValid()) { - self::storeNote($actor_id, $data['content'], $data['attachments'], is_local: true); + self::storeNote($actor_id, $data['content_type'] ?? array_key_first($content_type), $data['content'], $data['attachments'], is_local: true); throw new RedirectException(); } else { throw new InvalidFormException(); @@ -106,14 +116,15 @@ class Posting extends Component * @throws DuplicateFoundException * @throws ClientException|ServerException */ - public static function storeNote(int $actor_id, ?string $content, array $attachments, bool $is_local, ?int $reply_to = null, ?int $repeat_of = null) + public static function storeNote(int $actor_id, string $content_type, string $content, array $attachments, bool $is_local, ?int $reply_to = null, ?int $repeat_of = null) { $note = Note::create([ - 'gsactor_id' => $actor_id, - 'content' => $content, - 'is_local' => $is_local, - 'reply_to' => $reply_to, - 'repeat_of' => $repeat_of, + 'gsactor_id' => $actor_id, + 'content_type' => $content_type, + 'content' => $content, + 'is_local' => $is_local, + 'reply_to' => $reply_to, + 'repeat_of' => $repeat_of, ]); $processed_attachments = []; diff --git a/plugins/Reply/Controller/Reply.php b/plugins/Reply/Controller/Reply.php index 13c742ca4a..a23f54ba2a 100644 --- a/plugins/Reply/Controller/Reply.php +++ b/plugins/Reply/Controller/Reply.php @@ -59,10 +59,10 @@ class Reply extends Controller $form = Form::create([ ['content', TextareaType::class, [ - 'label' => _m('Reply'), - 'label_attr' => ['class' => 'section-form-label'], - 'help' => _m('Please input your reply.'), - ] + 'label' => _m('Reply'), + 'label_attr' => ['class' => 'section-form-label'], + 'help' => _m('Please input your reply.'), + ], ], ['attachments', FileType::class, ['label' => ' ', 'multiple' => true, 'required' => false]], ['replyform', SubmitType::class, ['label' => _m('Submit')]], @@ -74,12 +74,13 @@ class Reply extends Controller $data = $form->getData(); if ($form->isValid()) { Posting::storeNote( - $actor_id, - $data['content'], - $data['attachments'], - $is_local = true, - $reply_to, - $repeat_of = null + actor_id: $actor_id, + content_type: 'text/plain', + content: $data['content'], + attachments: $data['attachments'], + is_local: true, + reply_to: $reply_to, + repeat_of: null ); $return = $this->string('return_to'); if (!is_null($return)) { diff --git a/src/Entity/Note.php b/src/Entity/Note.php index 803b9306f5..e5a5a7affd 100644 --- a/src/Entity/Note.php +++ b/src/Entity/Note.php @@ -38,20 +38,21 @@ use DateTimeInterface; * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ -class Note extends Entity implements \JsonSerializable +class Note extends Entity { // {{{ Autocode // @codeCoverageIgnoreStart private int $id; private int $gsactor_id; - private ?string $content; - private ?string $rendered; + private string $content_type = 'text/plain'; + private string $content; + private string $rendered; private ?int $reply_to; private ?bool $is_local; private ?string $source; private ?int $conversation; private ?int $repeat_of; - private int $scope = 1; + private int $scope = VisibilityScope::PUBLIC; private \DateTimeInterface $created; private \DateTimeInterface $modified; @@ -77,6 +78,23 @@ class Note extends Entity implements \JsonSerializable return $this->gsactor_id; } + /** + * @return string + */ + public function getContentType(): string + { + return $this->content_type; + } + + /** + * @param string $content_type + */ + public function setContentType(string $content_type): self + { + $this->content_type = $content_type; + return $this; + } + public function setContent(?string $content): self { $this->content = $content; @@ -272,14 +290,6 @@ class Note extends Entity implements \JsonSerializable ['note_id' => $this->id, 'actor_id' => $a->getId()])); } - public function jsonSerialize() - { - return [ - 'content' => $this->getContent(), - 'author' => $this->getGSActorId(), - ]; - } - public static function schemaDef(): array { return [ @@ -287,7 +297,8 @@ class Note extends Entity implements \JsonSerializable 'fields' => [ 'id' => ['type' => 'serial', 'not null' => true], 'gsactor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'GSActor.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'who made the note'], - 'content' => ['type' => 'text', 'description' => 'note content'], + 'content' => ['type' => 'text', 'not null' => true, 'description' => 'note content'], + 'content_type' => ['type' => 'varchar', 'not null' => true, 'default' => 'text/plain', 'length' => 129, 'description' => 'A note can be written in a multitude of formats such as text/plain, text/markdown, application/x-latex, and text/html'], 'rendered' => ['type' => 'text', 'description' => 'rendered note content, so we can keep the microtags (if not local)'], 'reply_to' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'note replied to, null if root of a conversation'], 'is_local' => ['type' => 'bool', 'description' => 'was this note generated by a local actor'],