|
@@ -0,0 +1,306 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+// Start session for language preference
|
|
|
|
|
+if (session_status() === PHP_SESSION_NONE) {
|
|
|
|
|
+ session_start();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+require_once '../includes/config.php';
|
|
|
|
|
+require_once '../includes/database.php';
|
|
|
|
|
+require_once '../includes/auth.php';
|
|
|
|
|
+require_once '../includes/comment.php';
|
|
|
|
|
+require_once '../includes/translation.php';
|
|
|
|
|
+
|
|
|
|
|
+// Translation system is auto-initialized when translation.php is included
|
|
|
|
|
+
|
|
|
|
|
+$auth = new Auth();
|
|
|
|
|
+$auth->requireAuth();
|
|
|
|
|
+
|
|
|
|
|
+$comment = new Comment();
|
|
|
|
|
+$user = $auth->getUser();
|
|
|
|
|
+
|
|
|
|
|
+// Handle actions
|
|
|
|
|
+$action = $_GET['action'] ?? '';
|
|
|
|
|
+$message = '';
|
|
|
|
|
+
|
|
|
|
|
+if ($action === 'approve' && isset($_GET['id'])) {
|
|
|
|
|
+ $id = (int)$_GET['id'];
|
|
|
|
|
+ if ($comment->updateStatus($id, 'approved')) {
|
|
|
|
|
+ $message = t('admin_comment_approved_success');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $message = t('admin_comment_approve_error');
|
|
|
|
|
+ }
|
|
|
|
|
+ header('Location: comments.php?message=' . urlencode($message));
|
|
|
|
|
+ exit;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if ($action === 'reject' && isset($_GET['id'])) {
|
|
|
|
|
+ $id = (int)$_GET['id'];
|
|
|
|
|
+ if ($comment->updateStatus($id, 'rejected')) {
|
|
|
|
|
+ $message = t('admin_comment_rejected_success');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $message = t('admin_comment_reject_error');
|
|
|
|
|
+ }
|
|
|
|
|
+ header('Location: comments.php?message=' . urlencode($message));
|
|
|
|
|
+ exit;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if ($action === 'delete' && isset($_GET['id'])) {
|
|
|
|
|
+ $id = (int)$_GET['id'];
|
|
|
|
|
+ if ($comment->delete($id)) {
|
|
|
|
|
+ $message = t('admin_comment_deleted_success');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $message = t('admin_comment_delete_error');
|
|
|
|
|
+ }
|
|
|
|
|
+ header('Location: comments.php?message=' . urlencode($message));
|
|
|
|
|
+ exit;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if ($action === 'reply' && isset($_POST['comment_id']) && isset($_POST['reply_content'])) {
|
|
|
|
|
+ $commentId = (int)$_POST['comment_id'];
|
|
|
|
|
+ $replyContent = trim($_POST['reply_content']);
|
|
|
|
|
+
|
|
|
|
|
+ // Get original comment to get publication ID
|
|
|
|
|
+ $originalComment = $comment->getById($commentId);
|
|
|
|
|
+
|
|
|
|
|
+ if ($originalComment && !empty($replyContent)) {
|
|
|
|
|
+ $replyData = [
|
|
|
|
|
+ 'publication_id' => $originalComment['publication_id'],
|
|
|
|
|
+ 'parent_id' => $commentId,
|
|
|
|
|
+ 'name' => $user['username'],
|
|
|
|
|
+ 'content' => $replyContent,
|
|
|
|
|
+ 'replied_by' => $user['id']
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ if ($comment->createAdminReply($replyData)) {
|
|
|
|
|
+ $message = t('admin_reply_added_success');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $message = t('admin_reply_add_error');
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $message = t('admin_reply_invalid_data');
|
|
|
|
|
+ }
|
|
|
|
|
+ header('Location: comments.php?message=' . urlencode($message));
|
|
|
|
|
+ exit;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Get pagination parameters
|
|
|
|
|
+$page = max(1, (int)($_GET['page'] ?? 1));
|
|
|
|
|
+$limit = 20;
|
|
|
|
|
+$offset = ($page - 1) * $limit;
|
|
|
|
|
+
|
|
|
|
|
+// Get status filter
|
|
|
|
|
+$status = $_GET['status'] ?? '';
|
|
|
|
|
+
|
|
|
|
|
+// Get comments
|
|
|
|
|
+$comments = $comment->getAll($status ?: null, $limit, $offset);
|
|
|
|
|
+$totalComments = $comment->getCountByStatus($status ?: null);
|
|
|
|
|
+$totalPages = ceil($totalComments / $limit);
|
|
|
|
|
+
|
|
|
|
|
+// Handle message from redirect
|
|
|
|
|
+if (isset($_GET['message'])) {
|
|
|
|
|
+ $message = htmlspecialchars($_GET['message']);
|
|
|
|
|
+}
|
|
|
|
|
+?>
|
|
|
|
|
+<!DOCTYPE html>
|
|
|
|
|
+<html lang="<?php echo Translation::getCurrentLang(); ?>">
|
|
|
|
|
+<head>
|
|
|
|
|
+ <meta charset="UTF-8">
|
|
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
+ <title><?php echo t('manage_comments'); ?> - <?php echo SITE_TITLE; ?></title>
|
|
|
|
|
+ <link rel="stylesheet" href="../css/style.css">
|
|
|
|
|
+ <link rel="stylesheet" href="../css/admin-comments.css">
|
|
|
|
|
+</head>
|
|
|
|
|
+<body>
|
|
|
|
|
+ <div class="admin-layout">
|
|
|
|
|
+ <header class="admin-header">
|
|
|
|
|
+ <div class="header-content">
|
|
|
|
|
+ <h1><a href="/index.php"><?php echo SITE_TITLE; ?></a></h1>
|
|
|
|
|
+ <nav class="admin-nav">
|
|
|
|
|
+ <a href="index.php" class="nav-link"><?php echo t('admin_nav_dashboard'); ?></a>
|
|
|
|
|
+ <a href="publications.php" class="nav-link"><?php echo t('admin_nav_publications'); ?></a>
|
|
|
|
|
+ <a href="categories.php" class="nav-link"><?php echo t('admin_nav_categories'); ?></a>
|
|
|
|
|
+ <a href="users.php" class="nav-link"><?php echo t('manage_users'); ?></a>
|
|
|
|
|
+ <a href="comments.php" class="nav-link active"><?php echo t('admin_nav_comments'); ?></a>
|
|
|
|
|
+ <?php if (LDAP_ENABLED): ?>
|
|
|
|
|
+ <a href="ldap-users.php" class="nav-link"><?php echo t('admin_nav_ldap_users'); ?></a>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <a href="logout.php" class="nav-link"><?php echo t('admin_nav_logout'); ?></a>
|
|
|
|
|
+ </nav>
|
|
|
|
|
+ <div class="user-info">
|
|
|
|
|
+ <?php echo t('welcome'); ?>, <?php echo htmlspecialchars($user['username']); ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <?php echo Translation::getLanguageSwitcher('comments.php'); ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </header>
|
|
|
|
|
+
|
|
|
|
|
+ <main class="admin-main">
|
|
|
|
|
+ <div class="page-header">
|
|
|
|
|
+ <h2><?php echo t('manage_comments'); ?></h2>
|
|
|
|
|
+ <div class="header-stats">
|
|
|
|
|
+ <span class="stat-item">
|
|
|
|
|
+ <?php echo t('pending_comments'); ?>: <strong><?php echo $comment->getPendingCount(); ?></strong>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="stat-item">
|
|
|
|
|
+ <?php echo t('total_comments'); ?>: <strong><?php echo $comment->getCountByStatus(); ?></strong>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <?php if ($message): ?>
|
|
|
|
|
+ <div class="alert alert-<?php echo strpos($message, 'Error') === false ? 'success' : 'error'; ?>">
|
|
|
|
|
+ <?php echo $message; ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Status Filter -->
|
|
|
|
|
+ <div class="filter-section">
|
|
|
|
|
+ <form method="get" class="filter-form">
|
|
|
|
|
+ <label for="status"><?php echo t('filter_by_status'); ?>:</label>
|
|
|
|
|
+ <select name="status" id="status" onchange="this.form.submit()">
|
|
|
|
|
+ <option value=""><?php echo t('all_comments'); ?></option>
|
|
|
|
|
+ <option value="pending" <?php echo $status === 'pending' ? 'selected' : ''; ?>><?php echo t('pending'); ?></option>
|
|
|
|
|
+ <option value="approved" <?php echo $status === 'approved' ? 'selected' : ''; ?>><?php echo t('approved'); ?></option>
|
|
|
|
|
+ <option value="rejected" <?php echo $status === 'rejected' ? 'selected' : ''; ?>><?php echo t('rejected'); ?></option>
|
|
|
|
|
+ </select>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Comments List -->
|
|
|
|
|
+ <div class="comments-admin-list">
|
|
|
|
|
+ <?php if (empty($comments)): ?>
|
|
|
|
|
+ <p class="no-comments"><?php echo t('no_comments_found'); ?></p>
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <?php foreach ($comments as $comment_item): ?>
|
|
|
|
|
+ <div class="comment-admin-item <?php echo $comment_item['status']; ?>">
|
|
|
|
|
+ <div class="comment-header">
|
|
|
|
|
+ <div class="comment-meta">
|
|
|
|
|
+ <span class="comment-author">
|
|
|
|
|
+ <strong><?php echo htmlspecialchars($comment_item['name']); ?></strong>
|
|
|
|
|
+ <?php if ($comment_item['email']): ?>
|
|
|
|
|
+ <small>(<?php echo htmlspecialchars($comment_item['email']); ?>)</small>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="comment-date">
|
|
|
|
|
+ <?php echo date('M j, Y g:i A', strtotime($comment_item['created_at'])); ?>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="comment-status status-<?php echo $comment_item['status']; ?>">
|
|
|
|
|
+ <?php echo t($comment_item['status']); ?>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="comment-actions">
|
|
|
|
|
+ <?php if ($comment_item['status'] === 'pending'): ?>
|
|
|
|
|
+ <a href="comments.php?action=approve&id=<?php echo $comment_item['id']; ?>"
|
|
|
|
|
+ class="btn btn-sm btn-success"><?php echo t('approve'); ?></a>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <?php if ($comment_item['status'] !== 'rejected'): ?>
|
|
|
|
|
+ <a href="comments.php?action=reject&id=<?php echo $comment_item['id']; ?>"
|
|
|
|
|
+ class="btn btn-sm btn-warning"><?php echo t('reject'); ?></a>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <button type="button" class="btn btn-sm btn-primary reply-btn"
|
|
|
|
|
+ data-comment-id="<?php echo $comment_item['id']; ?>">
|
|
|
|
|
+ <?php echo t('reply'); ?>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <a href="comments.php?action=delete&id=<?php echo $comment_item['id']; ?>"
|
|
|
|
|
+ class="btn btn-sm btn-danger"
|
|
|
|
|
+ onclick="return confirm('<?php echo t('admin_delete_comment_confirm'); ?>')">
|
|
|
|
|
+ <?php echo t('delete'); ?>
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="comment-content">
|
|
|
|
|
+ <p><?php echo nl2br(htmlspecialchars($comment_item['content'])); ?></p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="comment-publication">
|
|
|
|
|
+ <small>
|
|
|
|
|
+ <?php echo t('on_publication'); ?>:
|
|
|
|
|
+ <a href="../public/publication.php?id=<?php echo $comment_item['publication_id']; ?>" target="_blank">
|
|
|
|
|
+ <?php echo htmlspecialchars($comment_item['publication_title']); ?>
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </small>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Reply Form (hidden by default) -->
|
|
|
|
|
+ <div class="reply-form-container" id="reply-form-<?php echo $comment_item['id']; ?>" style="display: none;">
|
|
|
|
|
+ <form method="post" class="reply-form">
|
|
|
|
|
+ <input type="hidden" name="comment_id" value="<?php echo $comment_item['id']; ?>">
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label><?php echo t('admin_reply'); ?>:</label>
|
|
|
|
|
+ <textarea name="reply_content" rows="3" required placeholder="<?php echo t('enter_reply'); ?>"></textarea>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="form-actions">
|
|
|
|
|
+ <button type="submit" class="btn btn-primary"><?php echo t('submit_reply'); ?></button>
|
|
|
|
|
+ <button type="button" class="btn btn-secondary cancel-reply"><?php echo t('cancel'); ?></button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Show replies -->
|
|
|
|
|
+ <?php if ($comment_item['parent_id']): ?>
|
|
|
|
|
+ <div class="reply-indicator">
|
|
|
|
|
+ <small><?php echo t('reply_to_comment'); ?></small>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <?php endforeach; ?>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Pagination -->
|
|
|
|
|
+ <?php if ($totalPages > 1): ?>
|
|
|
|
|
+ <div class="pagination">
|
|
|
|
|
+ <?php if ($page > 1): ?>
|
|
|
|
|
+ <a href="?page=<?php echo $page - 1; ?><?php echo $status ? '&status=' . $status : ''; ?>"
|
|
|
|
|
+ class="btn btn-secondary"><?php echo t('previous'); ?></a>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+
|
|
|
|
|
+ <span class="page-info">
|
|
|
|
|
+ <?php echo t('page'); ?> <?php echo $page; ?> <?php echo t('of'); ?> <?php echo $totalPages; ?>
|
|
|
|
|
+ </span>
|
|
|
|
|
+
|
|
|
|
|
+ <?php if ($page < $totalPages): ?>
|
|
|
|
|
+ <a href="?page=<?php echo $page + 1; ?><?php echo $status ? '&status=' . $status : ''; ?>"
|
|
|
|
|
+ class="btn btn-secondary"><?php echo t('next'); ?></a>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </main>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <script>
|
|
|
|
|
+ // Admin Comments JavaScript
|
|
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
+ // Handle reply buttons
|
|
|
|
|
+ document.querySelectorAll('.reply-btn').forEach(button => {
|
|
|
|
|
+ button.addEventListener('click', function() {
|
|
|
|
|
+ const commentId = this.dataset.commentId;
|
|
|
|
|
+ const replyForm = document.getElementById('reply-form-' + commentId);
|
|
|
|
|
+
|
|
|
|
|
+ // Hide all other reply forms
|
|
|
|
|
+ document.querySelectorAll('.reply-form-container').forEach(form => {
|
|
|
|
|
+ if (form.id !== 'reply-form-' + commentId) {
|
|
|
|
|
+ form.style.display = 'none';
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Toggle this reply form
|
|
|
|
|
+ replyForm.style.display = replyForm.style.display === 'none' ? 'block' : 'none';
|
|
|
|
|
+
|
|
|
|
|
+ // Focus on textarea if showing
|
|
|
|
|
+ if (replyForm.style.display === 'block') {
|
|
|
|
|
+ replyForm.querySelector('textarea').focus();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Handle cancel reply buttons
|
|
|
|
|
+ document.querySelectorAll('.cancel-reply').forEach(button => {
|
|
|
|
|
+ button.addEventListener('click', function() {
|
|
|
|
|
+ this.closest('.reply-form-container').style.display = 'none';
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ </script>
|
|
|
|
|
+</body>
|
|
|
|
|
+</html>
|