with('quickReplies') ->latest() ->paginate($perPage); } public function create(string $title, string $content, ?string $note = null, array $allowedActions = []): Article { return Article::query()->create([ 'title' => trim($title), 'content' => trim($content), 'note' => $note !== null && trim($note) !== '' ? trim($note) : null, 'allowed_actions' => $this->sanitizeAllowedActions($allowedActions), 'status' => 'published', 'is_ai_draft' => false, ]); } public function deleteById(int $articleId): bool { return (bool) Article::query()->whereKey($articleId)->delete(); } public function updateMetadata(int $articleId, ?string $note, array $allowedActions, array $quickReplyIds = []): bool { $article = Article::query()->find($articleId); if ($article === null) { return false; } DB::transaction(function () use ($article, $note, $allowedActions, $quickReplyIds): void { $article->note = $note !== null && trim($note) !== '' ? trim($note) : null; $article->allowed_actions = $this->sanitizeAllowedActions($allowedActions); $article->save(); $article->quickReplies()->sync($this->existingQuickReplyIds($quickReplyIds)); }); return true; } public function approveDraft(int $articleId): bool { $article = Article::query()->find($articleId); if ($article === null) { return false; } $article->status = 'published'; $article->is_ai_draft = false; $article->save(); return true; } private function sanitizeAllowedActions(array $allowedActions): array { return array_values(array_intersect(array_unique($allowedActions), ['domain_inf'])); } private function existingQuickReplyIds(array $quickReplyIds): array { $ids = array_values(array_unique(array_filter( array_map(static fn ($id) => (int) $id, $quickReplyIds), static fn ($id) => $id > 0 ))); if ($ids === []) { return []; } return QuickReply::query() ->whereIn('id', $ids) ->pluck('id') ->map(static fn ($id) => (int) $id) ->all(); } }