-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbook.php
More file actions
102 lines (91 loc) · 3.6 KB
/
book.php
File metadata and controls
102 lines (91 loc) · 3.6 KB
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
<?php
/**
* Book detail page.
*
* Public: anyone can view title/author/cover/description.
* Authed users additionally see "Add to shelf" controls, their own review,
* and a write-review form.
*
* POST handles inline review submit/delete (server-rendered fallback for
* the JS-driven review form on the page).
*/
define('APP_BOOTED', true);
require __DIR__ . '/includes/bootstrap.php';
$uuid = (string) ($_GET['b'] ?? '');
if (!preg_match('/^[0-9a-f-]{36}$/i', $uuid)) {
abort(404);
}
$book = BookRepository::findByUuid($uuid);
if (!$book || $book['status'] !== 'published') {
abort(404);
}
$user = current_user();
// ---- POST handlers ----
if (is_post()) {
csrf_verify_or_abort();
if (!$user) {
flash('error', 'Please sign in first.');
redirect('login.php');
}
$verb = (string) ($_POST['verb'] ?? '');
if ($verb === 'review_submit') {
$rating = (int) ($_POST['rating'] ?? 0);
if ($rating < 1 || $rating > 5) {
flash('error', 'Pick a rating between 1 and 5 stars.');
redirect('book.php?b=' . $uuid);
}
ReviewRepository::upsert((int) $user['id'], (int) $book['id'], [
'rating' => $rating,
'title' => $_POST['title'] ?? null,
'body' => $_POST['body'] ?? null,
]);
AuditLogger::log('review.submit', 'book', (int) $book['id'], ['rating' => $rating]);
flash('success', 'Thanks for your review.');
redirect('book.php?b=' . $uuid);
}
if ($verb === 'review_delete') {
$reviewId = (int) ($_POST['review_id'] ?? 0);
if ($reviewId > 0 && ReviewRepository::delete((int) $user['id'], $reviewId)) {
AuditLogger::log('review.delete', 'book', (int) $book['id']);
flash('success', 'Review removed.');
}
redirect('book.php?b=' . $uuid);
}
if ($verb === 'shelf_toggle') {
$collectionId = (int) ($_POST['collection_id'] ?? 0);
$coll = $collectionId > 0 ? CollectionRepository::findById($collectionId) : null;
if (!$coll || (int) $coll['user_id'] !== (int) $user['id']) {
flash('error', 'Shelf not found.');
redirect('book.php?b=' . $uuid);
}
if (CollectionRepository::containsBook($collectionId, (int) $book['id'])) {
CollectionRepository::removeBook($collectionId, (int) $book['id']);
flash('success', 'Removed from ' . $coll['name'] . '.');
} else {
CollectionRepository::addBook($collectionId, (int) $book['id']);
flash('success', 'Added to ' . $coll['name'] . '.');
}
redirect('book.php?b=' . $uuid);
}
}
// ---- Render data ----
$tags = TagRepository::forBook((int) $book['id']);
$progress = $user ? ProgressRepository::get((int) $user['id'], (int) $book['id']) : null;
$reviews = ReviewRepository::listForBook((int) $book['id'], 25);
$myReview = $user ? ReviewRepository::findForUserBook((int) $user['id'], (int) $book['id']) : null;
$distribution = ReviewRepository::distributionForBook((int) $book['id']);
$related = BookRepository::relatedTo((int) $book['id'], 6);
$shelves = $user ? CollectionRepository::forUserAndBook((int) $user['id'], (int) $book['id']) : [];
render('book/show', [
'pageTitle' => $book['title'] . ' — ' . $book['author'],
'pageClass' => 'book-detail-page',
'book' => $book,
'tags' => $tags,
'progress' => $progress,
'reviews' => $reviews,
'myReview' => $myReview,
'distribution' => $distribution,
'related' => $related,
'shelves' => $shelves,
'user' => $user,
], 'app');