first commit

This commit is contained in:
2025-11-20 14:44:35 +08:00
commit 91f70ed69c
839 changed files with 207385 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
<?php
// models/Book.php
class Book {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
public function findById($id) {
$stmt = $this->pdo->prepare("SELECT * FROM books WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByShareToken($share_token) {
$stmt = $this->pdo->prepare("SELECT * FROM books WHERE share_token = ?");
$stmt->execute([$share_token]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByUser($user_id) {
$stmt = $this->pdo->prepare("
SELECT b.*,
COUNT(c.id) as chapter_count,
COALESCE(SUM(c.word_count), 0) as total_words
FROM books b
LEFT JOIN chapters c ON b.id = c.book_id
WHERE b.user_id = ?
GROUP BY b.id
ORDER BY b.created_at DESC
");
$stmt->execute([$user_id]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function create($data) {
$share_token = bin2hex(random_bytes(16));
$stmt = $this->pdo->prepare("
INSERT INTO books (title, description, genre, user_id, series_id, sort_order_in_series, share_token)
VALUES (?, ?, ?, ?, ?, ?, ?)
");
return $stmt->execute([
$data['title'],
$data['description'] ?? null,
$data['genre'] ?? null,
$data['user_id'],
$data['series_id'] ?? null,
$data['sort_order_in_series'] ?? null,
$share_token
]);
}
public function update($id, $data) {
$stmt = $this->pdo->prepare("
UPDATE books
SET title = ?, description = ?, genre = ?, series_id = ?, sort_order_in_series = ?
WHERE id = ? AND user_id = ?
");
return $stmt->execute([
$data['title'],
$data['description'] ?? null,
$data['genre'] ?? null,
$data['series_id'] ?? null,
$data['sort_order_in_series'] ?? null,
$id,
$data['user_id']
]);
}
public function delete($id, $user_id) {
try {
$this->pdo->beginTransaction();
// Удаляем главы книги (сработает CASCADE, но лучше явно)
$stmt = $this->pdo->prepare("DELETE FROM chapters WHERE book_id = ?");
$stmt->execute([$id]);
// Удаляем саму книгу
$stmt = $this->pdo->prepare("DELETE FROM books WHERE id = ? AND user_id = ?");
$result = $stmt->execute([$id, $user_id]);
$this->pdo->commit();
return $result;
} catch (Exception $e) {
$this->pdo->rollBack();
return false;
}
}
public function userOwnsBook($book_id, $user_id) {
$stmt = $this->pdo->prepare("SELECT id FROM books WHERE id = ? AND user_id = ?");
$stmt->execute([$book_id, $user_id]);
return $stmt->fetch() !== false;
}
public function generateNewShareToken($book_id) {
$new_token = bin2hex(random_bytes(16));
$stmt = $this->pdo->prepare("UPDATE books SET share_token = ? WHERE id = ?");
$success = $stmt->execute([$new_token, $book_id]);
return $success ? $new_token : false;
}
public function getPublishedChapters($book_id) {
$stmt = $this->pdo->prepare("
SELECT * FROM chapters
WHERE book_id = ? AND status = 'published'
ORDER BY sort_order, created_at
");
$stmt->execute([$book_id]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
?>
+104
View File
@@ -0,0 +1,104 @@
<?php
// models/Chapter.php
class Chapter {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
public function findById($id) {
$stmt = $this->pdo->prepare("
SELECT c.*, b.user_id, b.title as book_title
FROM chapters c
JOIN books b ON c.book_id = b.id
WHERE c.id = ?
");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByBook($book_id) {
$stmt = $this->pdo->prepare("
SELECT * FROM chapters
WHERE book_id = ?
ORDER BY sort_order, created_at
");
$stmt->execute([$book_id]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function create($data) {
// Сначала получаем максимальный sort_order для этой книги
$stmt = $this->pdo->prepare("SELECT MAX(sort_order) as max_order FROM chapters WHERE book_id = ?");
$stmt->execute([$data['book_id']]);
$result = $stmt->fetch();
$next_order = ($result['max_order'] ?? 0) + 1;
// Подсчитываем количество слов
$word_count = $this->countWords($data['content']);
$stmt = $this->pdo->prepare("
INSERT INTO chapters (book_id, title, content, sort_order, word_count, status)
VALUES (?, ?, ?, ?, ?, ?)
");
return $stmt->execute([
$data['book_id'],
$data['title'],
$data['content'],
$next_order,
$word_count,
$data['status'] ?? 'draft'
]);
}
public function update($id, $data) {
$word_count = $this->countWords($data['content']);
$stmt = $this->pdo->prepare("
UPDATE chapters
SET title = ?, content = ?, word_count = ?, status = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
");
return $stmt->execute([
$data['title'],
$data['content'],
$word_count,
$data['status'] ?? 'draft',
$id
]);
}
public function delete($id) {
$stmt = $this->pdo->prepare("DELETE FROM chapters WHERE id = ?");
return $stmt->execute([$id]);
}
public function updateSortOrder($chapter_id, $new_order) {
$stmt = $this->pdo->prepare("UPDATE chapters SET sort_order = ? WHERE id = ?");
return $stmt->execute([$new_order, $chapter_id]);
}
private function countWords($text) {
// Простой подсчет слов (можно улучшить)
$text = strip_tags($text);
$text = preg_replace('/[^\p{L}\p{N}\s]/u', ' ', $text);
$words = preg_split('/\s+/', $text);
$words = array_filter($words);
return count($words);
}
public function userOwnsChapter($chapter_id, $user_id) {
$stmt = $this->pdo->prepare("
SELECT c.id
FROM chapters c
JOIN books b ON c.book_id = b.id
WHERE c.id = ? AND b.user_id = ?
");
$stmt->execute([$chapter_id, $user_id]);
return $stmt->fetch() !== false;
}
}
?>
+90
View File
@@ -0,0 +1,90 @@
<?php
// models/User.php
class User {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
public function findById($id) {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByUsername($username) {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByEmail($email) {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findAll() {
$stmt = $this->pdo->prepare("SELECT id, username, display_name, email, created_at, last_login, is_active FROM users ORDER BY created_at DESC");
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function create($data) {
$password_hash = password_hash($data['password'], PASSWORD_DEFAULT);
// Определяем статус активности: по умолчанию неактивен, если не указано иное
$is_active = $data['is_active'] ?? 0;
$stmt = $this->pdo->prepare("
INSERT INTO users (username, display_name, email, password_hash, is_active)
VALUES (?, ?, ?, ?, ?)
");
return $stmt->execute([
$data['username'],
$data['display_name'] ?? $data['username'],
$data['email'] ?? null,
$password_hash,
$is_active
]);
}
public function update($id, $data) {
$sql = "UPDATE users SET display_name = ?, email = ?";
$params = [$data['display_name'], $data['email']];
if (!empty($data['password'])) {
$sql .= ", password_hash = ?";
$params[] = password_hash($data['password'], PASSWORD_DEFAULT);
}
$sql .= " WHERE id = ?";
$params[] = $id;
$stmt = $this->pdo->prepare($sql);
return $stmt->execute($params);
}
public function updateStatus($id, $is_active) {
$stmt = $this->pdo->prepare("UPDATE users SET is_active = ? WHERE id = ?");
return $stmt->execute([$is_active, $id]);
}
public function delete($id) {
$stmt = $this->pdo->prepare("DELETE FROM users WHERE id = ?");
return $stmt->execute([$id]);
}
public function updateLastLogin($id) {
$stmt = $this->pdo->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?");
return $stmt->execute([$id]);
}
public function verifyPassword($password, $hash) {
return password_verify($password, $hash);
}
}
?>