diff --git a/.env b/.env index 7dd5499..824cbba 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # Postgres -POSTGRES_HOST="db" +POSTGRES_HOST="localhost" POSTGRES_PORT="5432" POSTGRES_USER="postgres" POSTGRES_PASSWORD="postgres" diff --git a/library_service/models/dto/book.py b/library_service/models/dto/book.py index 514ad4f..e06b485 100644 --- a/library_service/models/dto/book.py +++ b/library_service/models/dto/book.py @@ -1,43 +1,55 @@ """Модуль DTO-моделей книг""" + from typing import List from pydantic import ConfigDict -from sqlmodel import SQLModel +from sqlmodel import SQLModel, Field from library_service.models.enums import BookStatus class BookBase(SQLModel): """Базовая модель книги""" + title: str description: str + page_count: int = Field(gt=0) model_config = ConfigDict( # pyright: ignore json_schema_extra={ - "example": {"title": "book_title", "description": "book_description"} + "example": { + "title": "book_title", + "description": "book_description", + "page_count": 1, + } } ) class BookCreate(BookBase): """Модель книги для создания""" + pass class BookUpdate(SQLModel): """Модель книги для обновления""" + title: str | None = None description: str | None = None + page_count: int | None = None status: BookStatus | None = None class BookRead(BookBase): """Модель книги для чтения""" + id: int status: BookStatus class BookList(SQLModel): """Список книг""" + books: List[BookRead] total: int diff --git a/library_service/models/dto/misc.py b/library_service/models/dto/misc.py index d859a97..dcbd7c5 100644 --- a/library_service/models/dto/misc.py +++ b/library_service/models/dto/misc.py @@ -37,6 +37,7 @@ class BookWithAuthors(SQLModel): id: int title: str description: str + page_count: int authors: List[AuthorRead] = Field(default_factory=list) @@ -46,6 +47,7 @@ class BookWithGenres(SQLModel): id: int title: str description: str + page_count: int status: BookStatus | None = None genres: List[GenreRead] = Field(default_factory=list) @@ -56,6 +58,7 @@ class BookWithAuthorsAndGenres(SQLModel): id: int title: str description: str + page_count: int status: BookStatus | None = None authors: List[AuthorRead] = Field(default_factory=list) genres: List[GenreRead] = Field(default_factory=list) diff --git a/library_service/static/page/book.js b/library_service/static/page/book.js index 899b1a3..ef4145a 100644 --- a/library_service/static/page/book.js +++ b/library_service/static/page/book.js @@ -234,6 +234,12 @@ $(document).ready(() => { function renderBook(book) { $("#book-title").text(book.title); $("#book-id").text(`ID: ${book.id}`); + if (book.page_count && book.page_count > 0) { + $("#book-page-count-value").text(book.page_count); + $("#book-page-count-text").removeClass("hidden"); + } else { + $("#book-page-count-text").addClass("hidden"); + } $("#book-authors-text").text( book.authors.map((a) => a.name).join(", ") || "Автор неизвестен", ); diff --git a/library_service/static/page/books.js b/library_service/static/page/books.js index 9f67490..2fef73f 100644 --- a/library_service/static/page/books.js +++ b/library_service/static/page/books.js @@ -180,6 +180,11 @@ $(document).ready(() => { clone.querySelector(".book-title").textContent = book.title; clone.querySelector(".book-authors").textContent = book.authors.map((a) => a.name).join(", ") || "Автор неизвестен"; + if (book.page_count && book.page_count > 0) { + const pageEl = clone.querySelector(".book-page-count"); + pageEl.querySelector(".page-count-value").textContent = book.page_count; + pageEl.classList.remove("hidden"); + } clone.querySelector(".book-desc").textContent = book.description || ""; const statusConfig = getStatusConfig(book.status); diff --git a/library_service/static/page/create_book.js b/library_service/static/page/create_book.js index 699e0fb..736baec 100644 --- a/library_service/static/page/create_book.js +++ b/library_service/static/page/create_book.js @@ -235,18 +235,25 @@ $(document).ready(() => { const title = $("#book-title").val().trim(); const description = $("#book-description").val().trim(); + const pageCount = parseInt($("#book-page-count").val()) || null; if (!title) { Utils.showToast("Введите название книги", "error"); return; } + if (!parseInt(pageCount)) { + Utils.showToast("Введите количество страниц", "error"); + return; + } + setLoading(true); try { const bookPayload = { title: title, description: description || null, + page_count: pageCount ? parseInt(pageCount) : null, }; const createdBook = await Api.post("/api/books/", bookPayload); diff --git a/library_service/static/page/edit_book.js b/library_service/static/page/edit_book.js index 0bb3cc9..28f578d 100644 --- a/library_service/static/page/edit_book.js +++ b/library_service/static/page/edit_book.js @@ -23,6 +23,7 @@ $(document).ready(() => { const $titleInput = $("#book-title"); const $descInput = $("#book-description"); const $statusSelect = $("#book-status"); + const $pagesInput = $("#book-page-count"); const $submitBtn = $("#submit-btn"); const $submitText = $("#submit-text"); const $loadingSpinner = $("#loading-spinner"); @@ -69,6 +70,7 @@ $(document).ready(() => { function populateForm(book) { $titleInput.val(book.title); $descInput.val(book.description || ""); + $pagesInput.val(book.page_count); $statusSelect.val(book.status); updateCounters(); } @@ -329,6 +331,7 @@ $(document).ready(() => { const title = $titleInput.val().trim(); const description = $descInput.val().trim(); + const pages = $pagesInput.val(); const status = $statusSelect.val(); if (!title) { @@ -340,6 +343,7 @@ $(document).ready(() => { if (title !== originalBook.title) payload.title = title; if (description !== (originalBook.description || "")) payload.description = description || null; + if (pageCount !== originalBook.page_count) payload.page_count = pages; if (status !== originalBook.status) payload.status = status; if (Object.keys(payload).length === 0) { diff --git a/library_service/static/utils.js b/library_service/static/utils.js index 93476a5..febad3d 100644 --- a/library_service/static/utils.js +++ b/library_service/static/utils.js @@ -19,8 +19,8 @@ const StorageHelper = { const Utils = { escapeHtml: (text) => { - if (!text) return ""; - return text.replace( + if (text === null || text === undefined) return ""; + return String(text).replace( /[&<>"']/g, (m) => ({ diff --git a/library_service/templates/book.html b/library_service/templates/book.html index a3b16af..b26a545 100644 --- a/library_service/templates/book.html +++ b/library_service/templates/book.html @@ -107,6 +107,10 @@ id="book-authors-text" class="text-lg text-gray-600 font-medium mb-6" >

+

Авторы:

+

diff --git a/library_service/templates/create_book.html b/library_service/templates/create_book.html index 06f866d..f42dce7 100644 --- a/library_service/templates/create_book.html +++ b/library_service/templates/create_book.html @@ -69,6 +69,22 @@ >

+
+ + +

diff --git a/library_service/templates/edit_book.html b/library_service/templates/edit_book.html index 976961a..c79fd51 100644 --- a/library_service/templates/edit_book.html +++ b/library_service/templates/edit_book.html @@ -78,6 +78,23 @@

+
+ + +
+