88 lines
2.6 KiB
PHP
88 lines
2.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\News;
|
|
|
|
use App\Services\ContentSanitizer;
|
|
use App\Models\NewsArticleComment;
|
|
use App\Models\User;
|
|
use Illuminate\Validation\ValidationException;
|
|
use cPad\Plugins\News\Models\NewsArticle;
|
|
|
|
final class NewsArticleCommentService
|
|
{
|
|
public function __construct(private readonly NewsService $news)
|
|
{
|
|
}
|
|
|
|
public function create(NewsArticle $article, User $actor, string $body, ?NewsArticleComment $parent = null): NewsArticleComment
|
|
{
|
|
if (! $article->commentsAreEnabled()) {
|
|
throw ValidationException::withMessages([
|
|
'body' => 'Comments are disabled for this article.',
|
|
]);
|
|
}
|
|
|
|
$trimmedBody = trim($body);
|
|
$errors = ContentSanitizer::validate($trimmedBody);
|
|
|
|
if ($errors !== []) {
|
|
throw ValidationException::withMessages([
|
|
'body' => $errors,
|
|
]);
|
|
}
|
|
|
|
$comment = NewsArticleComment::query()->create([
|
|
'article_id' => (int) $article->id,
|
|
'user_id' => (int) $actor->id,
|
|
'parent_id' => $parent?->id,
|
|
'author_name' => trim((string) ($actor->name ?: $actor->username)),
|
|
'body' => $trimmedBody,
|
|
'rendered_body' => ContentSanitizer::sanitizeRenderedHtml(
|
|
ContentSanitizer::render($trimmedBody),
|
|
$this->actorCanPublishLinks($actor)
|
|
),
|
|
'status' => 'visible',
|
|
]);
|
|
|
|
$this->news->invalidatePublicCache();
|
|
|
|
return $comment->fresh(['user.profile', 'replies.user.profile']);
|
|
}
|
|
|
|
public function delete(NewsArticleComment $comment, User $actor): void
|
|
{
|
|
$article = $comment->article()->with('author')->first();
|
|
|
|
if (! $article || ! $this->canDelete($comment, $article, $actor)) {
|
|
throw ValidationException::withMessages([
|
|
'comment' => 'You are not allowed to remove this comment.',
|
|
]);
|
|
}
|
|
|
|
if ($comment->trashed()) {
|
|
return;
|
|
}
|
|
|
|
$comment->delete();
|
|
|
|
$this->news->invalidatePublicCache();
|
|
}
|
|
|
|
private function canDelete(NewsArticleComment $comment, NewsArticle $article, User $actor): bool
|
|
{
|
|
return (int) $comment->user_id === (int) $actor->id
|
|
|| (int) $article->author_id === (int) $actor->id
|
|
|| $actor->isAdmin()
|
|
|| $actor->isModerator();
|
|
}
|
|
|
|
private function actorCanPublishLinks(User $actor): bool
|
|
{
|
|
$level = (int) ($actor->level ?? 1);
|
|
$rank = strtolower((string) ($actor->rank ?? 'Newbie'));
|
|
|
|
return $level > 1 && $rank !== 'newbie';
|
|
}
|
|
} |