2020-06-07 19:04:43 +03:00
< ? php declare ( strict_types = 1 );
namespace openvk\Web\Presenters ;
2022-10-11 18:39:45 +03:00
use openvk\Web\Models\Exceptions\TooMuchOptionsException ;
use openvk\Web\Models\Entities\ { Poll , Post , Photo , Video , Club , User };
2021-11-13 23:28:17 +03:00
use openvk\Web\Models\Entities\Notifications\ { RepostNotification , WallPostNotification };
2020-06-07 19:04:43 +03:00
use openvk\Web\Models\Repositories\ { Posts , Users , Clubs , Albums };
use Chandler\Database\DatabaseConnection ;
use Nette\InvalidStateException as ISE ;
2022-02-05 17:50:24 +03:00
use Bhaktaraz\RSSGenerator\Item ;
use Bhaktaraz\RSSGenerator\Feed ;
use Bhaktaraz\RSSGenerator\Channel ;
2020-06-07 19:04:43 +03:00
final class WallPresenter extends OpenVKPresenter
{
private $posts ;
function __construct ( Posts $posts )
{
$this -> posts = $posts ;
parent :: __construct ();
}
private function logPostView ( Post $post , int $wall ) : void
{
if ( is_null ( $this -> user ))
return ;
$this -> logEvent ( " postView " , [
" profile " => $this -> user -> identity -> getId (),
" post " => $post -> getId (),
" owner " => abs ( $wall ),
" group " => $wall < 0 ,
" subscribed " => $wall < 0 ? $post -> getOwner () -> getSubscriptionStatus ( $this -> user -> identity ) : false ,
]);
}
private function logPostsViewed ( array & $posts , int $wall ) : void
{
$x = array_values ( $posts ); # clone array (otherwise Nette DB objects will become kinda gay)
foreach ( $x as $post )
$this -> logPostView ( $post , $wall );
}
2021-09-15 21:00:34 +03:00
function renderWall ( int $user , bool $embedded = false ) : void
2020-06-07 19:04:43 +03:00
{
if ( false )
2022-02-09 22:36:41 +03:00
exit ( tr ( " forbidden " ) . " : " . ( string ) random_int ( 0 , 255 ));
2020-06-07 19:04:43 +03:00
$owner = ( $user < 0 ? ( new Clubs ) : ( new Users )) -> get ( abs ( $user ));
2021-11-04 20:01:09 +03:00
if ( is_null ( $this -> user )) {
2020-06-07 19:04:43 +03:00
$canPost = false ;
2021-11-04 20:01:09 +03:00
} else if ( $user > 0 ) {
2021-11-04 16:15:58 +03:00
if ( ! $owner -> isBanned ())
$canPost = $owner -> getPrivacyPermission ( " wall.write " , $this -> user -> identity );
else
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " error " ), tr ( " forbidden " ));
2022-02-05 17:50:24 +03:00
} else if ( $user < 0 ) {
2020-06-11 23:18:05 +03:00
if ( $owner -> canBeModifiedBy ( $this -> user -> identity ))
2020-06-07 19:04:43 +03:00
$canPost = true ;
2020-06-11 23:18:05 +03:00
else
$canPost = $owner -> canPost ();
2021-11-04 20:01:09 +03:00
} else {
$canPost = false ;
2022-02-05 17:50:24 +03:00
}
2020-06-07 19:04:43 +03:00
2021-09-15 21:00:34 +03:00
if ( $embedded == true ) $this -> template -> _template = " components/wall.xml " ;
2020-06-07 19:04:43 +03:00
$this -> template -> oObj = $owner ;
$this -> template -> owner = $user ;
$this -> template -> canPost = $canPost ;
$this -> template -> count = $this -> posts -> getPostCountOnUserWall ( $user );
$this -> template -> posts = iterator_to_array ( $this -> posts -> getPostsFromUsersWall ( $user , ( int ) ( $_GET [ " p " ] ? ? 1 )));
$this -> template -> paginatorConf = ( object ) [
" count " => $this -> template -> count ,
" page " => ( int ) ( $_GET [ " p " ] ? ? 1 ),
" amount " => sizeof ( $this -> template -> posts ),
" perPage " => OPENVK_DEFAULT_PER_PAGE ,
];
2021-09-15 21:00:34 +03:00
2020-06-07 19:04:43 +03:00
$this -> logPostsViewed ( $this -> template -> posts , $user );
}
2021-09-15 21:00:34 +03:00
function renderWallEmbedded ( int $user ) : void
{
$this -> renderWall ( $user , true );
}
2022-02-05 17:50:24 +03:00
function renderRSS ( int $user ) : void
{
if ( false )
2022-02-09 22:36:41 +03:00
exit ( tr ( " forbidden " ) . " : " . ( string ) random_int ( 0 , 255 ));
2022-02-05 17:50:24 +03:00
$owner = ( $user < 0 ? ( new Clubs ) : ( new Users )) -> get ( abs ( $user ));
if ( is_null ( $this -> user )) {
$canPost = false ;
} else if ( $user > 0 ) {
if ( ! $owner -> isBanned ())
$canPost = $owner -> getPrivacyPermission ( " wall.write " , $this -> user -> identity );
else
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " error " ), tr ( " forbidden " ));
2022-02-05 17:50:24 +03:00
} else if ( $user < 0 ) {
if ( $owner -> canBeModifiedBy ( $this -> user -> identity ))
$canPost = true ;
else
$canPost = $owner -> canPost ();
} else {
$canPost = false ;
}
$posts = iterator_to_array ( $this -> posts -> getPostsFromUsersWall ( $user ));
$feed = new Feed ();
$channel = new Channel ();
2022-08-28 14:01:31 +03:00
$channel -> title ( $owner -> getCanonicalName () . " — " . OPENVK_ROOT_CONF [ 'openvk' ][ 'appearance' ][ 'name' ]) -> url ( ovk_scheme ( true ) . $_SERVER [ " HTTP_HOST " ]) -> appendTo ( $feed );
2022-02-05 17:50:24 +03:00
foreach ( $posts as $post ) {
$item = new Item ();
$item
-> title ( $post -> getOwner () -> getCanonicalName ())
-> description ( $post -> getText ())
2022-08-28 14:01:31 +03:00
-> url ( ovk_scheme ( true ) . $_SERVER [ " HTTP_HOST " ] . " /wall { $post -> getPrettyId () } " )
2022-02-05 17:50:24 +03:00
-> pubDate ( $post -> getPublicationTime () -> timestamp ())
-> appendTo ( $channel );
}
header ( " Content-Type: application/rss+xml " );
exit ( $feed );
}
2020-06-07 19:04:43 +03:00
function renderFeed () : void
{
$this -> assertUserLoggedIn ();
$id = $this -> user -> id ;
$subs = DatabaseConnection :: i ()
-> getContext ()
-> table ( " subscriptions " )
-> where ( " follower " , $id );
$ids = array_map ( function ( $rel ) {
return $rel -> target * ( $rel -> model === " openvk \ Web \ Models \ Entities \ User " ? 1 : - 1 );
}, iterator_to_array ( $subs ));
$ids [] = $this -> user -> id ;
2020-08-25 18:44:06 +03:00
$perPage = min (( int ) ( $_GET [ " posts " ] ? ? OPENVK_DEFAULT_PER_PAGE ), 50 );
2020-06-07 19:04:43 +03:00
$posts = DatabaseConnection :: i ()
-> getContext ()
-> table ( " posts " )
-> select ( " id " )
-> where ( " wall IN (?) " , $ids )
-> where ( " deleted " , 0 )
-> order ( " created DESC " );
$this -> template -> paginatorConf = ( object ) [
" count " => sizeof ( $posts ),
" page " => ( int ) ( $_GET [ " p " ] ? ? 1 ),
" amount " => sizeof ( $posts -> page (( int ) ( $_GET [ " p " ] ? ? 1 ), $perPage )),
" perPage " => $perPage ,
];
$this -> template -> posts = [];
foreach ( $posts -> page (( int ) ( $_GET [ " p " ] ? ? 1 ), $perPage ) as $post )
$this -> template -> posts [] = $this -> posts -> get ( $post -> id );
2020-06-11 12:51:12 +03:00
}
function renderGlobalFeed () : void
{
$this -> assertUserLoggedIn ();
$page = ( int ) ( $_GET [ " p " ] ? ? 1 );
2020-08-25 18:44:06 +03:00
$pPage = min (( int ) ( $_GET [ " posts " ] ? ? OPENVK_DEFAULT_PER_PAGE ), 50 );
2022-01-02 01:52:35 +03:00
$queryBase = " FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0 " ;
2021-01-07 19:19:36 +03:00
if ( $this -> user -> identity -> getNsfwTolerance () === User :: NSFW_INTOLERANT )
2022-01-02 01:52:35 +03:00
$queryBase .= " AND `nsfw` = 0 " ;
$posts = DatabaseConnection :: i () -> getConnection () -> query ( " SELECT `posts`.`id` " . $queryBase . " ORDER BY `created` DESC LIMIT " . $pPage . " OFFSET " . ( $page - 1 ) * $pPage );
$count = DatabaseConnection :: i () -> getConnection () -> query ( " SELECT COUNT(*) " . $queryBase ) -> fetch () -> { " COUNT(*) " };
2021-01-07 19:19:36 +03:00
2020-06-11 12:51:12 +03:00
$this -> template -> _template = " Wall/Feed.xml " ;
$this -> template -> globalFeed = true ;
$this -> template -> paginatorConf = ( object ) [
2022-01-02 01:52:35 +03:00
" count " => $count ,
2020-06-11 12:51:12 +03:00
" page " => ( int ) ( $_GET [ " p " ] ? ? 1 ),
2022-01-02 01:52:35 +03:00
" amount " => sizeof ( $posts ),
2020-06-11 12:51:12 +03:00
" perPage " => $pPage ,
];
2022-01-02 01:52:35 +03:00
foreach ( $posts as $post )
2020-06-11 12:51:12 +03:00
$this -> template -> posts [] = $this -> posts -> get ( $post -> id );
2020-06-07 19:04:43 +03:00
}
function renderHashtagFeed ( string $hashtag ) : void
{
$hashtag = rawurldecode ( $hashtag );
$page = ( int ) ( $_GET [ " p " ] ? ? 1 );
$posts = $this -> posts -> getPostsByHashtag ( $hashtag , $page );
$count = $this -> posts -> getPostCountByHashtag ( $hashtag );
$this -> template -> hashtag = $hashtag ;
$this -> template -> posts = $posts ;
$this -> template -> paginatorConf = ( object ) [
" count " => 0 ,
" page " => $page ,
" amount " => $count ,
" perPage " => OPENVK_DEFAULT_PER_PAGE ,
];
}
function renderMakePost ( int $wall ) : void
{
$this -> assertUserLoggedIn ();
2021-01-01 00:18:53 +03:00
$this -> willExecuteWriteAction ();
2020-06-07 19:04:43 +03:00
$wallOwner = ( $wall > 0 ? ( new Users ) -> get ( $wall ) : ( new Clubs ) -> get ( $wall * - 1 ))
2022-02-09 22:36:41 +03:00
? ? $this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " error_4 " ));
2021-11-04 20:01:09 +03:00
if ( $wall > 0 ) {
2021-11-04 16:15:58 +03:00
if ( ! $wallOwner -> isBanned ())
$canPost = $wallOwner -> getPrivacyPermission ( " wall.write " , $this -> user -> identity );
else
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " not_enough_permissions " ), tr ( " not_enough_permissions_comment " ));
2021-11-04 20:01:09 +03:00
} else if ( $wall < 0 ) {
2020-06-07 19:04:43 +03:00
if ( $wallOwner -> canBeModifiedBy ( $this -> user -> identity ))
$canPost = true ;
2020-06-11 23:18:05 +03:00
else
$canPost = $wallOwner -> canPost ();
2021-11-04 20:01:09 +03:00
} else {
2020-06-07 19:04:43 +03:00
$canPost = false ;
2021-11-04 20:01:09 +03:00
}
2020-06-07 19:04:43 +03:00
if ( ! $canPost )
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " not_enough_permissions " ), tr ( " not_enough_permissions_comment " ));
2021-11-17 10:43:55 +03:00
$anon = OPENVK_ROOT_CONF [ " openvk " ][ " preferences " ][ " wall " ][ " anonymousPosting " ][ " enable " ];
if ( $wallOwner instanceof Club && $this -> postParam ( " as_group " ) === " on " && $this -> postParam ( " force_sign " ) !== " on " && $anon ) {
$manager = $wallOwner -> getManager ( $this -> user -> identity );
if ( $manager )
$anon = $manager -> isHidden ();
elseif ( $this -> user -> identity -> getId () === $wallOwner -> getOwner () -> getId ())
$anon = $wallOwner -> isOwnerHidden ();
} else {
$anon = $anon && $this -> postParam ( " anon " ) === " on " ;
}
2021-11-15 22:45:48 +03:00
2020-06-07 19:04:43 +03:00
$flags = 0 ;
2021-12-15 20:19:13 +03:00
if ( $this -> postParam ( " as_group " ) === " on " && $wallOwner instanceof Club && $wallOwner -> canBeModifiedBy ( $this -> user -> identity ))
2020-06-07 19:04:43 +03:00
$flags |= 0 b10000000 ;
if ( $this -> postParam ( " force_sign " ) === " on " )
$flags |= 0 b01000000 ;
2021-10-13 22:51:28 +03:00
try {
$photo = NULL ;
$video = NULL ;
if ( $_FILES [ " _pic_attachment " ][ " error " ] === UPLOAD_ERR_OK ) {
2021-10-12 14:17:21 +03:00
$album = NULL ;
2021-11-15 22:45:48 +03:00
if ( ! $anon && $wall > 0 && $wall === $this -> user -> id )
2021-10-12 14:17:21 +03:00
$album = ( new Albums ) -> getUserWallAlbum ( $wallOwner );
2020-06-07 19:04:43 +03:00
2021-11-15 22:45:48 +03:00
$photo = Photo :: fastMake ( $this -> user -> id , $this -> postParam ( " text " ), $_FILES [ " _pic_attachment " ], $album , $anon );
2020-06-07 19:04:43 +03:00
}
2022-10-11 18:39:45 +03:00
if ( $_FILES [ " _vid_attachment " ][ " error " ] === UPLOAD_ERR_OK )
2021-11-15 22:45:48 +03:00
$video = Video :: fastMake ( $this -> user -> id , $this -> postParam ( " text " ), $_FILES [ " _vid_attachment " ], $anon );
2021-10-15 12:34:59 +03:00
} catch ( \DomainException $ex ) {
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " media_file_corrupted " ));
2021-10-13 22:51:28 +03:00
} catch ( ISE $ex ) {
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " media_file_corrupted_or_too_large " ));
2020-06-07 19:04:43 +03:00
}
2022-10-11 18:39:45 +03:00
try {
$poll = NULL ;
$xml = $this -> postParam ( " poll " );
if ( ! is_null ( $xml ) && $xml != " none " )
$poll = Poll :: import ( $this -> user -> identity , $xml );
} catch ( TooMuchOptionsException $e ) {
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " poll_err_to_much_options " ));
} catch ( \UnexpectedValueException $e ) {
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), " Poll format invalid " );
}
if ( empty ( $this -> postParam ( " text " )) && ! $photo && ! $video && ! $poll )
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " post_is_empty_or_too_big " ));
2021-10-13 22:51:28 +03:00
2021-11-20 01:46:51 +03:00
try {
$post = new Post ;
$post -> setOwner ( $this -> user -> id );
$post -> setWall ( $wall );
$post -> setCreated ( time ());
$post -> setContent ( $this -> postParam ( " text " ));
$post -> setAnonymous ( $anon );
$post -> setFlags ( $flags );
$post -> setNsfw ( $this -> postParam ( " nsfw " ) === " on " );
$post -> save ();
} catch ( \LengthException $ex ) {
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " failed_to_publish_post " ), tr ( " post_is_too_big " ));
2021-11-20 01:46:51 +03:00
}
2021-10-13 22:51:28 +03:00
if ( ! is_null ( $photo ))
$post -> attach ( $photo );
if ( ! is_null ( $video ))
$post -> attach ( $video );
2022-10-11 18:39:45 +03:00
if ( ! is_null ( $poll ))
$post -> attach ( $poll );
2020-06-07 19:04:43 +03:00
if ( $wall > 0 && $wall !== $this -> user -> identity -> getId ())
( new WallPostNotification ( $wallOwner , $post , $this -> user -> identity )) -> emit ();
2022-08-09 08:52:36 +03:00
$this -> redirect ( $wallOwner -> getURL ());
2020-06-07 19:04:43 +03:00
}
function renderPost ( int $wall , int $post_id ) : void
{
$post = $this -> posts -> getPostById ( $wall , $post_id );
if ( ! $post || $post -> isDeleted ())
$this -> notFound ();
$this -> logPostView ( $post , $wall );
$this -> template -> post = $post ;
2021-11-04 16:15:58 +03:00
if ( $post -> getTargetWall () > 0 ) {
2021-09-17 20:46:32 +03:00
$this -> template -> wallOwner = ( new Users ) -> get ( $post -> getTargetWall ());
$this -> template -> isWallOfGroup = false ;
2021-11-04 16:15:58 +03:00
if ( $this -> template -> wallOwner -> isBanned ())
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " error " ), tr ( " forbidden " ));
2021-09-17 20:46:32 +03:00
} else {
$this -> template -> wallOwner = ( new Clubs ) -> get ( abs ( $post -> getTargetWall ()));
$this -> template -> isWallOfGroup = true ;
}
2020-06-07 19:04:43 +03:00
$this -> template -> cCount = $post -> getCommentsCount ();
$this -> template -> cPage = ( int ) ( $_GET [ " p " ] ? ? 1 );
$this -> template -> comments = iterator_to_array ( $post -> getComments ( $this -> template -> cPage ));
}
function renderLike ( int $wall , int $post_id ) : void
{
$this -> assertUserLoggedIn ();
2021-01-01 00:18:53 +03:00
$this -> willExecuteWriteAction ();
2020-06-07 19:04:43 +03:00
$this -> assertNoCSRF ();
$post = $this -> posts -> getPostById ( $wall , $post_id );
if ( ! $post || $post -> isDeleted ()) $this -> notFound ();
if ( ! is_null ( $this -> user )) {
$post -> toggleLike ( $this -> user -> identity );
}
2022-08-09 08:52:36 +03:00
$this -> redirect ( " $_SERVER[HTTP_REFERER] #postGarter= " . $post -> getId ());
2020-06-07 19:04:43 +03:00
}
function renderShare ( int $wall , int $post_id ) : void
{
$this -> assertUserLoggedIn ();
2021-01-01 00:18:53 +03:00
$this -> willExecuteWriteAction ();
2020-06-07 19:04:43 +03:00
$this -> assertNoCSRF ();
$post = $this -> posts -> getPostById ( $wall , $post_id );
if ( ! $post || $post -> isDeleted ()) $this -> notFound ();
if ( ! is_null ( $this -> user )) {
$nPost = new Post ;
$nPost -> setOwner ( $this -> user -> id );
$nPost -> setWall ( $this -> user -> id );
2021-10-08 20:44:57 +03:00
$nPost -> setContent ( $this -> postParam ( " text " ));
2020-06-07 19:04:43 +03:00
$nPost -> save ();
$nPost -> attach ( $post );
if ( $post -> getOwner ( false ) -> getId () !== $this -> user -> identity -> getId () && ! ( $post -> getOwner () instanceof Club ))
( new RepostNotification ( $post -> getOwner ( false ), $post , $this -> user -> identity )) -> emit ();
};
2021-12-25 19:03:21 +03:00
$this -> returnJson ([ " wall_owner " => $this -> user -> identity -> getId ()]);
2020-06-07 19:04:43 +03:00
}
function renderDelete ( int $wall , int $post_id ) : void
{
$this -> assertUserLoggedIn ();
2021-01-01 00:18:53 +03:00
$this -> willExecuteWriteAction ();
2020-06-07 19:04:43 +03:00
$post = $this -> posts -> getPostById ( $wall , $post_id );
if ( ! $post )
$this -> notFound ();
$user = $this -> user -> id ;
2020-06-18 14:22:32 +03:00
$wallOwner = ( $wall > 0 ? ( new Users ) -> get ( $wall ) : ( new Clubs ) -> get ( $wall * - 1 ))
2022-02-09 22:36:41 +03:00
? ? $this -> flashFail ( " err " , tr ( " failed_to_delete_post " ), tr ( " error_4 " ));
2020-06-18 14:22:32 +03:00
if ( $wall < 0 ) $canBeDeletedByOtherUser = $wallOwner -> canBeModifiedBy ( $this -> user -> identity );
else $canBeDeletedByOtherUser = false ;
2020-06-07 19:04:43 +03:00
if ( ! is_null ( $user )) {
2020-06-18 14:22:32 +03:00
if ( $post -> getOwnerPost () == $user || $post -> getTargetWall () == $user || $canBeDeletedByOtherUser ) {
2020-06-07 19:04:43 +03:00
$post -> unwire ();
2020-06-23 23:06:15 +03:00
$post -> delete ();
2020-06-07 19:04:43 +03:00
}
} else {
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " failed_to_delete_post " ), tr ( " login_required_error_comment " ));
2020-06-07 19:04:43 +03:00
}
2022-08-09 08:52:36 +03:00
$this -> redirect ( $wall < 0 ? " /club " . ( $wall *- 1 ) : " /id " . $wall );
2020-06-07 19:04:43 +03:00
}
2021-09-20 15:19:15 +03:00
function renderPin ( int $wall , int $post_id ) : void
{
$this -> assertUserLoggedIn ();
$this -> willExecuteWriteAction ();
$post = $this -> posts -> getPostById ( $wall , $post_id );
if ( ! $post )
$this -> notFound ();
2021-09-20 16:46:55 +03:00
if ( ! $post -> canBePinnedBy ( $this -> user -> identity ))
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " err " , tr ( " not_enough_permissions " ), tr ( " not_enough_permissions_comment " ));
2021-09-20 15:19:15 +03:00
if (( $this -> queryParam ( " act " ) ? ? " pin " ) === " pin " ) {
$post -> pin ();
} else {
$post -> unpin ();
}
2022-05-08 13:06:26 +03:00
# TODO localize message based on language and ?act=(un)pin
2022-02-09 22:36:41 +03:00
$this -> flashFail ( " succ " , tr ( " information_-1 " ), tr ( " changes_saved_comment " ));
2021-09-20 15:19:15 +03:00
}
2020-06-07 19:04:43 +03:00
}