newsModel = new NewsModel(); $this->auditLogModel = new AuditLogModel(); } /** * Display list of news */ public function index() { $perPage = 10; $page = $this->request->getGet('page') ?? 1; $status = $this->request->getGet('status'); $search = $this->request->getGet('search'); // Build query with filters $this->newsModel->select('news.*, users.username as creator_name') ->join('users', 'users.id = news.created_by', 'left'); // Filter by status if ($status && in_array($status, ['draft', 'published'])) { $this->newsModel->where('news.status', $status); } // Search if ($search) { $this->newsModel->groupStart() ->like('news.title', $search) ->orLike('news.content', $search) ->groupEnd(); } // Get paginated results $news = $this->newsModel->orderBy('news.created_at', 'DESC') ->paginate($perPage, 'default', $page); $pager = $this->newsModel->pager; $data = [ 'title' => 'Berita', 'news' => $news, 'pager' => $pager, 'currentStatus' => $status, 'currentSearch' => $search, 'stats' => [ 'total' => $this->newsModel->countByStatus(), 'published' => $this->newsModel->countByStatus('published'), 'draft' => $this->newsModel->countByStatus('draft'), ], ]; return view('admin/news/index', $data); } /** * Show form to create new news */ public function create() { $data = [ 'title' => 'Tambah Berita', 'news' => null, ]; return view('admin/news/form', $data); } /** * Store new news */ public function store() { $validation = \Config\Services::validation(); $rules = [ 'title' => 'required|min_length[3]|max_length[255]', 'content' => 'required', 'status' => 'required|in_list[draft,published]', ]; if (!$this->validate($rules)) { return redirect()->back() ->withInput() ->with('validation', $validation); } $title = $this->request->getPost('title'); $slug = $this->newsModel->generateSlug($title); $content = $this->request->getPost('content'); $contentHtml = $this->request->getPost('content_html'); $contentJson = $this->request->getPost('content_json'); $excerpt = $this->request->getPost('excerpt'); $status = $this->request->getPost('status'); $userId = session()->get('user_id'); // Use content_html if available, otherwise use content $finalContent = !empty($contentHtml) ? $contentHtml : $content; $data = [ 'title' => $title, 'slug' => $slug, 'content' => $finalContent, 'content_html' => $contentHtml, 'content_json' => $contentJson, 'excerpt' => $excerpt, 'status' => $status, 'created_by' => $userId, ]; // Set published_at if status is published if ($status === 'published') { $data['published_at'] = date('Y-m-d H:i:s'); } if ($this->newsModel->insert($data)) { // Log action $this->auditLogModel->logAction('news_created', $userId); return redirect()->to('/admin/news') ->with('success', 'Berita berhasil ditambahkan.'); } return redirect()->back() ->withInput() ->with('error', 'Gagal menambahkan berita.'); } /** * Show form to edit news */ public function edit($id) { $news = $this->newsModel->find($id); if (!$news) { return redirect()->to('/admin/news') ->with('error', 'Berita tidak ditemukan.'); } $data = [ 'title' => 'Edit Berita', 'news' => $news, ]; return view('admin/news/form', $data); } /** * Update news */ public function update($id) { $news = $this->newsModel->find($id); if (!$news) { return redirect()->to('/admin/news') ->with('error', 'Berita tidak ditemukan.'); } $validation = \Config\Services::validation(); $rules = [ 'title' => 'required|min_length[3]|max_length[255]', 'content' => 'required', 'status' => 'required|in_list[draft,published]', ]; if (!$this->validate($rules)) { return redirect()->back() ->withInput() ->with('validation', $validation); } $title = $this->request->getPost('title'); $oldTitle = $news['title']; $content = $this->request->getPost('content'); $contentHtml = $this->request->getPost('content_html'); $contentJson = $this->request->getPost('content_json'); $excerpt = $this->request->getPost('excerpt'); $status = $this->request->getPost('status'); $userId = session()->get('user_id'); // Use content_html if available, otherwise use content $finalContent = !empty($contentHtml) ? $contentHtml : $content; // Generate new slug if title changed $slug = ($title !== $oldTitle) ? $this->newsModel->generateSlug($title, $id) : $news['slug']; $data = [ 'title' => $title, 'slug' => $slug, 'content' => $finalContent, 'content_html' => $contentHtml, 'content_json' => $contentJson, 'excerpt' => $excerpt, 'status' => $status, ]; // Set published_at if status changed to published and wasn't published before if ($status === 'published' && empty($news['published_at'])) { $data['published_at'] = date('Y-m-d H:i:s'); } try { // Skip model validation karena sudah divalidasi di controller $this->newsModel->skipValidation(true); $result = $this->newsModel->update($id, $data); if ($result === false) { // Get validation errors if any $errors = $this->newsModel->errors(); $errorMessage = !empty($errors) ? implode(', ', $errors) : 'Gagal memperbarui berita.'; log_message('error', 'News update failed - ID: ' . $id . ', Errors: ' . json_encode($errors)); return redirect()->back() ->withInput() ->with('error', $errorMessage); } // Log action $this->auditLogModel->logAction('news_updated', $userId); return redirect()->to('/admin/news') ->with('success', 'Berita berhasil diperbarui.'); } catch (\Exception $e) { log_message('error', 'News update exception - ID: ' . $id . ', Error: ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString()); return redirect()->back() ->withInput() ->with('error', 'Terjadi kesalahan saat memperbarui berita: ' . $e->getMessage()); } } /** * Delete news */ public function delete($id) { $news = $this->newsModel->find($id); if (!$news) { return redirect()->to('/admin/news') ->with('error', 'Berita tidak ditemukan.'); } $userId = session()->get('user_id'); if ($this->newsModel->delete($id)) { // Log action $this->auditLogModel->logAction('news_deleted', $userId); return redirect()->to('/admin/news') ->with('success', 'Berita berhasil dihapus.'); } return redirect()->to('/admin/news') ->with('error', 'Gagal menghapus berita.'); } }