Initial commit - CMS Gov Bapenda Garut dengan EditorJS
This commit is contained in:
94
app/Controllers/Admin/AuditLogs.php
Normal file
94
app/Controllers/Admin/AuditLogs.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\AuditLogModel;
|
||||
use App\Models\UserModel;
|
||||
|
||||
class AuditLogs extends BaseController
|
||||
{
|
||||
protected $auditLogModel;
|
||||
protected $userModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->auditLogModel = new AuditLogModel();
|
||||
$this->userModel = new UserModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display audit logs with pagination
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Check if user is admin
|
||||
if (session()->get('role') !== 'admin') {
|
||||
return redirect()->to('/admin/dashboard')
|
||||
->with('error', 'Anda tidak memiliki akses ke halaman ini.');
|
||||
}
|
||||
|
||||
// Get search query
|
||||
$search = $this->request->getGet('search');
|
||||
$actionFilter = $this->request->getGet('action');
|
||||
$userFilter = $this->request->getGet('user');
|
||||
|
||||
// Build query
|
||||
$this->auditLogModel->select('audit_logs.*, users.username, users.email')
|
||||
->join('users', 'users.id = audit_logs.user_id', 'left')
|
||||
->orderBy('audit_logs.created_at', 'DESC');
|
||||
|
||||
// Apply search filter
|
||||
if (!empty($search)) {
|
||||
$this->auditLogModel->groupStart()
|
||||
->like('audit_logs.action', $search)
|
||||
->orLike('users.username', $search)
|
||||
->orLike('users.email', $search)
|
||||
->orLike('audit_logs.ip_address', $search)
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
// Apply action filter
|
||||
if (!empty($actionFilter)) {
|
||||
$this->auditLogModel->where('audit_logs.action', $actionFilter);
|
||||
}
|
||||
|
||||
// Apply user filter
|
||||
if (!empty($userFilter)) {
|
||||
$this->auditLogModel->where('audit_logs.user_id', $userFilter);
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
$perPage = 20;
|
||||
$page = (int) ($this->request->getGet('page') ?? 1);
|
||||
$auditLogs = $this->auditLogModel->paginate($perPage, 'default', $page);
|
||||
$pager = $this->auditLogModel->pager;
|
||||
$total = $pager->getTotal();
|
||||
|
||||
// Get unique actions for filter dropdown
|
||||
$actions = $this->auditLogModel->select('action')
|
||||
->distinct()
|
||||
->orderBy('action', 'ASC')
|
||||
->findAll();
|
||||
|
||||
// Get users for filter dropdown
|
||||
$users = $this->userModel->select('id, username, email')
|
||||
->orderBy('username', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$data = [
|
||||
'title' => 'Audit Log',
|
||||
'auditLogs' => $auditLogs,
|
||||
'pager' => $pager,
|
||||
'search' => $search,
|
||||
'actionFilter' => $actionFilter,
|
||||
'userFilter' => $userFilter,
|
||||
'actions' => $actions,
|
||||
'users' => $users,
|
||||
'total' => $total,
|
||||
];
|
||||
|
||||
return view('admin/audit-logs/index', $data);
|
||||
}
|
||||
}
|
||||
|
||||
71
app/Controllers/Admin/Dashboard.php
Normal file
71
app/Controllers/Admin/Dashboard.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\NewsModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\AuditLogModel;
|
||||
|
||||
class Dashboard extends BaseController
|
||||
{
|
||||
protected $newsModel;
|
||||
protected $userModel;
|
||||
protected $auditLogModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->newsModel = new NewsModel();
|
||||
$this->userModel = new UserModel();
|
||||
$this->auditLogModel = new AuditLogModel();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// Get news statistics
|
||||
$totalNews = $this->newsModel->countByStatus();
|
||||
$publishedNews = $this->newsModel->countByStatus('published');
|
||||
$draftNews = $this->newsModel->countByStatus('draft');
|
||||
|
||||
// Get pages statistics (query directly since no PageModel)
|
||||
$db = \Config\Database::connect();
|
||||
$totalPages = $db->table('pages')->countAllResults();
|
||||
$publishedPages = $db->table('pages')->where('status', 'published')->countAllResults();
|
||||
$draftPages = $db->table('pages')->where('status', 'draft')->countAllResults();
|
||||
|
||||
// Get users statistics
|
||||
$totalUsers = $this->userModel->countAllResults();
|
||||
$activeUsers = $this->userModel->where('is_active', 1)->countAllResults();
|
||||
|
||||
// Get recent audit logs (limit 10)
|
||||
$recentAuditLogs = $this->auditLogModel->select('audit_logs.*, users.username')
|
||||
->join('users', 'users.id = audit_logs.user_id', 'left')
|
||||
->orderBy('audit_logs.created_at', 'DESC')
|
||||
->limit(10)
|
||||
->findAll();
|
||||
|
||||
$data = [
|
||||
'title' => 'Dashboard',
|
||||
'stats' => [
|
||||
'news' => [
|
||||
'total' => $totalNews,
|
||||
'published' => $publishedNews,
|
||||
'draft' => $draftNews,
|
||||
],
|
||||
'pages' => [
|
||||
'total' => $totalPages,
|
||||
'published' => $publishedPages,
|
||||
'draft' => $draftPages,
|
||||
],
|
||||
'users' => [
|
||||
'total' => $totalUsers,
|
||||
'active' => $activeUsers,
|
||||
],
|
||||
],
|
||||
'recentAuditLogs' => $recentAuditLogs,
|
||||
];
|
||||
|
||||
return view('admin/dashboard', $data);
|
||||
}
|
||||
}
|
||||
|
||||
281
app/Controllers/Admin/News.php
Normal file
281
app/Controllers/Admin/News.php
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\NewsModel;
|
||||
use App\Models\AuditLogModel;
|
||||
|
||||
class News extends BaseController
|
||||
{
|
||||
protected $newsModel;
|
||||
protected $auditLogModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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.');
|
||||
}
|
||||
}
|
||||
|
||||
442
app/Controllers/Admin/Pages.php
Normal file
442
app/Controllers/Admin/Pages.php
Normal file
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\PageModel;
|
||||
use App\Models\AuditLogModel;
|
||||
use App\Services\ContentRenderer;
|
||||
|
||||
class Pages extends BaseController
|
||||
{
|
||||
protected $pageModel;
|
||||
protected $auditLogModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->pageModel = new PageModel();
|
||||
$this->auditLogModel = new AuditLogModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display list of pages
|
||||
*/
|
||||
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->pageModel->select('pages.*');
|
||||
|
||||
// Filter by status
|
||||
if ($status && in_array($status, ['draft', 'published'])) {
|
||||
$this->pageModel->where('pages.status', $status);
|
||||
}
|
||||
|
||||
// Search
|
||||
if ($search) {
|
||||
$this->pageModel->groupStart()
|
||||
->like('pages.title', $search)
|
||||
->orLike('pages.content_html', $search)
|
||||
->orLike('pages.excerpt', $search)
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
$pages = $this->pageModel->orderBy('pages.created_at', 'DESC')
|
||||
->paginate($perPage, 'default', $page);
|
||||
|
||||
$pager = $this->pageModel->pager;
|
||||
|
||||
$data = [
|
||||
'title' => 'Halaman',
|
||||
'pages' => $pages,
|
||||
'pager' => $pager,
|
||||
'currentStatus' => $status,
|
||||
'currentSearch' => $search,
|
||||
'stats' => [
|
||||
'total' => $this->pageModel->countByStatus(),
|
||||
'published' => $this->pageModel->countByStatus('published'),
|
||||
'draft' => $this->pageModel->countByStatus('draft'),
|
||||
],
|
||||
];
|
||||
|
||||
return view('admin/pages/index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to create new page
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data = [
|
||||
'title' => 'Tambah Halaman',
|
||||
'page' => null,
|
||||
];
|
||||
|
||||
return view('admin/pages/form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store new page
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'title' => 'required|min_length[3]|max_length[255]',
|
||||
'content_json' => 'permit_empty',
|
||||
'status' => 'required|in_list[draft,published]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('validation', $validation);
|
||||
}
|
||||
|
||||
$title = $this->request->getPost('title');
|
||||
$slug = $this->pageModel->generateSlug($title);
|
||||
$contentJson = $this->request->getPost('content_json') ?? '{}';
|
||||
$contentHtml = $this->request->getPost('content_html') ?? '';
|
||||
$excerpt = $this->request->getPost('excerpt') ?? '';
|
||||
$featuredImage = $this->request->getPost('featured_image') ?? null;
|
||||
$status = $this->request->getPost('status');
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
// Validate and parse JSON
|
||||
$blocks = [];
|
||||
if (!empty($contentJson)) {
|
||||
$parsed = json_decode($contentJson, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && isset($parsed['blocks'])) {
|
||||
$blocks = $parsed['blocks'];
|
||||
}
|
||||
}
|
||||
|
||||
// Render HTML from JSON if not provided
|
||||
if (empty($contentHtml) && !empty($blocks)) {
|
||||
$contentHtml = ContentRenderer::renderEditorJsToHtml($blocks);
|
||||
}
|
||||
|
||||
// Sanitize HTML
|
||||
$contentHtml = $this->sanitizeHtml($contentHtml);
|
||||
|
||||
// Extract excerpt if empty
|
||||
if (empty($excerpt) && !empty($blocks)) {
|
||||
$excerpt = ContentRenderer::extractExcerpt($blocks);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'title' => $title,
|
||||
'slug' => $slug,
|
||||
'content' => $contentHtml, // Keep for backward compatibility
|
||||
'content_json' => $contentJson,
|
||||
'content_html' => $contentHtml,
|
||||
'excerpt' => $excerpt,
|
||||
'featured_image' => $featuredImage,
|
||||
'status' => $status,
|
||||
];
|
||||
|
||||
if ($this->pageModel->insert($data)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('page_created', $userId);
|
||||
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('success', 'Halaman berhasil ditambahkan.');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Gagal menambahkan halaman.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to edit page
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$page = $this->pageModel->find($id);
|
||||
|
||||
if (!$page) {
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('error', 'Halaman tidak ditemukan.');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'title' => 'Edit Halaman',
|
||||
'page' => $page,
|
||||
];
|
||||
|
||||
return view('admin/pages/form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update page
|
||||
*/
|
||||
public function update($id)
|
||||
{
|
||||
$page = $this->pageModel->find($id);
|
||||
|
||||
if (!$page) {
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('error', 'Halaman tidak ditemukan.');
|
||||
}
|
||||
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'title' => 'required|min_length[3]|max_length[255]',
|
||||
'content_json' => 'permit_empty',
|
||||
'status' => 'required|in_list[draft,published]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('validation', $validation);
|
||||
}
|
||||
|
||||
$title = $this->request->getPost('title');
|
||||
$oldTitle = $page['title'];
|
||||
$contentJson = $this->request->getPost('content_json') ?? '{}';
|
||||
$contentHtml = $this->request->getPost('content_html') ?? '';
|
||||
$excerpt = $this->request->getPost('excerpt') ?? '';
|
||||
$featuredImage = $this->request->getPost('featured_image') ?? null;
|
||||
$status = $this->request->getPost('status');
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
// Validate and parse JSON
|
||||
$blocks = [];
|
||||
if (!empty($contentJson)) {
|
||||
$parsed = json_decode($contentJson, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && isset($parsed['blocks'])) {
|
||||
$blocks = $parsed['blocks'];
|
||||
}
|
||||
}
|
||||
|
||||
// Render HTML from JSON if not provided
|
||||
if (empty($contentHtml) && !empty($blocks)) {
|
||||
$contentHtml = ContentRenderer::renderEditorJsToHtml($blocks);
|
||||
}
|
||||
|
||||
// Sanitize HTML
|
||||
$contentHtml = $this->sanitizeHtml($contentHtml);
|
||||
|
||||
// Extract excerpt if empty
|
||||
if (empty($excerpt) && !empty($blocks)) {
|
||||
$excerpt = ContentRenderer::extractExcerpt($blocks);
|
||||
}
|
||||
|
||||
// Generate new slug if title changed
|
||||
$slug = ($title !== $oldTitle)
|
||||
? $this->pageModel->generateSlug($title, $id)
|
||||
: $page['slug'];
|
||||
|
||||
$data = [
|
||||
'title' => $title,
|
||||
'slug' => $slug,
|
||||
'content' => $contentHtml, // Keep for backward compatibility
|
||||
'content_json' => $contentJson,
|
||||
'content_html' => $contentHtml,
|
||||
'excerpt' => $excerpt,
|
||||
'featured_image' => $featuredImage,
|
||||
'status' => $status,
|
||||
];
|
||||
|
||||
try {
|
||||
$this->pageModel->skipValidation(true);
|
||||
|
||||
$result = $this->pageModel->update($id, $data);
|
||||
|
||||
if ($result === false) {
|
||||
$errors = $this->pageModel->errors();
|
||||
$errorMessage = !empty($errors)
|
||||
? implode(', ', $errors)
|
||||
: 'Gagal memperbarui halaman.';
|
||||
|
||||
log_message('error', 'Page update failed - ID: ' . $id . ', Errors: ' . json_encode($errors));
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', $errorMessage);
|
||||
}
|
||||
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('page_updated', $userId);
|
||||
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('success', 'Halaman berhasil diperbarui.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Page update exception - ID: ' . $id . ', Error: ' . $e->getMessage());
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Terjadi kesalahan saat memperbarui halaman: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autosave page (AJAX)
|
||||
*/
|
||||
public function autosave($id)
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['success' => false, 'message' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$page = $this->pageModel->find($id);
|
||||
if (!$page) {
|
||||
return $this->response->setJSON(['success' => false, 'message' => 'Page not found']);
|
||||
}
|
||||
|
||||
$contentJson = $this->request->getPost('content_json') ?? '{}';
|
||||
$contentHtml = $this->request->getPost('content_html') ?? '';
|
||||
|
||||
// Validate JSON
|
||||
$blocks = [];
|
||||
if (!empty($contentJson)) {
|
||||
$parsed = json_decode($contentJson, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && isset($parsed['blocks'])) {
|
||||
$blocks = $parsed['blocks'];
|
||||
}
|
||||
}
|
||||
|
||||
// Render HTML if not provided
|
||||
if (empty($contentHtml) && !empty($blocks)) {
|
||||
$contentHtml = ContentRenderer::renderEditorJsToHtml($blocks);
|
||||
}
|
||||
|
||||
// Sanitize HTML
|
||||
$contentHtml = $this->sanitizeHtml($contentHtml);
|
||||
|
||||
// Extract excerpt
|
||||
$excerpt = '';
|
||||
if (!empty($blocks)) {
|
||||
$excerpt = ContentRenderer::extractExcerpt($blocks);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'content_json' => $contentJson,
|
||||
'content_html' => $contentHtml,
|
||||
'excerpt' => $excerpt,
|
||||
];
|
||||
|
||||
try {
|
||||
$this->pageModel->skipValidation(true);
|
||||
$this->pageModel->update($id, $data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => 'Autosaved',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Autosave failed - ID: ' . $id . ', Error: ' . $e->getMessage());
|
||||
return $this->response->setJSON(['success' => false, 'message' => 'Autosave failed']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload image (AJAX)
|
||||
*/
|
||||
public function upload()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['success' => 0, 'message' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$file = $this->request->getFile('image');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->response->setJSON(['success' => 0, 'message' => 'No file uploaded']);
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
|
||||
if (!in_array($file->getMimeType(), $allowedTypes)) {
|
||||
return $this->response->setJSON(['success' => 0, 'message' => 'Invalid file type. Only JPG, PNG, and WebP are allowed.']);
|
||||
}
|
||||
|
||||
// Validate file size (2MB max)
|
||||
if ($file->getSize() > 2 * 1024 * 1024) {
|
||||
return $this->response->setJSON(['success' => 0, 'message' => 'File size exceeds 2MB limit.']);
|
||||
}
|
||||
|
||||
// Generate random filename
|
||||
$extension = $file->getExtension();
|
||||
$newName = uniqid('page_', true) . '.' . $extension;
|
||||
$uploadPath = WRITEPATH . 'uploads/pages/';
|
||||
|
||||
// Create directory if not exists
|
||||
if (!is_dir($uploadPath)) {
|
||||
mkdir($uploadPath, 0755, true);
|
||||
}
|
||||
|
||||
// Move file
|
||||
if ($file->move($uploadPath, $newName)) {
|
||||
$url = base_url('writable/uploads/pages/' . $newName);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => 1,
|
||||
'file' => [
|
||||
'url' => $url,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['success' => 0, 'message' => 'Upload failed']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete page
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$page = $this->pageModel->find($id);
|
||||
|
||||
if (!$page) {
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('error', 'Halaman tidak ditemukan.');
|
||||
}
|
||||
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
if ($this->pageModel->delete($id)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('page_deleted', $userId);
|
||||
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('success', 'Halaman berhasil dihapus.');
|
||||
}
|
||||
|
||||
return redirect()->to('/admin/pages')
|
||||
->with('error', 'Gagal menghapus halaman.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize HTML using basic PHP functions
|
||||
* For production, consider using HTMLPurifier library
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizeHtml(string $html): string
|
||||
{
|
||||
// Basic sanitization - allow common HTML tags
|
||||
$allowedTags = '<p><h1><h2><h3><h4><h5><h6><ul><ol><li><blockquote><cite><pre><code><table><tbody><tr><td><th><hr><figure><img><figcaption><a><div><strong><em><u><s><br>';
|
||||
|
||||
// Strip all tags except allowed
|
||||
$html = strip_tags($html, $allowedTags);
|
||||
|
||||
// Remove dangerous attributes
|
||||
$html = preg_replace('/on\w+="[^"]*"/i', '', $html);
|
||||
$html = preg_replace('/javascript:/i', '', $html);
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
134
app/Controllers/Admin/Profile.php
Normal file
134
app/Controllers/Admin/Profile.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\UserModel;
|
||||
|
||||
class Profile extends BaseController
|
||||
{
|
||||
protected $userModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userModel = new UserModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display profile edit form
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
if (!$userId) {
|
||||
return redirect()->to('/auth/login')
|
||||
->with('error', 'Silakan login terlebih dahulu.');
|
||||
}
|
||||
|
||||
$user = $this->userModel->find($userId);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/dashboard')
|
||||
->with('error', 'User tidak ditemukan.');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'title' => 'Edit Profile',
|
||||
'user' => $user,
|
||||
];
|
||||
|
||||
return view('admin/profile/index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
if (!$userId) {
|
||||
return redirect()->to('/auth/login')
|
||||
->with('error', 'Silakan login terlebih dahulu.');
|
||||
}
|
||||
|
||||
$user = $this->userModel->find($userId);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/dashboard')
|
||||
->with('error', 'User tidak ditemukan.');
|
||||
}
|
||||
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'username' => 'required|min_length[3]|max_length[100]',
|
||||
'email' => 'required|valid_email|max_length[255]',
|
||||
'phone_number' => 'permit_empty|max_length[20]',
|
||||
'telegram_id' => 'permit_empty|integer',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('errors', $validation->getErrors());
|
||||
}
|
||||
|
||||
// Check if username is unique (except current user)
|
||||
$existingUser = $this->userModel->where('username', $this->request->getPost('username'))
|
||||
->where('id !=', $userId)
|
||||
->first();
|
||||
|
||||
if ($existingUser) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('errors', ['username' => 'Username sudah digunakan.']);
|
||||
}
|
||||
|
||||
// Check if email is unique (except current user)
|
||||
$existingEmail = $this->userModel->where('email', $this->request->getPost('email'))
|
||||
->where('id !=', $userId)
|
||||
->first();
|
||||
|
||||
if ($existingEmail) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('errors', ['email' => 'Email sudah digunakan.']);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'username' => $this->request->getPost('username'),
|
||||
'email' => $this->request->getPost('email'),
|
||||
'phone_number' => $this->request->getPost('phone_number') ?: null,
|
||||
'telegram_id' => $this->request->getPost('telegram_id') ?: null,
|
||||
];
|
||||
|
||||
// Update password if provided
|
||||
$newPassword = $this->request->getPost('password');
|
||||
if (!empty($newPassword)) {
|
||||
if (strlen($newPassword) < 6) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Password minimal 6 karakter.');
|
||||
}
|
||||
$data['password_hash'] = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
if ($this->userModel->update($userId, $data)) {
|
||||
// Update session data
|
||||
session()->set([
|
||||
'username' => $data['username'],
|
||||
'email' => $data['email'],
|
||||
]);
|
||||
|
||||
return redirect()->to('/admin/profile')
|
||||
->with('success', 'Profile berhasil diperbarui.');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Gagal memperbarui profile.');
|
||||
}
|
||||
}
|
||||
|
||||
83
app/Controllers/Admin/Settings.php
Normal file
83
app/Controllers/Admin/Settings.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\SettingsModel;
|
||||
|
||||
class Settings extends BaseController
|
||||
{
|
||||
protected $settingsModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->settingsModel = new SettingsModel();
|
||||
|
||||
// Check if user is admin
|
||||
if (session()->get('role') !== 'admin') {
|
||||
throw new \CodeIgniter\Exceptions\PageNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display settings form
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Get all settings
|
||||
$settings = $this->settingsModel->findAll();
|
||||
|
||||
// Convert to key-value array for easier access
|
||||
$settingsArray = [];
|
||||
foreach ($settings as $setting) {
|
||||
$settingsArray[$setting['key']] = $setting;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'title' => 'Pengaturan',
|
||||
'settings' => $settingsArray,
|
||||
];
|
||||
|
||||
return view('admin/settings/index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update settings
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'site_name' => 'required|min_length[3]|max_length[100]',
|
||||
'site_description' => 'permit_empty|max_length[255]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('errors', $validation->getErrors());
|
||||
}
|
||||
|
||||
$siteName = $this->request->getPost('site_name');
|
||||
$siteDescription = $this->request->getPost('site_description') ?: '';
|
||||
|
||||
// Update or create site_name
|
||||
$this->settingsModel->setSetting(
|
||||
'site_name',
|
||||
$siteName,
|
||||
'Nama situs yang ditampilkan di sidebar dan judul halaman'
|
||||
);
|
||||
|
||||
// Update or create site_description
|
||||
$this->settingsModel->setSetting(
|
||||
'site_description',
|
||||
$siteDescription,
|
||||
'Deskripsi singkat tentang situs'
|
||||
);
|
||||
|
||||
return redirect()->to('/admin/settings')
|
||||
->with('success', 'Pengaturan berhasil diperbarui.');
|
||||
}
|
||||
}
|
||||
|
||||
356
app/Controllers/Admin/Users.php
Normal file
356
app/Controllers/Admin/Users.php
Normal file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\RoleModel;
|
||||
use App\Models\AuditLogModel;
|
||||
|
||||
class Users extends BaseController
|
||||
{
|
||||
protected $userModel;
|
||||
protected $roleModel;
|
||||
protected $auditLogModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userModel = new UserModel();
|
||||
$this->roleModel = new RoleModel();
|
||||
$this->auditLogModel = new AuditLogModel();
|
||||
|
||||
// Check if user is admin
|
||||
if (session()->get('role') !== 'admin') {
|
||||
throw new \CodeIgniter\Exceptions\PageNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display list of users
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$perPage = 10;
|
||||
$page = $this->request->getGet('page') ?? 1;
|
||||
$role = $this->request->getGet('role');
|
||||
$status = $this->request->getGet('status');
|
||||
$search = $this->request->getGet('search');
|
||||
|
||||
// Build query with filters
|
||||
$this->userModel->select('users.*, roles.name as role_name')
|
||||
->join('roles', 'roles.id = users.role_id', 'left');
|
||||
|
||||
// Filter by role
|
||||
if ($role) {
|
||||
$this->userModel->where('roles.name', $role);
|
||||
}
|
||||
|
||||
// Filter by status
|
||||
if ($status !== null && $status !== '') {
|
||||
$this->userModel->where('users.is_active', $status);
|
||||
}
|
||||
|
||||
// Search
|
||||
if ($search) {
|
||||
$this->userModel->groupStart()
|
||||
->like('users.username', $search)
|
||||
->orLike('users.email', $search)
|
||||
->orLike('users.phone_number', $search)
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
$users = $this->userModel->orderBy('users.created_at', 'DESC')
|
||||
->paginate($perPage, 'default', $page);
|
||||
|
||||
$pager = $this->userModel->pager;
|
||||
|
||||
// Get roles for filter
|
||||
$roles = $this->roleModel->findAll();
|
||||
|
||||
$data = [
|
||||
'title' => 'Pengguna',
|
||||
'users' => $users,
|
||||
'pager' => $pager,
|
||||
'roles' => $roles,
|
||||
'currentRole' => $role,
|
||||
'currentStatus' => $status,
|
||||
'currentSearch' => $search,
|
||||
'stats' => [
|
||||
'total' => $this->userModel->countAllResults(),
|
||||
'active' => $this->userModel->where('is_active', 1)->countAllResults(),
|
||||
'inactive' => $this->userModel->where('is_active', 0)->countAllResults(),
|
||||
],
|
||||
];
|
||||
|
||||
return view('admin/users/index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to create new user
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$roles = $this->roleModel->findAll();
|
||||
|
||||
$data = [
|
||||
'title' => 'Tambah Pengguna',
|
||||
'user' => null,
|
||||
'roles' => $roles,
|
||||
];
|
||||
|
||||
return view('admin/users/form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store new user
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'username' => 'required|min_length[3]|max_length[100]|is_unique[users.username]',
|
||||
'email' => 'required|valid_email|max_length[255]|is_unique[users.email]',
|
||||
'password' => 'required|min_length[6]',
|
||||
'role_id' => 'required|integer',
|
||||
'phone_number' => 'permit_empty|max_length[20]|is_unique[users.phone_number]',
|
||||
'telegram_id' => 'permit_empty|integer|is_unique[users.telegram_id]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('validation', $validation);
|
||||
}
|
||||
|
||||
$username = $this->request->getPost('username');
|
||||
$email = $this->request->getPost('email');
|
||||
$password = $this->request->getPost('password');
|
||||
$roleId = $this->request->getPost('role_id');
|
||||
$phoneNumber = $this->request->getPost('phone_number');
|
||||
$telegramId = $this->request->getPost('telegram_id');
|
||||
$isActive = $this->request->getPost('is_active') ? 1 : 0;
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
$data = [
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'password_hash' => $password, // Will be hashed by beforeInsert
|
||||
'role_id' => $roleId,
|
||||
'phone_number' => !empty($phoneNumber) ? $phoneNumber : null,
|
||||
'telegram_id' => !empty($telegramId) ? $telegramId : null,
|
||||
'is_active' => $isActive,
|
||||
];
|
||||
|
||||
if ($this->userModel->insert($data)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('user_created', $userId);
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('success', 'Pengguna berhasil ditambahkan.');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Gagal menambahkan pengguna.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to edit user
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Pengguna tidak ditemukan.');
|
||||
}
|
||||
|
||||
$roles = $this->roleModel->findAll();
|
||||
|
||||
$data = [
|
||||
'title' => 'Edit Pengguna',
|
||||
'user' => $user,
|
||||
'roles' => $roles,
|
||||
];
|
||||
|
||||
return view('admin/users/form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user
|
||||
*/
|
||||
public function update($id)
|
||||
{
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Pengguna tidak ditemukan.');
|
||||
}
|
||||
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'username' => "required|min_length[3]|max_length[100]|is_unique[users.username,id,{$id}]",
|
||||
'email' => "required|valid_email|max_length[255]|is_unique[users.email,id,{$id}]",
|
||||
'role_id' => 'required|integer',
|
||||
'phone_number' => "permit_empty|max_length[20]|is_unique[users.phone_number,id,{$id}]",
|
||||
'telegram_id' => "permit_empty|integer|is_unique[users.telegram_id,id,{$id}]",
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('validation', $validation);
|
||||
}
|
||||
|
||||
$username = $this->request->getPost('username');
|
||||
$email = $this->request->getPost('email');
|
||||
$roleId = $this->request->getPost('role_id');
|
||||
$phoneNumber = $this->request->getPost('phone_number');
|
||||
$telegramId = $this->request->getPost('telegram_id');
|
||||
$isActive = $this->request->getPost('is_active') ? 1 : 0;
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
$data = [
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'role_id' => $roleId,
|
||||
'phone_number' => !empty($phoneNumber) ? $phoneNumber : null,
|
||||
'telegram_id' => !empty($telegramId) ? $telegramId : null,
|
||||
'is_active' => $isActive,
|
||||
];
|
||||
|
||||
if ($this->userModel->update($id, $data)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('user_updated', $userId);
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('success', 'Pengguna berhasil diperbarui.');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('error', 'Gagal memperbarui pengguna.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset user password
|
||||
*/
|
||||
public function resetPassword($id)
|
||||
{
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Pengguna tidak ditemukan.');
|
||||
}
|
||||
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$rules = [
|
||||
'new_password' => 'required|min_length[6]',
|
||||
'confirm_password' => 'required|matches[new_password]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->with('validation', $validation)
|
||||
->with('error', 'Password tidak valid atau tidak cocok.');
|
||||
}
|
||||
|
||||
$newPassword = $this->request->getPost('new_password');
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
$data = [
|
||||
'password_hash' => $newPassword, // Will be hashed by beforeUpdate
|
||||
];
|
||||
|
||||
if ($this->userModel->update($id, $data)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('user_password_reset', $userId);
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('success', 'Password pengguna berhasil direset.');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', 'Gagal mereset password.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle user active status
|
||||
*/
|
||||
public function toggleActive($id)
|
||||
{
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Pengguna tidak ditemukan.');
|
||||
}
|
||||
|
||||
// Prevent deactivating yourself
|
||||
if ($id == session()->get('user_id')) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Anda tidak dapat menonaktifkan akun sendiri.');
|
||||
}
|
||||
|
||||
$newStatus = $user['is_active'] ? 0 : 1;
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
$data = [
|
||||
'is_active' => $newStatus,
|
||||
];
|
||||
|
||||
if ($this->userModel->update($id, $data)) {
|
||||
// Log action
|
||||
$action = $newStatus ? 'user_activated' : 'user_deactivated';
|
||||
$this->auditLogModel->logAction($action, $userId);
|
||||
|
||||
$message = $newStatus ? 'Pengguna berhasil diaktifkan.' : 'Pengguna berhasil dinonaktifkan.';
|
||||
return redirect()->to('/admin/users')
|
||||
->with('success', $message);
|
||||
}
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Gagal mengubah status pengguna.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
if (!$user) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Pengguna tidak ditemukan.');
|
||||
}
|
||||
|
||||
// Prevent deleting yourself
|
||||
if ($id == session()->get('user_id')) {
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Anda tidak dapat menghapus akun sendiri.');
|
||||
}
|
||||
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
if ($this->userModel->delete($id)) {
|
||||
// Log action
|
||||
$this->auditLogModel->logAction('user_deleted', $userId);
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('success', 'Pengguna berhasil dihapus.');
|
||||
}
|
||||
|
||||
return redirect()->to('/admin/users')
|
||||
->with('error', 'Gagal menghapus pengguna.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user