CommentPolicy.php 4.31 KB
<?php

namespace FootyRoom\Core\Comment;

use Carbon\Carbon;
use FootyRoom\User\User;
use FootyRoom\Queries\Ban\Ban;
use FootyRoom\Core\AuthException;
use FootyRoom\Core\CoreException;
use FootyRoom\Queries\Ban\ActiveBanQuery;
use FootyRoom\Queries\Ban\BanQueryHandler;
use FootyRoom\Queries\Comment\CommentQueryHandler;
use FootyRoom\Queries\Comment\CommentsInPeriodQuery;

class CommentPolicy
{
    /**
     * \FootyRoom\Queries\Ban\BanQueryHandler.
     */
    protected $banQueryHandler;

    /**
     * \FootyRoom\Queries\Comment\CommentQueryHandler.
     */
    protected $commentQueryHandler;

    /**
     * Constructor.
     *
     * @param \FootyRoom\Queries\Ban\BanQueryHandler $banQueryHandler
     * @param \FootyRoom\Queries\Comment\CommentQueryHandler $commentQueryHandler
     */
    public function __construct(
        BanQueryHandler $banQueryHandler,
        CommentQueryHandler $commentQueryHandler
    ) {
        $this->banQueryHandler = $banQueryHandler;
        $this->commentQueryHandler = $commentQueryHandler;
    }

    /**
     * Determine if user can comment in a discussion.
     *
     * @param \FootyRoom\User\User $user
     * @param bool $throw
     *
     * @return bool
     */
    public function canComment(User $user, $throw = false)
    {
        // Make sure user is not permanently baned.
        if ($user->isBanned()) {
            if ($throw) {
                throw new CoreException('Your account is permanently banned.');
            }
            
            return false;
        }

        $ban = $this->banQueryHandler->findActiveBan(
            new ActiveBanQuery('user_id', $user->getUserId(), 'comment')
        );

        if ($throw && $ban) {
            $this->throwBannedException($ban);
        }

        if ($ban) {
            return false;
        }

        if ($user->getStatus() === 'newborn') {
            // Count comments in last 24 hours.
            $count = $this->commentQueryHandler->commentsInPeriod(
                new CommentsInPeriodQuery(60 * 60 * 24, $user->getUserId())
            );

            if ($throw && $count >= 5) {
                throw new CoreException('New members can comment/post 5 times per day. You have already made 5 comments/posts today. Please wait until tomorrow.');
            }

            if ($count >= 5) {
                return false;
            }
        }

        return true;
    }

    /**
     * Decides whether user can moderate comments.
     *
     * @param \FootyRoom\User\User $user
     * @param bool $throw
     *
     * @return bool
     */
    public static function canModerate(User $user, $throw = false)
    {
        if ($user->getRole() >= 20) {
            return true;
        }

        if ($throw) {
            throw new AuthException();
        }

        return false;
    }

    /**
     * Checks whether user can edit specific comment.
     */
    public function canEdit(User $user, int $commentUserId, string $discussionId, $throw = false): bool
    {
        if ($commentUserId === $user->getUserId()) {
            return true;
        }

        if (substr($discussionId, 0, 5) !== 'wall:' && $user->getRole() >= 20) {
            return true;
        }

        if ($throw) {
            throw new AuthException();
        }

        return false;
    }

    /**
     * Throws exception that says that user has been banned from commenting.
     *
     * @param \FootyRoom\Queries\Ban\Ban $ban (description)
     *
     * @throws \FootyRoom\Core\CoreException
     */
    protected function throwBannedException(Ban $ban)
    {
        throw new CoreException(
            'You are banned from commenting. Your ban will be lifted in '
            .Carbon::instance($ban->getCreatedAt())
                ->addSeconds($ban->getDuration())
                ->diffForHumans(Carbon::now(), true)
            .'.'
        );
    }

    /**
     * Returns which meta fields are visible to for specific user role.
     *
     * @param int $userRole
     *
     * @return array
     */
    public static function getVisibleMeta($userRole)
    {
        return $userRole >= 25 ? ['edited'] : ['edited'];
    }

    /**
     * Determine if specific user role can see unpublished comments.
     *
     * @param int $userRole
     *
     * @return bool
     */
    public static function seeUnpublished($userRole)
    {
        return $userRole >= 25 ? true : false;
    }
}