1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
<?php
declare(strict_types=1);
// Gallery: public paginated feed with likes, comments, and notifications.
namespace App\Controllers;
use App\Csrf;
use App\Flash;
use App\Mail;
use App\Models\Comment;
use App\Models\Like;
use App\Models\Post;
use App\Models\User;
class GalleryController
{
private Post $post;
private Like $like;
private Comment $comment;
private const POSTS_PER_PAGE = 5;
public function __construct()
{
$this->post = new Post();
$this->like = new Like();
$this->comment = new Comment();
}
public function index(): void
{
$page = max(1, (int) ($_GET['page'] ?? 1));
$offset = ($page - 1) * self::POSTS_PER_PAGE;
$posts = $this->post->findAllPaginated(self::POSTS_PER_PAGE, $offset);
$totalPosts = $this->post->countAll();
$totalPages = max(1, (int) ceil($totalPosts / self::POSTS_PER_PAGE));
$userId = $_SESSION['user_id'] ?? null;
foreach ($posts as &$post) {
$post['like_count'] = $this->like->countByPost($post['id']);
$post['user_liked'] = $userId ? $this->like->hasUserLiked($userId, $post['id']) : false;
$post['comments'] = $this->comment->findByPostId($post['id']);
}
unset($post);
$content = __DIR__ . '/../Views/gallery/index.php';
include __DIR__ . '/../Views/layouts/main.php';
}
public function like(string $id): void
{
if (!isset($_SESSION['user_id'])) {
header('Location: /login');
return;
}
if (!Csrf::validate($_POST['csrf_token'] ?? '')) {
Flash::set('error', 'Invalid CSRF token.');
header('Location: /gallery');
return;
}
$this->like->toggle($_SESSION['user_id'], (int) $id);
$page = (int) ($_POST['page'] ?? 1);
header('Location: /gallery?page=' . $page . '#post-' . $id);
}
public function comment(string $id): void
{
if (!isset($_SESSION['user_id'])) {
header('Location: /login');
return;
}
if (!Csrf::validate($_POST['csrf_token'] ?? '')) {
Flash::set('error', 'Invalid CSRF token.');
header('Location: /gallery');
return;
}
$content = trim($_POST['content'] ?? '');
if ($content === '') {
Flash::set('error', 'Comment cannot be empty.');
$page = (int) ($_POST['page'] ?? 1);
header('Location: /gallery?page=' . $page . '#post-' . $id);
return;
}
if (\strlen($content) > 500) {
Flash::set('error', 'Comment is too long (max 500 characters).');
$page = (int) ($_POST['page'] ?? 1);
header('Location: /gallery?page=' . $page . '#post-' . $id);
return;
}
$this->comment->create($_SESSION['user_id'], (int) $id, $content);
// Notify the post owner if they have comment notifications enabled
$post = $this->post->findById((int) $id);
if ($post && $post['user_id'] !== $_SESSION['user_id']) {
$user = new User();
$owner = $user->findById($post['user_id']);
if ($owner && $owner['notify_comments']) {
Mail::sendCommentNotification(
$owner['email'],
$_SESSION['username'],
(int) $id
);
}
}
$page = (int) ($_POST['page'] ?? 1);
header('Location: /gallery?page=' . $page . '#post-' . $id);
}
}
|