Compare commits

..

3 Commits

10 changed files with 145 additions and 62 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
# DEFAULT_ADMIN_EMAIL = "admin@example.com"
# DEFAULT_ADMIN_PASSWORD = "password-is-generated-randomly-on-first-launch"
POSTGRES_HOST = "localhost"
POSTGRES_HOST = "db"
POSTGRES_PORT = "5432"
POSTGRES_USER = "postgres"
POSTGRES_PASSWORD = "postgres"
Vendored
+2
View File
@@ -1,3 +1,5 @@
.env
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
+24 -17
View File
@@ -1,22 +1,29 @@
FROM python:3.13 as requirements-stage
WORKDIR /tmp
RUN pip install poetry
RUN poetry self add poetry-plugin-export
COPY ./pyproject.toml ./poetry.lock* /tmp/
RUN poetry export -f requirements.txt --output requirements.txt --with dev --without-hashes
FROM python:3.12-slim
FROM python:3.13
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN apt-get update \
&& apt-get -y install gcc postgresql \
&& apt-get clean # netcat
RUN pip install --upgrade pip
WORKDIR /code
COPY --from=requirements-stage /tmp/requirements.txt ./requirements.txt
RUN pip install --no-cache-dir --upgrade -r ./requirements.txt
COPY . .
ENV PYTHONPATH=.
RUN apt-get update \
&& apt-get -y install gcc libpq-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN pip install poetry
RUN poetry config virtualenvs.create false
COPY ./pyproject.toml ./poetry.lock* /code/
RUN poetry install --with dev --no-root --no-interaction
COPY ./library_service /code/library_service
COPY ./alembic.ini /code/
COPY ./data.py /code/
RUN useradd app && chown -R app:app /code
USER app
ENV PYTHONPATH=/code
CMD ["uvicorn", "library_service.main:app", "--host", "0.0.0.0", "--port", "8000", "--forwarded-allow-ips=\"*\""]
+51 -17
View File
@@ -37,12 +37,12 @@
5. Запустите приложение:
```bash
docker compose up api
docker compose up api -d
```
Для создания новых миграций:
```bash
docker compose run --rm -T api alembic revision --autogenerate -m "Migration name"
alembic revision --autogenerate -m "Migration name"
```
Для запуска тестов:
@@ -50,6 +50,11 @@
docker compose up test
```
Для добавление данных для примера используйте:
```bash
python data.py
```
### **Эндпоинты API**
**Авторы**
@@ -100,37 +105,66 @@
```mermaid
erDiagram
AUTHOR {
int id PK "ID автора"
string name "Имя автора"
USER {
int id PK
string username UK
string email UK
string full_name
string password
boolean is_active
boolean is_verified
}
USER_ROLE {
int user_id FK
string role
}
LOAN {
int id PK
int book_id FK
int user_id FK
datetime borrowed_at
datetime due_date
datetime returned_at
}
BOOK {
int id PK "ID книги"
string title "Название книги"
string description "Описание книги"
int id PK
string title
string description
}
AUTHOR {
int id PK
string name
string bio
}
GENRE {
int id PK "ID жанра"
string name "Название жанра"
int id PK
string name
}
AUTHOR_BOOK {
int author_id FK "ID автора"
int book_id FK "ID книги"
int author_id FK
int book_id FK
}
GENRE_BOOK {
int genre_id FK "ID жанра"
int book_id FK "ID книги"
int genre_id FK
int book_id FK
}
AUTHOR ||--o{ AUTHOR_BOOK : "писал"
BOOK ||--o{ AUTHOR_BOOK : "написан"
USER ||--o{ USER_ROLE : "имеет роли"
USER ||--o{ LOAN : "берёт книги"
LOAN }o--|| BOOK : "выдача"
AUTHOR ||--o{ AUTHOR_BOOK : "пишет"
AUTHOR_BOOK }o--|| BOOK : "авторство"
BOOK ||--o{ GENRE_BOOK : "принадлежит"
GENRE ||--o{ GENRE_BOOK : "содержит"
GENRE_BOOK }o--|| BOOK : "жанр"
```
+1 -1
View File
@@ -3,7 +3,7 @@ from typing import Optional
# Конфигурация
USERNAME = "admin"
PASSWORD = "GzwQMe3j2DsPRKpL2DVw6A"
PASSWORD = "your-password-here"
BASE_URL = "http://localhost:8000"
+46 -11
View File
@@ -1,28 +1,63 @@
services:
db:
container_name: db
image: postgres:17
ports:
- 5432:5432
# volumes:
# - ./data/db:/var/lib/postgresql/data
container_name: db
restart: unless-stopped
logging:
options:
max-size: "10m"
max-file: "3"
volumes:
- ./data/db:/var/lib/postgresql/data
networks:
- proxy
env_file:
- ./.env
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
api:
container_name: api
build: .
command: bash -c "alembic upgrade head && uvicorn library_service.main:app --host 0.0.0.0 --port 8000 --reload"
container_name: api
restart: unless-stopped
command: bash -c "uvicorn library_service.main:app --host 0.0.0.0 --port 8000 --forwarded-allow-ips=\"*\""
logging:
options:
max-size: "10m"
max-file: "3"
networks:
- proxy
env_file:
- ./.env
volumes:
- .:/code
ports:
- "8000:8000"
# depends_on:
# - db
depends_on:
db:
condition: service_healthy
tests:
container_name: tests
build: .
command: bash -c "pytest tests"
restart: unless-stopped
logging:
options:
max-size: "10m"
max-file: "3"
networks:
- proxy
env_file:
- ./.env
volumes:
- .:/code
depends_on:
db:
condition: service_healthy
networks:
proxy: # Рекомендуется использовать через реверс-прокси
name: proxy
external: true
+2 -2
View File
@@ -96,8 +96,8 @@ async def book(request: Request, book_id: int):
return templates.TemplateResponse(request, "book.html")
@router.get("/auth", include_in_schema=False)
async def auth(request: Request):
@router.get("/auth", include_in_schema=False)
async def auth(request: Request):
"""Эндпоинт страницы авторизации"""
return templates.TemplateResponse(request, "auth.html")
+7 -2
View File
@@ -53,7 +53,12 @@ const Utils = {
};
const Api = {
getBaseUrl() {
return window.location.origin;
},
async request(endpoint, options = {}) {
const fullUrl = this.getBaseUrl() + endpoint;
const token = localStorage.getItem("access_token");
const headers = {
"Content-Type": "application/json",
@@ -67,14 +72,14 @@ const Api = {
const config = { ...options, headers };
try {
const response = await fetch(endpoint, config);
const response = await fetch(fullUrl, config);
if (response.status === 401) {
const refreshed = await Auth.tryRefresh();
if (refreshed) {
headers["Authorization"] =
`Bearer ${localStorage.getItem("access_token")}`;
const retryResponse = await fetch(endpoint, { ...options, headers });
const retryResponse = await fetch(fullUrl, { ...options, headers });
if (retryResponse.ok) {
return retryResponse.json();
}
Generated
+6 -6
View File
@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
[[package]]
name = "aiofiles"
@@ -1969,14 +1969,14 @@ files = [
[[package]]
name = "uvicorn"
version = "0.34.3"
version = "0.40.0"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.9"
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885"},
{file = "uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a"},
{file = "uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee"},
{file = "uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea"},
]
[package.dependencies]
@@ -2247,4 +2247,4 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = "^3.12"
content-hash = "a8d44f0decfa3ba437e998207c16ca7429ee42e930e8aa1d40f87231e71f219f"
content-hash = "6048c7b120fbeb4533a1e858a87eb09aec68e5da569ca821b9e41ecabf220a9e"
+2 -2
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "LibraryAPI"
version = "0.2.0"
version = "0.3.0"
description = "Это простое API для управления авторами, книгами и их жанрами."
authors = ["wowlikon"]
readme = "README.md"
@@ -9,11 +9,11 @@ packages = [{ include = "library_service" }]
[tool.poetry.dependencies]
python = "^3.12"
fastapi = { extras = ["all"], version = "^0.115.12" }
uvicorn = { extras = ["standard"], version = "^0.40.0" }
psycopg2-binary = "^2.9.10"
alembic = "^1.16.1"
python-dotenv = "^0.21.0"
sqlmodel = "^0.0.24"
uvicorn = "^0.34.3"
jinja2 = "^3.1.6"
toml = "^0.10.2"
python-jose = {extras = ["cryptography"], version = "^3.5.0"}