Book and Library ================ The Book feature provides a comprehensive system for creating structured, hierarchical documentation with automatic table of contents numbering, PDF export capabilities, and user access management. The Library content type serves as a container for organizing multiple books. Overview -------- The Book system consists of: - **Library** - Container for organizing multiple books - **Book** - Main container with table of contents, custom styling, and PDF export - **Chapter** - Hierarchical content units with automatic numbering - **Paragraph** - Content blocks within chapters Key features include: - Automatic table of contents generation with hierarchical numbering (1, 1.1, 1.1.1, etc.) - PDF export via WeasyPrint integration - Custom CSS styling per book - User registration and access request workflows - REST API with enhanced serialization Content Types ------------- Library ^^^^^^^ A container specifically designed for organizing books. **Portal Type:** ``Library`` **Allowed Content Types:** ``Book`` only Book ^^^^ The main documentation container with chapters and table of contents support. **Portal Type:** ``Book`` **Allowed Content Types:** ``Chapter`` only **Schema Fields (via behaviors):** - ``custom_css`` (Text) - Custom CSS with variable substitution - ``include_default_css`` (Bool) - Include default book CSS (default: True) - ``header_image`` (NamedBlobImage) - Header image for PDF export Chapter ^^^^^^^ Hierarchical content container that can nest other chapters. **Portal Type:** ``Chapter`` **Allowed Content Types:** - ``Chapter`` - Nested chapters (subchapters) - ``Paragraph`` - Content blocks - ``TableBlock`` - Table content - ``FileListingBlock`` - File listings - ``MediaFolder`` - Media containers - ``CommentBlock`` - Comments **Schema Fields:** - ``hide`` (Bool) - Hide from table of contents (default: False) Paragraph ^^^^^^^^^ A content block within chapters with optional TOC visibility. Table of Contents ----------------- The ``Toc`` class generates hierarchical chapter numbers automatically. Number Generation ^^^^^^^^^^^^^^^^^ Chapters receive automatic numbers based on their position in the hierarchy: - First chapter: ``1`` - Second chapter: ``2`` - First subchapter of chapter 1: ``1.1`` - Second subchapter of chapter 1: ``1.2`` - First subchapter of chapter 2: ``2.1`` - Deep nesting: ``1.1.1``, ``1.1.2``, ``2.1.1``, etc. **Usage:** .. code-block:: python from wcs.backend.book.toc import Toc # Get chapter number chapter = context # A Chapter object number = Toc(chapter).number() # Returns "1.1.2" or None if hidden TOC Visibility ^^^^^^^^^^^^^^ Chapters can be hidden from the table of contents: .. code-block:: python # Hide chapter from TOC chapter.hide = True chapter.reindexObject() Hidden chapters: - Do not appear in table of contents - Return ``None`` from ``Toc(chapter).number()`` - Their children still calculate numbers correctly (skipping the hidden parent in numbering) Catalog Index ^^^^^^^^^^^^^ The ``show_in_toc`` index enables efficient TOC queries: .. code-block:: python # Query chapters visible in TOC from plone import api catalog = api.portal.get_tool('portal_catalog') results = catalog.searchResults( portal_type='Chapter', show_in_toc=True, path='/Plone/my-book' ) REST API -------- Enhanced Serialization ^^^^^^^^^^^^^^^^^^^^^^ Books and chapters include automatic TOC number calculation in REST API responses. **Book Response:** .. code-block:: json { "@id": "http://localhost:8080/Plone/my-book", "@type": "Book", "title": "User Manual", "items": [ { "@id": "http://localhost:8080/Plone/my-book/chapter-1", "@type": "Chapter", "title": "Introduction", "number": "1" }, { "@id": "http://localhost:8080/Plone/my-book/chapter-2", "@type": "Chapter", "title": "Getting Started", "number": "2" } ] } **Chapter Response:** .. code-block:: json { "@id": "http://localhost:8080/Plone/my-book/chapter-1/subchapter-1", "@type": "Chapter", "title": "Installation", "number": "1.1", "items": [ { "@type": "Paragraph", "title": "Prerequisites", "number": "1.1.1" } ] } GET @book-keywords ^^^^^^^^^^^^^^^^^^ Returns all unique keywords in a book with occurrence counts. .. http:example:: curl python-requests GET /Plone/my-book/@book-keywords HTTP/1.1 Host: localhost:8080 Accept: application/json **Response:** .. code-block:: json { "keywords": [ {"keyword": "Baurecht", "count": 5}, {"keyword": "Eigentum", "count": 3}, {"keyword": "Vertrag", "count": 2} ], "total": 3 } GET @book-keyword-search ^^^^^^^^^^^^^^^^^^^^^^^^ Searches for paragraphs containing a specific keyword within a book. .. http:example:: curl python-requests GET /Plone/my-book/@book-keyword-search?keyword=Baurecht HTTP/1.1 Host: localhost:8080 Accept: application/json **Response:** .. code-block:: json { "@id": "http://localhost:8080/Plone/my-book/@book-keyword-search?keyword=Baurecht", "keyword": "Baurecht", "items": [ { "@id": "http://localhost:8080/Plone/my-book/chapter-1/paragraph-1", "title": "Introduction Paragraph", "UID": "abc123", "parent_chapter": { "@id": "http://localhost:8080/Plone/my-book/chapter-1", "title": "Introduction", "number": "1" } } ], "items_total": 1 } **Pagination:** Supports ``b_start`` and ``b_size`` query parameters for pagination. .. http:example:: curl python-requests GET /Plone/my-book/@book-keyword-search?keyword=Baurecht&b_size=10&b_start=0 HTTP/1.1 Host: localhost:8080 Accept: application/json GET @contextnavigation ^^^^^^^^^^^^^^^^^^^^^^ Enhanced context navigation for books with TOC numbers. .. http:example:: curl python-requests GET /Plone/my-book/@contextnavigation?expand.contextnavigation.bottomLevel=3 HTTP/1.1 Host: localhost:8080 Accept: application/json **Response:** .. code-block:: json { "items": [ { "@id": "http://localhost:8080/Plone/my-book/chapter-1", "title": "Introduction", "number": "1", "items": [ { "@id": "http://localhost:8080/Plone/my-book/chapter-1/overview", "title": "Overview", "number": "1.1" } ] }, { "@id": "http://localhost:8080/Plone/my-book/chapter-2", "title": "Getting Started", "number": "2" } ] } PDF Export ---------- Books support PDF generation via WeasyPrint integration with an external PDF server. Configuration ^^^^^^^^^^^^^ Environment variables: - ``PDFSERVER_URL`` - PDF server URL (default: ``http://localhost:8040``) - ``PLONE_BACKEND_HOST`` - Backend URL for PDF server to fetch content PDF Server Endpoints ^^^^^^^^^^^^^^^^^^^^ **POST @pdfserver-convert** Initiates PDF conversion for the current content. .. http:example:: curl python-requests POST /Plone/my-book/@pdfserver-convert HTTP/1.1 Host: localhost:8080 Accept: application/json Content-Type: application/json **Response:** .. code-block:: json { "uid": "conversion-job-uid", "status": "pending" } **GET @pdfserver-status** Check conversion status. .. http:example:: curl python-requests GET /Plone/my-book/@pdfserver-status?uid=conversion-job-uid HTTP/1.1 Host: localhost:8080 Accept: application/json **Response:** .. code-block:: json { "uid": "conversion-job-uid", "status": "completed" } **GET @@pdfserver-download** Download the generated PDF. .. http:example:: curl python-requests GET /Plone/my-book/@@pdfserver-download?uid=conversion-job-uid HTTP/1.1 Host: localhost:8080 **Response:** PDF file download WeasyPrint Views ^^^^^^^^^^^^^^^^ The following views render content for PDF generation: - ``@@view_weasyprint`` - Main WeasyPrint template for books - ``@@toc_weasyprint`` - Table of contents for PDF - ``@@chapter_weasyprint`` - Chapter rendering Custom CSS ^^^^^^^^^^ Books support custom CSS with variable substitution: .. code-block:: css /* Available variables: $portal_url, $book_url */ .book-header { background-image: url($book_url/@@images/header_image); } .book-logo { background-image: url($portal_url/++resource++images/logo.png); } CSS is served via: - ``@@custom-book.css`` - Custom CSS with variable substitution - ``@@book-variables.css`` - CSS custom properties for dates and images User Access Management ---------------------- The Book feature includes a complete user registration and access request workflow. Book Owner Behavior ^^^^^^^^^^^^^^^^^^^ Books can have the ``IBookOwner`` behavior for managing access: **Fields:** - ``moderator_email`` - Email for access request notifications - ``fallback_email`` - Fallback email if moderator is unavailable - ``group`` - Plone group for book access Registration Form ^^^^^^^^^^^^^^^^^ A custom registration form (``@@register``) allows users to: 1. Create a new account 2. Select books to request access to 3. Trigger email notifications to book moderators **Browser View:** ``@@register`` (available when ``IBackendBookLayer`` is active) Request Book Access ^^^^^^^^^^^^^^^^^^^ Logged-in users can request access to additional books. **Browser Form:** ``@@request-book-access`` **REST API:** .. http:example:: curl python-requests POST /Plone/@request-book-access HTTP/1.1 Host: localhost:8080 Accept: application/json Content-Type: application/json { "books": ["book-uid-1", "book-uid-2"] } **Response:** .. code-block:: json { "success": true } Approve Access ^^^^^^^^^^^^^^ Book moderators can approve access requests via ``@@book-share``: .. code-block:: text /Plone/my-book/@@book-share?userid=john.doe This: 1. Adds the user to the book's configured group 2. Sends a confirmation email to the user Email Templates ^^^^^^^^^^^^^^^ The following email templates are used: - ``new-user-access-book-request-mail`` - New user registration request - ``user-access-granted`` - Access approval notification - ``new-user-created-and-access-to-book-mail`` - Admin-created user with book access PDF Views ^^^^^^^^^ - ``@@pdf_view`` - PDF conversion interface - ``@@pdfserver-download`` - PDF download AI Ask (RAG) Configuration -------------------------- Books can individually enable or disable the AI Ask feature. This allows administrators to control which books expose the AI Ask tab to users. Prerequisites ^^^^^^^^^^^^^ - Global RAG must be enabled via the ``RAG_ENABLED=true`` environment variable - The book must have ``rag_enabled`` set to ``True`` When both conditions are met, the "AI Ask" tab appears in the book's navigation alongside "Table of Contents" and "Keyword Search". Permissions ^^^^^^^^^^^ The ``rag_enabled`` field requires the ``Manage RAG properties`` permission to edit. By default, only Manager and Site Administrator roles have this permission. REST API ^^^^^^^^ The ``rag_enabled`` field is included in the book's REST API response: .. code-block:: javascript // JavaScript example using fetch const response = await fetch('/plone/my-book', { headers: { 'Accept': 'application/json', 'Authorization': 'Bearer ' } }); const book = await response.json(); console.log(book.rag_enabled); // true or false Asking Questions ^^^^^^^^^^^^^^^^ When enabled, the AI Ask feature allows users to ask natural language questions about the book's content. The system searches through the book's chapters and paragraphs using hybrid search (combining keyword and semantic matching) and generates answers using an LLM. The ``@rag-ask`` endpoint supports a ``path`` parameter to scope questions to a specific book: .. code-block:: javascript // Ask a question scoped to a specific book const response = await fetch('/plone/@rag-ask', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ question: 'What is covered in chapter 3?', path: '/plone/my-book' }) }); See the :doc:`rag` documentation for complete details on the RAG system configuration and API. Integration Guide ----------------- Querying TOC Structure ^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python from plone import api from wcs.backend.book.toc import Toc book = api.content.get(path='/library/my-book') catalog = api.portal.get_tool('portal_catalog') # Get all visible chapters chapters = catalog.searchResults( portal_type='Chapter', path='/'.join(book.getPhysicalPath()), show_in_toc=True, sort_on='getObjPositionInParent' ) for brain in chapters: chapter = brain.getObject() number = Toc(chapter).number() print(f"{number} {chapter.Title()}") File Locations -------------- **Core Module:** - ``wcs/backend/book/content.py`` - Content type classes (Library, Book, Chapter, Paragraph) - ``wcs/backend/book/behaviors.py`` - Behaviors (IShowInToc, IBookCustomCSS, IBookConfiguration, IBookOwner) - ``wcs/backend/book/toc.py`` - Table of contents generator - ``wcs/backend/book/utils.py`` - Utility functions - ``wcs/backend/book/indexer.py`` - Catalog indexers (show_in_toc, book_keywords) - ``wcs/backend/book/keyword_utils.py`` - Keyword extraction utilities - ``wcs/backend/book/configure.zcml`` - ZCML configuration **REST API:** - ``wcs/backend/book/restapi.py`` - Serializers and services **Views:** - ``wcs/backend/book/views.py`` - Browser views - ``wcs/backend/book/templates/`` - View templates **PDF Generation:** - ``wcs/backend/book/pdfserver_client.py`` - PDF server client - ``wcs/backend/book/weasyprint/views.py`` - WeasyPrint views - ``wcs/backend/book/weasyprint/templates/`` - PDF templates - ``wcs/backend/book/weasyprint/resources/`` - PDF CSS resources **User Management:** - ``wcs/backend/book/register_form.py`` - Registration form - ``wcs/backend/book/emails.py`` - Email adapters - ``wcs/backend/book/templates/emails/`` - Email templates **Type Definitions:** - ``wcs/backend/profiles/default/types/Library.xml`` - ``wcs/backend/profiles/default/types/Book.xml`` - ``wcs/backend/profiles/default/types/Chapter.xml`` - ``wcs/backend/profiles/default/types/Paragraph.xml``