# Booklab API

[TOC]

# booklab

Main python package for Booklab system.

Consists of the following components:

- `booklab_cli` main CLI application to operate the system
- `booklabd` designed to serve `/api/.../` routes used by all functionalities that need write / update and POST operations
- `conf` contain configuration files for different system components including infrastructure ones like gunicorn or nginx
- `doc_src` contain the source of static site directory as Markdown files
- `docs` contain rhe static site compiled and "ready to use as-is" with any standard HTTP server
- `my_books` contain the end user created & generated books and `books_catalog.json` with info about all user books
- `scripts` contain diffrent scrpts usefull in system administrarion (install, maintain, configure, in-house development and customizations)
- `booklab.pyz`as standard Python PEX package

Package is compliant with Python PEP packaging specificatios and published on PyPi under `booklab` name.
Package is open source licenced and available as source package on GitHub under `booklab` name and author repositories.

author: Petre Iordanescu (_mail:_ petre.iordanescu@gmail.com, _GitHub:_ petre-renware)

<a id="booklab.booklab_cli"></a>

# booklab.booklab\_cli

Booklab CLI module to assure system operatins as command line.

Usage:

    booklab -v
    booklab setup <options>
    booklab init <options>
    booklab server (run|stop|restart)
    booklab catalog
    booklab status <my-book>
    booklab new
    booklab build <my-book>
    booklab preview <my-book>
    booklab deploy <my-book>
    booklab page-edit <my-book>
    booklab page-upload <my-book>
    booklab page-upload <my-book>
    vooklab edit-nav[igation] <my-book>
    booklab pack <my-book>

Options:

    -l, --list    List books catalog
    -s, --status  Display detailes about a book
    -v, --version Display booklab application version

Architecture; Linux standard (POSIX) CLI implemented over "Typer" framework.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.booklab_cli.cmd_xxx"></a>

# booklab.booklab\_cli.cmd\_xxx

Command xxx definition.

<a id="booklab.booklab_cli.param_types"></a>

# booklab.booklab\_cli.param\_types

Define parameters used by CLI app.

Parameters annotated definition as used by
`Typer` framework as parameters in components
and described through `Annotated` class.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.booklab_cli.param_types.UserId"></a>

#### UserId

`UserId` type used for ...xxx...

<a id="booklab.booklab_cli.param_types.param_x"></a>

#### param\_x

`param_x` of str type and  Annotated rype used for ...xxx...

<a id="booklab.booklab_cli.param_types.get_user_name"></a>

#### get\_user\_name

```python
def get_user_name(user_id: UserId) -> str
```

Test & proof of concept for new rype usage.

<a id="booklab.conf"></a>

# booklab.conf

Cnfigurations component contains various system components configuration files:

- `gunicorn` WSGI web server
- `nginx` local proxy HTTP

Notes / remarks:

- files wirh `.py` extension are considered Python files and can be imported accordingly as longas they are valid Python-code.
- all files from here are assumed to be _text files_. Any deviation from this rule is assumed to be treated accordingly in code.

Author; Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.conf.gunicorn_config"></a>

# booklab.conf.gunicorn\_config

Configuration file for gunicorn in serving `booklabd` server application

This is a Python file that will be executed by gunicorn at run-time.
As consequence declare all assignements as valid Python code.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.conf.gunicorn_config.reload"></a>

#### reload

Specify to reload gunicorn if code under scope change. Need a "file change notifier" to be active - see gunicorn documentation for details.

<a id="booklab.conf.gunicorn_config.user"></a>

#### user

User under authority to run gunicorn. Set as "app". In not set root user will be considered.

<a id="booklab.conf.gunicorn_config.wsgi_app"></a>

#### wsgi\_app

The application module:object to be executed by gunicorn at load.

<a id="booklab.conf.gunicorn_config.all_cfg"></a>

#### all\_cfg

All configuration variables as dictionary.

<a id="booklab.conf.booklab_ext_url"></a>

# booklab.conf.booklab\_ext\_url

This Python file contains external access URL information.
By external access is understood all URL parts necessary to expose Booklab application:

* EXT_SERVER - the external exposed server name and port if diffrent than standard default (80 or 443) (example: "booklab.mydomain.ro")
* EXT_PATH - the external exposed URL of configured start locations through a LAN main proxy (example: "/booklab/" for a complete external URL like http://booklab.mydomain.ro:5002/booklab/)

_NOTE: all information are of string type_

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.my_books.book_template"></a>

# booklab.my\_books.book\_template

Contains the book template used when create a new book (`newb` funxtion, `/api/newb/` booklabd route).

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.my_books"></a>

# booklab.my\_books

This component contains all defined books as individual directories, each one with all definions initiated from `book_template/` directory

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.my_books.books_manager"></a>

# booklab.my\_books.books\_manager

<a id="booklab.my_books.books_manager.Results"></a>

## Results Objects

```python
@dataclass(frozen = True)
class Results()
```

Define a result model (type) frequently used as return set by MyBook methods.

Class as data type (model) is defined _frozen_ to protect change its instance
attribites once created. This is usefull when used as member in other
objects to protect them to be altered outside the object.

<a id="booklab.my_books.books_manager.Results.exit_code"></a>

#### exit\_code

Exit code of run method. Usual is the same as method returns.

<a id="booklab.my_books.books_manager.Results.exit_text"></a>

#### exit\_text

Output text of last run method (equivalent of stdout when run a console process).

<a id="booklab.my_books.books_manager.Results.console_out"></a>

#### console\_out

```python
@property
def console_out() -> None | str
```

Return `exit_text` rendered to console format as printed on a simple usual / dumb terminal.

<a id="booklab.my_books.books_manager.MyBooks"></a>

## MyBooks Objects

```python
class MyBooks()
```

Class that manage end user books.

- _Mandatory requirements:_
    - _rendering:_ any Jinja renderings will be made 
      "from string" (ie, using Flask `render_from_string()` which is included)
      or by creating a local Jinja environment.

<a id="booklab.my_books.books_manager.MyBooks.MY_BOOKS_URL_prefix"></a>

#### MY\_BOOKS\_URL\_prefix

URL prefix to add when accesing a book local (generated) site.

<a id="booklab.my_books.books_manager.MyBooks.MY_BOOK_URL"></a>

#### MY\_BOOK\_URL

Instantiated book URL to local (generated) site.

<a id="booklab.my_books.books_manager.MyBooks.MY_BOOKS_ROOT"></a>

#### MY\_BOOKS\_ROOT

Confusing name ? just duplicate the global one in class namespace.

<a id="booklab.my_books.books_manager.MyBooks.book_code"></a>

#### book\_code

Instanciated book code.

<a id="booklab.my_books.books_manager.MyBooks.db_books_catalog"></a>

#### db\_books\_catalog

Books catalog data controller.

<a id="booklab.my_books.books_manager.MyBooks.db_book_nav"></a>

#### db\_book\_nav

Books navigation data controller.

<a id="booklab.my_books.books_manager.MyBooks.jinja_env"></a>

#### jinja\_env

Jinja environment usable for my_books rendering needs.

<a id="booklab.my_books.books_manager.MyBooks.results"></a>

#### results

Keep result of last run method (for methods that should return composite result).

<a id="booklab.my_books.books_manager.MyBooks.__init__"></a>

#### \_\_init\_\_

```python
def __init__(db: pysondb, book_code: str) -> None
```

Init an instance of class MyBooks.

<a id="booklab.my_books.books_manager.MyBooks.getBook"></a>

#### getBook

```python
def getBook() -> dict | None
```

Check for a given book code that is not None, exists in database and is exactly 1 record.

**Returns**:

- `dict` - with found record or
- `None` - if any of conditiona is not met

<a id="booklab.my_books.books_manager.MyBooks.getBookNav"></a>

#### getBookNav

```python
def getBookNav(format: str = None) -> None | dict | str
```

Get book navigation.

Navigation info is retrieved from `book_navigation.json` data-file
and is identified by `self.db_book_nav` pysondb handler.

**Returns**:

- `dict` - using `format = "dict"` (default option)
- `str` - JSON string using `format = "json"`
- `str` - YAML string using `format = "yaml"`
- `None` - if not known format

<a id="booklab.my_books.books_manager.MyBooks.wrBookNav"></a>

#### wrBookNav

```python
def wrBookNav() -> bool
```

Write out file "book_navigation.yml".

**Returns**:

- `True` - if file was written
- `False` - if file was not written or cannot be read regardless why (usual problem is source file)
  
  _Lateral effects:_
  
  - _on disk:_ create / update current book navigation definition file in YAML format (`book_navigation.yml`).

<a id="booklab.my_books.books_manager.MyBooks.getBookPath"></a>

#### getBookPath

```python
def getBookPath() -> str
```

Get absolute path of current book root directory.

<a id="booklab.my_books.books_manager.MyBooks.getBookURL"></a>

#### getBookURL

```python
def getBookURL() -> str
```

Get preview URL (redirectable as is) for current book_code.

<a id="booklab.my_books.books_manager.MyBooks.renderBookConfig"></a>

#### renderBookConfig

```python
def renderBookConfig() -> Results
```

Render current book configuration file.
Produce file `mkdocs.yml` as being the configuration file to build the book.
File is writen in book root directory.

**Returns**:

  
  - `Results object` reference to `self.results`
  
  _Lateral effects:_
  
  - _on disk:_ update current book configuration file (`mkdocs.yml`).

<a id="booklab.my_books.books_manager.MyBooks.buildBook"></a>

#### buildBook

```python
def buildBook() -> None | str
```

Build (mkdocs build) current boook.

Build current book (ie, `mkdocs build`) in its own directory.
Method suppose that mkdocs.yml file is good and book content directory (doc_src/) content is ok and "as-expected",
that meaning the method just run nkdocs build process, collect output and return it.

**Returns**:

  
  - `str` stdout + stderr of run process
  - `None` if process exit with fatal err (standard baah return 1)
  
  _Lateral effects:_
  
  - _on disk:_ create / update current book static site directory (usual `docs/`).

<a id="booklab.my_books.books_manager.MyBooks.createPhysicalBook"></a>

#### createPhysicalBook

```python
def createPhysicalBook() -> bool
```

Create physical book directory as copy of "book_template".

_Lateral effects:_

- _on disk:_ creates new directory & filrs on disk represing current book physical location.

<a id="booklab.doc_src"></a>

# booklab.doc\_src

Booklab master static site:

* `doc_src/` markdown source files
* `docs/` generated static site ready to be used as is with any standard HTTP server

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.scripts"></a>

# booklab.scripts

Booklab utility scripts that solve various aspects in installing, configuring and running Booklab system / application.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.__version__"></a>

# booklab.\_\_version\_\_

**__version__.py** module that contains Booklab aplication version number.

NOTE: this module is imported and made "public" in `booklab._init__.py`

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.booklabd.publisher"></a>

# booklab.booklabd.publisher

<a id="booklab.booklabd.publisher.publish"></a>

#### publish

```python
def publish()
```

Decorator the publishes the Flask function, wiring up arguments to the incoming request.

The function arguments are inspected and used to extract the values from the request
GET/POST data (via request.values).  If type annotations are specified, the incoming
values will be instantiated as that type.  If "**kwargs" is included, remaining GET/POST
values are placed there, otherwise they are ignored.

**Example**:

  
  @app.route("/somewhere")
  @publish()
  def somewhere(gender:str, age:int=None):
  return jsonify(gender=gender, age=age)

<a id="booklab.booklabd.routes"></a>

# booklab.booklabd.routes

Module that serve `booklabd` interface api-functions as HTTP routes

Important variables:

- `booklab.boolabd.api_app`: web application object (aka Flask.app)

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.booklabd.routes.api_newb"></a>

#### api\_newb

```python
@api_app.route("/api/newb/")
def api_newb()
```

Serve _New book (newb)_ functionality.

<a id="booklab.booklabd.routes.api_bstatus"></a>

#### api\_bstatus

```python
@api_app.route("/api/bstatus/")
def api_bstatus(book_code: str = ...)
```

Serve _Book status (bstatus)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_edtb"></a>

#### api\_edtb

```python
@api_app.route("/api/edtb/")
def api_edtb(book_code: str = ...)
```

Serve _Book edit (edtb)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_orgm"></a>

#### api\_orgm

```python
@api_app.route("/api/orgm/")
def api_orgm(book_code: str = ...)
```

Serve _Book structure & navigation organization (orgm)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_prvb"></a>

#### api\_prvb

```python
@api_app.route("/api/prvb/")
def api_prvb(book_code: str = ...)
```

Serve _Book preview (prvb)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_bbld"></a>

#### api\_bbld

```python
@api_app.route("/api/bbld/")
def api_bbld(book_code: str = ...)
```

Serve _Book build (bbld)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_dplb"></a>

#### api\_dplb

```python
@api_app.route("/api/dplb/")
def api_dplb(book_code: str = ...)
```

Serve _Book delivery (dplb)_ functionality.

**Query parameters:** `code` for database `boook_code`

<a id="booklab.booklabd.routes.api_bcat"></a>

#### api\_bcat

```python
@api_app.route("/api/bcat/")
def api_bcat()
```

Serve _Books catalog (bcat)_ functionality.

<a id="booklab.booklabd.routes.version"></a>

#### version

```python
@api_app.route("/api/version/")
def version()
```

Return Booklab application version as pure plain raw text (no html).

<a id="booklab.booklabd.routes.index"></a>

#### index

```python
@api_app.route("/")
def index()
```

Serve accessing Home route.
This route is an alternate option way (but usually the expected one from an end user) to access static site main / home page.

<a id="booklab.booklabd.routes.about"></a>

#### about

```python
@api_app.route("/api/about/")
def about()
```

Construct and request for "About Booklab" page.

<a id="booklab.booklabd.app_init"></a>

# booklab.booklabd.app\_init

**app_init** module that initialize `booklabd` application

This module is designed to initialize the main web application object `api_app`.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.booklabd.app_init.init_app"></a>

#### init\_app

```python
def init_app(app_name: str, static_site_dir: str, templates_dir: str,
             pjroot_location: str) -> Flask
```

Create Flask application object and return it

**Arguments**:

  
- ``app_name`` - name of web application objwcr
- ``static_site_dir`` - directory used by Flask app to render Jinja templates
- ``templates_dir`` - directory name where templates are to becfound (relative to pjroot_location)
- ``pjroot_location`` - project root directory (relative to pjroot_location)
  

**Returns**:

  
  web application object

<a id="booklab.booklabd"></a>

# booklab.booklabd

booklabd - Booklab API server module

Main functionalities:
* operate & manage JSON database file
* provide necessary http API routes fir book functionalities that need write & dynamic (run-time) behavior

Architecture; HTTP WSGI

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.docs"></a>

# booklab.docs

Booklab master static site:

* `doc_src/` markdown source files
* `docs/` generated static site ready to be used as is with any standard HTTP server

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.__main__"></a>

# booklab.\_\_main\_\_

Module "entry point" for `booklab` package.

Callable with `python -m` option and defined as executable script with the
package.

Usage:

``` bash
pip install booklab
booklab [options, commands, ...]
```

<a id="booklab.__main__.main"></a>

#### main

```python
def main()
```

Main entry point in Booklab application.

<a id="booklab.db_init"></a>

# booklab.db\_init

Module that initialize `booklabd` database (more JSON files)

This module is designed to initialize database objects `db_books` and `db_system`.

Author: Petre Iordanescu (petre.iordanescu@gmail.com)

<a id="booklab.db_init.init_db"></a>

#### init\_db

```python
def init_db() -> tuple[pysondb]
```

Create db_books, db_system objects and return them as tuple

**Returns**:

  
  `(db_books, db_system)` tuple of pysondb object

