Этот проект является API библиотекой и решает круг типичных задач любой библиотеки. Какие задачи решает:
- Облегчает поиск нужных книг
- Увеличивает поток читателей
- Улучшает популярность библиотеки
- Уменьшает количество физических поситителей
- Разгружает библиотекаря
- Упрощает учет книг
- Упрощает отслеживание выданных книг
В проекте используется Брокер сообщений Redis и воркер Celery
redis:
image: redis:7.2.5-alpine
expose:
- 6379
celery_worker:
build:
context: .
dockerfile: ./docker/django/Dockerfile
image: config
command: /start-celeryworker
volumes:
- .:/app
env_file:
- .env
celery_beat:
build:
context: .
dockerfile: ./docker/django/Dockerfile
image: config
command: /start-celerybeat
volumes:
- .:/app
env_file:
- .env
# settings.py
INSTALLED_APPS = [
'django_celery_beat',
]
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER")
CELERY_RESULT_BACKEND = os.environ.get("CELERY_BACKEND")
CELERY_RESULT_EXTENDED = True
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
CELERY_BEAT_SCHEDULER = os.environ.get('DEFAULT_DATABASE_BEAT')
STANDART_HOUR_TO_TASK = 8
STANDART_MINUTE_TO_TASK = 0
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
app = Celery('config')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# Менеджер для работы Celery
# Создание переодической задачи
instance = <Order>
task_manager = TaskManager(instance)
task_manager.start_periodic_task()
# Обновление переодической задачи
instance = <Order>
task_manager = TaskManager(instance)
task_manager.update_periodic_task()
# Удаление переодической задачи
instance = <Order>
task_manager = TaskManager(instance)
task_manager.delete_periodic_task()
# Запуск мнгновенной задачи
instance = <Order>
TaskManager.launch_task(
instance,
'path/to/html.html',
)
Автоматизированный Кэш
# settings.py
INSTALLED_APPS = [
'cachalot',
]
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': os.environ.get('REDIS_CACHE'),
}
}
Использование данного функционала полностью автоматизированно.
Проверка доступа к данном API извне посредством инспекции Headers.
# settings.py
INSTALLED_APPS = [
'corsheaders',
]
CORS_ALLOWED_ORIGINS = ['http://localhost:8000']
CSRF_TRUSTED_ORIGINS = ['http://localhost:8000']
CORS_ALLOW_ALL_ORIGINS = False
Использование данного функционала полностью автоматизированно.
JWT токен позволяет производить аутентификацию и авторизацию на очень высоком уровке безопасности.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(hours=1)
}
# urls.py
from rest_framework_simplejwt.views import (TokenObtainPairView,
TokenRefreshView)
urlpatterns = [
path('api/token/',
TokenObtainPairView.as_view(),
name='token_obtain_pair',
),
path('api/token/refresh/',
TokenRefreshView.as_view(),
name='token_refresh',
),
]
Для аутентификации необходимо перейти на энд поинт по назначеному адрессу и ввести логин и пароль. При правильных данных выводится JWT Bearer токен который необходимо использовать для авторизации.
Автогенерация документации на основе Энд поинтов, моделей, сериализаторов. Используется библиотека YASG.
# settings.py
INSTALLED_APPS = [
'drf_yasg',
]
SWAGGER_SETTINGS = {
'VALIDATOR_URL': 'http://127.0.0.1:8000'
}
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="EasyLibrary",
default_version='v1',
description="This documentation is say, how to use API servise",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="[email protected]"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path('redoc/', schema_view.with_ui('redoc', cache_timeout=0),
name='schema-redoc'),
]
Для получения документации по данному проекту необходимо перейти на адресс: http://localhost/redoc/ На данном адрессе вы найдете всю необходимую исчерпывающую информацию о каждом элементе и объекте проекта.
- ValidatorSetPasswordUser
- YearValidator
- VolumeValidator
- PublishedValidator
- OrderRepeatValidator
- BookQuantityValidator
- ExtensionValidator
- SomeUserValidator
- ResponseValidator
- CountExtensionsValidator
- IsActiveOrderValidator
# Проверка корректности паролей
values = dict(password1='password', password2='password')
validator = ValidatorSetPasswordUser('password1', 'password2')
validator(values)
# Проверка корректности года публикации
# Если книга опубликована, год не может быть больше чем текущий.
value = dict(year_published=2020, is_published=True)
validator = YearValidator('year_published', 'is_published')
validator(value)
# Проверка корректности тома
# Если указан том, необходимо так же указать номер.
# Будет совершена проверка в рамках того что в данном томе
# еще не присутсвует данный номер.
volume = <Volume>
value = dict(volume=volume, num_of_volume=1)
validator = VolumeValidator('volume', 'num_of_volume')
validator(value)
# Проверка корректности данных исходя из статуса публикации.
# Если книга не опубликована она не может иметь тираж.
# Если книга не опубликована она не может быть лидером продаж.
value = dict(
best_seller=True,
circulation=10000,
is_published=True,
)
validator = PublishedValidator(
'best_seller',
'circulation',
'is_published',
)
validator(value)
# Проверка выдачи книги.
# Если книга уже была выдана пользователю, то
# данный валидатор не даст снова ее выдать.
book = <Book>
value = dict(book=book)
validator = OrderRepeatValidator('book')
validator(value)
# Проверка количества книг.
# Если книг на складе больше нет, тогда выдать ее не получится.
book = <Book>
value = dict(book=book)
validator = BookQuantityValidator('book')
validator(value)
# Контроль запросов на продление.
# Данный валидатор проверяет что запросов на продление
# еще нет, а так же если есть тогда они должны быть обработаны,
# в ином случае пользователю стоит подождать ответа на запрос.
order = <Order>
value = dict(order=order)
validator = ExtensionValidator('order')
validator(value)
# Проверка пользователя.
# Пользователь может подавать запрос на продление
# только своего заказа книги.
order = <Order>
value = dict(order=order)
validator = SomeUserValidator('order')
validator(value)
# Проверка состояния запроса.
# Если по запросу был дан ответ, тогда выдать
# повторно ответ уже не получится.
value = dict(solution='wait')
validator = ResponseValidator('solution')
validator(value)
# Проверка количество продлений.
# Если количество продлений заказа
# уже на границе установленного уровня, тогда подать
# запрос больше не получится.
order = <Order>
value = dict(order=order)
validator = CountExtensionsValidator('order')
validator(value)
# Проверка статуса книги.
# Если книга уже была возвращена, тогда
# заявление больше подать не получится.
order = <Order>
value = dict(order=order)
validator = IsActiveOrderValidator('order')
validator(value)
HandleCreateUser
# Создание пользователя
# User - модель пользователя
user = HandleCreateUser(User,
validated_data,
)
user.create()
- Администратор
- Библиотекарь
- Пользователь
- Анонимный пользователь
- Администратор может делать все и только он может создавать библиотекаря.
- Библиотекарь может взаимодействовать так же со всей системой, но по опеределенным правилами.
- Пользователь может только просматривать все таблицы, а так же брать книги если они есть в наличии и создавать заявки на продление выданной книги.
- Анонимный пользователь может только просматривать таблицы, не каких других действий он не может совершать.
- Самое главное, Администратор может создавать библиотекаря и только он.
- Все остальное.
- Cоздавать, просматривать, редактировать, удалять Книги.
- Cоздавать, просматривать, редактировать, удалять Авторов.
- Cоздавать, просматривать, редактировать, удалять Издателей.
- Cоздавать, просматривать, редактировать, удалять Тома.
- Cоздавать, просматривать, редактировать, удалять Жанры.
- Открывать, просматривать, закрывать Выдачу книг.
- Открывать, просматривать, принимать, отказывать заявки на Продление книг.
- Создавать, редактировать, удалять любых пользователей включая себя.
- Открывать, просматривать, Выдачу книг.
- Открывать, просматривать, заявку на Продление книг.
- Создавать, просматривать, редактировать, удалять свой профиль.
- Все остальное.
- Просматривать Книги, Авторов, Издателей, Жанры, Тома.
- Все остальное.
- Если книга опубликована - год ее написания не может быть больше ТЕКУЩЕГО.
- Если книга не была опубликована - год ее написания может быть больше ТЕКУЩЕГО.
- Если книга не была опубликована - она не может быть ЛИДЕРОМ продаж.
- Если книга не была опубликована - она не может иметь ТИРАЖ.
- Если у книги есть том - должен быть и номер присущей этой книги в ТОМЕ.
- Поля обязательные: author, publisher, name, age_restriction, count_pages, year_published, genre, circulation.
- Поля имя и фамилия обязательны.
- Поля имя и фамилия должны быть уникальной комбинацией.
- Все поля обязательны.
- Имя, телефон, Эмеил, URL, должны быть уникальны (то есть не повторяться).
- Все поля обязательны.
- Все поля обязательны.
- Нельзя выдать одну и ту же книгу тому же пользователю, если книга до сих пор не была возвращена.
- Нельзя выдать книгу, если количество книг в библиотеке уже 0.
- Нельзя запросить продление, если заявление уже было подано и оно до сих пор в статусе "wait" (то есть еще не было обработано библиотекарем).
- Пользователь может открывать заявление только на свои книги которые были ему выданы.
- Можно открывать заявления только на активную выдачу книги (то есть на ту которая еще не была возвращена).
- Нельзя открывать заявление, если количество продлений уже 2 (можно продлевать только 2 раза).
- Одно заявление можно обработать только один раз, если статус заявление не 'wait' больше отвечать нельзя.
DB_PASSWORD=password # Пароль Базы данных (использование).
POSTGRES_PASSWORD=password # Пароль Базы данных (настройка).
YANDEX_HOST_USER=host # Эмеил от имени которого будет рассылка.
YANDEX_PASSWORD_HOST=password # Пароль от Эмеила.
Проект находится под контролем системы контеризации Docker.
docker-compose build
docker-compose up
Для проведения тестов вам нужно попасть внутрь основного контейнера
docker exec -it config bash
Если выходит ошибка попробуйте
docker exec -it config bin/bash
Затем запустить тесты
python manage.py test
У вас будет выполнено множество тестов.
- http://localhost/api/book/list/ GET - просмотр списка книг.
- http://localhost/api/book/retrieve/"some_book_number"/ GET - просмотр книги.
- http://localhost/api/book/create/ POST - создание книги.
- http://localhost/api/book/update/"some_book_number"/ PATCH - обновление книги.
- http://localhost/api/book/delete/"some_book_number"/ DELETE - удаление книги.
- http://localhost/api/author/list/ GET - просмотр списка авторов.
- http://localhost/api/author/retrieve/"some_author_number"/ GET - просмотр автора.
- http://localhost/api/author/create/ CREATE - создание автора.
- http://localhost/api/author/update/"some_author_number"/ PATCH - обновление автора.
- http://localhost/api/author/delete/"some_author_number"/ DELETE - удаление автора.
- http://localhost/api/publisher/list/ GET - просмотр списка издателей.
- http://localhost/api/publisher/retrieve/"some_publisher_number"/ GET - просмотр автора.
- http://localhost/api/publisher/create/ CREATE - создание издателя.
- http://localhost/api/publisher/update/"some_publisher_number"/ PATCH - обновление автора.
- http://localhost/api/publisher/delete/"some_publisher_number"/ DELETE - удаление автора.
- http://localhost/api/volume/list/ GET - просмотр списка томов.
- http://localhost/api/volume/retrieve/"some_volume_number"/ GET - просмотр тома.
- http://localhost/api/volume/create/ CREATE - создание тома.
- http://localhost/api/volume/update/"some_volume_number"/ PATCH - обновление тома.
- http://localhost/api/volume/delete/"some_volume_number"/ DELETE - удаление тома.
- http://localhost/api/genre/list/ GET - просмотр списка жанров.
- http://localhost/api/genre/retrieve/"some_genre_number"/ GET - просмотр жанра.
- http://localhost/api/genre/create/ CREATE - создание жанра.
- http://localhost/api/genre/update/"some_genre_number"/ PATCH - обновление жанра.
- http://localhost/api/genre/delete/"some_genre_number"/ DELETE - удаление жанра.
- http://localhost/api/order/open/"some_book_number"/ CREATE - открытие выдачи книги.
- http://localhost/api/order/close/"some_order_number"/ DELETE - закрытие выдачи книги.
- http://localhost/api/order/retrieve/"some_order_number"/ GET - просмотр выдачи.
- http://localhost/api/order/list/ GET - просмотр списка выдач.
- http://localhost/api/extension/open/"some_order_number"/ CREATE - открытие заявление на продление.
- http://localhost/api/extension/accept/"some_extension_number"/ PATCH - принятие продления.
- http://localhost/api/extension/cancel/"some_extension_number"/ PATCH - отказ от продления.
- http://localhost/api/extension/retrieve/"some_extension_number"/ GET - просмотр заявления.
- http://localhost/api/extension/list/ GET - просмотра списка заявлений.
Проект состоит из ~2800 строк кода не считая тестов.
Тестов 101 штука. Тестов написанно ~2500 строк кода.
В дальнейшей работе есть цель улучшить оптимизацию.
Улучшения связанные с программой могут быть:
- Добавление таблицы "Редакция".
- Добавление таблицы "Должники" для санкций и штрафов.
- Внедрение посторонего API для оплаты штрафов например: Stripe.
- Логика связанная с снятием санкий по сигналу оплаты.
- Онлайн книги.
- Аудио книги.