2022-02-15 17:15:29 +00:00
< ? php
declare ( strict_types = 1 );
// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
// }}}
namespace Component\Blog\Controller ;
use App\Core\ActorLocalRoles ;
use App\Core\Controller ;
use App\Core\Event ;
use App\Core\Form ;
use function App\Core\I18n\_m ;
use App\Core\VisibilityScope ;
use App\Entity\Actor ;
use App\Util\Common ;
use App\Util\Exception\ClientException ;
use App\Util\Exception\RedirectException ;
use App\Util\Form\FormFields ;
use Component\Posting\Posting ;
2022-02-26 14:45:38 +00:00
use InvalidArgumentException ;
2022-02-15 17:15:29 +00:00
use Symfony\Component\Form\Extension\Core\Type\ChoiceType ;
use Symfony\Component\Form\Extension\Core\Type\FileType ;
use Symfony\Component\Form\Extension\Core\Type\SubmitType ;
use Symfony\Component\Form\Extension\Core\Type\TextareaType ;
2022-02-26 14:45:38 +00:00
use Symfony\Component\Form\Extension\Core\Type\TextType ;
2022-02-15 17:15:29 +00:00
use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException ;
2022-02-26 14:45:38 +00:00
use Symfony\Component\HttpFoundation\RedirectResponse ;
2022-02-15 17:15:29 +00:00
use Symfony\Component\HttpFoundation\Request ;
use Symfony\Component\Validator\Constraints\Length ;
class Post extends Controller
{
/**
* Creates and handles Blog post creation form
*
* @ throws \App\Util\Exception\DuplicateFoundException
* @ throws \App\Util\Exception\NoLoggedInUser
* @ throws \App\Util\Exception\ServerException
* @ throws ClientException
* @ throws RedirectException
*/
public function makePost ( Request $request )
{
$actor = Common :: ensureLoggedIn () -> getActor ();
$placeholder_strings = [ 'How are you feeling?' , 'Have something to share?' , 'How was your day?' ];
Event :: handle ( 'PostingPlaceHolderString' , [ & $placeholder_strings ]);
$placeholder = $placeholder_strings [ array_rand ( $placeholder_strings )];
$initial_content = '' ;
Event :: handle ( 'PostingInitialContent' , [ & $initial_content ]);
$available_content_types = [
_m ( 'Plain Text' ) => 'text/plain' ,
];
Event :: handle ( 'PostingAvailableContentTypes' , [ & $available_content_types ]);
2022-02-26 14:45:38 +00:00
if ( ! \is_int ( $this -> int ( 'in' ))) {
throw new InvalidArgumentException ( 'You must specify an In group/org.' );
2022-02-16 06:56:59 +00:00
}
2022-02-15 17:15:29 +00:00
$context_actor = Actor :: getById ( $this -> int ( 'in' ));
if ( ! $context_actor -> isGroup ()) {
2022-02-26 14:45:38 +00:00
throw new InvalidArgumentException ( 'Only group blog posts are supported for now.' );
2022-02-15 17:15:29 +00:00
}
2022-02-26 14:45:38 +00:00
$in_targets = [ " ! { $context_actor -> getNickname () } " => $context_actor -> getId ()];
2022-02-15 17:15:29 +00:00
$form_params [] = [ 'in' , ChoiceType :: class , [ 'label' => _m ( 'In:' ), 'multiple' => false , 'expanded' => false , 'choices' => $in_targets ]];
$visibility_options = [
_m ( 'Public' ) => VisibilityScope :: EVERYWHERE -> value ,
_m ( 'Local' ) => VisibilityScope :: LOCAL -> value ,
_m ( 'Addressee' ) => VisibilityScope :: ADDRESSEE -> value ,
];
2022-02-26 14:45:38 +00:00
if ( ! \is_null ( $context_actor ) && $context_actor -> isGroup ()) { // @phpstan-ignore-line currently an open bug. See https://web.archive.org/web/20220226131651/https://github.com/phpstan/phpstan/issues/6234
2022-02-15 17:15:29 +00:00
if ( $actor -> canModerate ( $context_actor )) {
if ( $context_actor -> getRoles () & ActorLocalRoles :: PRIVATE_GROUP ) {
$visibility_options = array_merge ([ _m ( 'Group' ) => VisibilityScope :: GROUP -> value ], $visibility_options );
} else {
$visibility_options [ _m ( 'Group' )] = VisibilityScope :: GROUP -> value ;
}
}
}
$form_params [] = [ 'visibility' , ChoiceType :: class , [ 'label' => _m ( 'Visibility:' ), 'multiple' => false , 'expanded' => false , 'choices' => $visibility_options ]];
2022-02-17 18:45:30 +00:00
$form_params [] = [ 'title' , TextType :: class , [ 'label' => _m ( 'Title:' ), 'constraints' => [ new Length ([ 'max' => 129 ])], 'required' => true ]];
2022-02-15 17:15:29 +00:00
$form_params [] = [ 'content' , TextareaType :: class , [ 'label' => _m ( 'Content:' ), 'data' => $initial_content , 'attr' => [ 'placeholder' => _m ( $placeholder )], 'constraints' => [ new Length ([ 'max' => Common :: config ( 'site' , 'text_limit' )])]]];
$form_params [] = [ 'attachments' , FileType :: class , [ 'label' => _m ( 'Attachments:' ), 'multiple' => true , 'required' => false , 'invalid_message' => _m ( 'Attachment not valid.' )]];
$form_params [] = FormFields :: language ( $actor , $context_actor , label : _m ( 'Note language' ), help : _m ( 'The selected language will be federated and added as a lang attribute, preferred language can be set up in settings' ));
if ( \count ( $available_content_types ) > 1 ) {
$form_params [] = [ 'content_type' , ChoiceType :: class ,
[
'label' => _m ( 'Text format:' ), 'multiple' => false , 'expanded' => false ,
'data' => $available_content_types [ array_key_first ( $available_content_types )],
'choices' => $available_content_types ,
],
];
}
Event :: handle ( 'PostingAddFormEntries' , [ $request , $actor , & $form_params ]);
$form_params [] = [ 'post_note' , SubmitType :: class , [ 'label' => _m ( 'Post' )]];
$form = Form :: create ( $form_params );
$form -> handleRequest ( $request );
if ( $form -> isSubmitted ()) {
try {
if ( $form -> isValid ()) {
$data = $form -> getData ();
Event :: handle ( 'PostingModifyData' , [ $request , $actor , & $data , $form_params , $form ]);
if ( empty ( $data [ 'content' ]) && empty ( $data [ 'attachments' ])) {
// TODO Display error: At least one of `content` and `attachments` must be provided
throw new ClientException ( _m ( 'You must enter content or provide at least one attachment to post a note.' ));
}
if ( \is_null ( VisibilityScope :: tryFrom ( $data [ 'visibility' ]))) {
throw new ClientException ( _m ( 'You have selected an impossible visibility.' ));
}
$content_type = $data [ 'content_type' ] ? ? $available_content_types [ array_key_first ( $available_content_types )];
$extra_args = [];
Event :: handle ( 'AddExtraArgsToNoteContent' , [ $request , $actor , $data , & $extra_args , $form_params , $form ]);
2022-02-16 19:35:27 +00:00
[, $note ,] = Posting :: storeLocalPage (
2022-02-15 17:15:29 +00:00
actor : $actor ,
content : $data [ 'content' ],
content_type : $content_type ,
locale : $data [ 'language' ],
scope : VisibilityScope :: from ( $data [ 'visibility' ]),
2022-03-13 18:23:19 +00:00
attentions : [( int ) $data [ 'in' ]],
2022-02-16 06:56:59 +00:00
reply_to : $data [ 'reply_to_id' ],
2022-02-15 17:15:29 +00:00
attachments : $data [ 'attachments' ],
process_note_content_extra_args : $extra_args ,
2022-02-17 18:45:30 +00:00
title : $data [ 'title' ],
2022-02-15 17:15:29 +00:00
);
2022-02-16 06:58:11 +00:00
return new RedirectResponse ( $note -> getConversationUrl ());
2022-02-15 17:15:29 +00:00
}
} catch ( FormSizeFileException $e ) {
throw new ClientException ( _m ( 'Invalid file size given' ), previous : $e );
}
}
return [
'_template' => 'blog/make_post.html.twig' ,
'blog_entry_form' => $form -> createView (),
];
}
}