find-frend / find_friend_backend

2 stars 3 forks source link

workflow

Бэкенд приложения "Найди друга"

Знакомства с новыми людьми, поиск людей с общими интересами и организация совместных мероприятий

Структура проекта:

Имя Описание
src Файлы для backend разработки
infra Docker-compose файлы для запуска проекта с помощью Docker

Подключенные приложения:

  1. Users - отвечает за создание пользователей
  2. Api - вспомогательное приложение для api

Правила работы с git (как делать коммиты и pull request-ы):

  1. Две основные ветки: main и develop
  2. Ветка develop — “предрелизная”. Т.е. здесь должен быть рабочий и выверенный код
  3. В main находится только production-ready код (CI/CD)
  4. Создавая новую ветку, наследуйтесь от ветки develop
  5. Правила именования веток
    • весь новый функционал — feature/название-функционала
    • исправление ошибок — bugfix/название-багфикса
  6. Пушим свою ветку в репозиторий и открываем Pull Request

Добавление пакетов в requireremens.txt

При установке пакетов не забывайте добавлять их в requirements.txt! Если устанавливаемый вами пакет нужен только на этапе разработки и не требуеся на боевом сервере, прописывайте зависимость в requirements-dev.txt!

Запуск приложения:

!!! ИНСТРУКЦИЯ ДЛЯ ЭТАПА РАЗРАБОТКИ !!!

Для локальной разработки нужно:

  1. Клонировать репозиторий и перейти в директорию:
git clone git@github.com:find-frend/find_friend_backend.git
cd find_friend_backend/
  1. Создать и активировать виртуальное окружение:
python -m venv venv                      # Устанавливаем виртуальное окружение
source venv/scripts/activate             # Активируем (Windows); или
source venv/bin/activate                 # Активируем (Linux)
python -m pip install --upgrade pip      # Обновляем менеджер пакетов pip
pip install -r src/requirements-dev.txt  # Устанавливаем пакеты для разработки
  1. Установить пре-коммит хуки:
pre-commit install
  1. Создать файл .env с переменными окружения из .env.example. Пример наполнения - непосредственно в .env.example. Значение DEBUG при локальной разработке (в т.ч. для запуска дев сервера через python manage.py runserver) должно быть True.Для локальной разработки параметры DB не нужны, т.к. используется SQLite. Параметр DJANGO_ALLOWED_HOSTS можно закомментировать. Вот как выглядит .env для разработки:
DEBUG=True
DJANGO_SECRET_KEY=somegeneratedsecretkey

Для запуска приложения в контейнерах необходимо:

  1. Заполнить .env:
DEBUG=False

DJANGO_SECRET_KEY=somegeneratedsecretkey

# Выставляем так, как ниже
DJANGO_ALLOWED_HOSTS=127.0.0.1 localhost backend 158.160.60.2

DB_ENGINE=django.db.backends.postgresql_psycopg2
POSTGRES_DB=findafriend
POSTGRES_USER=postgresusername
POSTGRES_PASSWORD=postgresuserpassword
DB_HOST=db
DB_PORT=5432
  1. Перейти в директорию с файлом docker-compose.dev.yaml, открыть терминал и запустить docker-compose с ключом -d:
cd infra/dev/
docker compose -f docker-compose.dev.yaml up -d
  1. Выполнить миграции:
docker compose -f docker-compose.dev.yaml exec backend python manage.py migrate
  1. Создать суперюзера:
docker compose -f docker-compose.dev.yaml exec backend python manage.py createsuperuser
  1. Собрать статику:
docker compose -f docker-compose.dev.yaml exec backend python manage.py collectstatic --no-input
  1. После успешного запуска проект станет доступен по адресу: http://localhost/api - Корень api http://localhost/admin - Админка Django

  2. Остановить проект:

docker compose -f docker-compose.dev.yaml down
  1. Если необходимо пересобрать контейнеры после изменений в проекте:
docker compose -f docker-compose.dev.yaml up -d --build

Регистрация и авторизация пользователей

Авторизация реализована с помощью токенов: пользователь регистрируется с емейлом и паролем, отдельным запросом получает токен, затем этот токен передаётся в заголовке каждого запроса.

Уровни доступа пользователей:

Что могут делать неавторизованные пользователи

Что может делать администратор Администратор обладает всеми правами авторизованного пользователя. Плюс к этому он может:

Эти функции реализованы в стандартной админ-панели Django.

Спецификации API в файле openapi-schema.yml в папке docs

Также документация API доступна по адресам:

Чат

Чат реализован на веб-сокетах для поддержки двухстороннего обмена данными с клиентом и асинхронных расширениях Django Channels для создания таких каналов передачи информации.

Использование веб-сокетов предполагает поддержку асинхронных вызовов со стороны процесса, обрабатывающего веб-запросы, поэтому для публикации используется протокол asgi. В нашем случае мы используем сервер daphne.

Эндпоинты и логика

Доступны следующие эндпоинты:

Стандартные HTTP эндпоинты, обрабатываются WSGI сервером:

{
    "id": 3,
    "initiator": {
        "email": "testuser1@fake.org",
        "first_name": "Тестодин",
        "last_name": "Юзеродин",
        "age": 23,
        "city": null
    },
    "receiver": {
        "email": "testuser2@fake.org",
        "first_name": "Тестдва",
        "last_name": "Юзердва",
        "age": 23,
        "city": null
    },
    "chat_messages": []
}

Websocket эндпоинт, обрабатывается ASGI сервером:

При подключении к чату из базы подгружаются последние сообщения в чате (по умолчниаю 30, число настраивается).

Тестирование работы чатов

Прежде всего необходимо, чтобы в базе были два пользователя с токенами аутентификации. Эти пользователи должны быть в друзьях друг у друга. Для примера user1@fake.org и user2@fake.org. Затем нужно создать новый чат (см. выше) - будучи залогиненным как user1, отправить POST запрос на /api/v1/chats/start/ с email'ом user2. После получения id чата можно приступать к тестированию непосредственно чата на вебсокете.

Для тестирования будем использовать Postman.

Начнем с создания нового запроса:

img

По умолчанию создается HTTP запрос. Необходимо изменить тип на Websocket:

img

Сохраняем запрос: Save -> Request name "User 1" -> Внизу слева New Collection -> Название коллекции "Find Friend" -> Save.

Коллекция появляется в списке коллекций, в ней пока один запрос User 1.

Нажимаем на коллекцию, котрывается окно с двумя вкладками: Overview и Variables. Нам нужна вкладка Variables. Там добавляем новую переменную baseUrl, в Initial value и Current value прописываем ws://127.0.0.1:8000/ws/chat. Сохраняем (Ctrl + S).

Прописываем еще две переменных - authToken1 и authToken2. Значениями должны быть токены аутентификации, полученные при создании юзеров. Сохраняем.

Должно получиться вот так:

img

Теперь настроим запрос User 1.

В поле Enter URL вводим {{baseUrl}}/1/ (где 1 - это id чата, присвоенный ему базой данный при создании чата).

Переходим на вкладку Headers, добавляем новый Key Authorization со значением Token {{authToken1}}. Сохраняем (Ctrl + S).

Теперь делаем дубликат запроса и переименовываем его в User 2(правой кнопкой по запросу -> Duplicate -> Правой кнопкой по дубликату -> Rename).

В настроках User 2 переходим в Headers, меняем Value на Token {{authToken2}}, сохраняем (Ctrl + S).

Для работы чатов требуется Redis. Запускаем его в докере: docker run -d -p 6379:6379 redis.

Запускаем локальный dev-сервер (python manage.py runserver), если еще не запущен. При запуске в логах должна быть срочка Starting ASGI/Daphne version 4.1.0 development server at http://127.0.0.1:8000/. Это свидетельствует о том, что командой runserver теперь управляет daphne, что и позволит нам установить websocket соединение.

Теперь в обоих запросах нажимаем на кнопку Connect. Внизу в разделе Response для обоих юзеров должно отобразиться Connected to ws://127.0.0.1:8000/ws/chat/1/ с зеленой галочкой и статус Connected.

Теперь можно написать первое сообщение от имени User 1, любой текст (просто текст, не JSON), и нажать на кнопку Send. Сообщение появится внизу в разделе Response в виде JSON с id и прочими атрибутами. В этот момент оно уходит в базу.

Если теперь перейти в User 2, это сообщение появится и у него. Если появилось, значит, всё ОК. Можно поотправлять сообщения с разных юзеров, и они все должны появляться у обоих.

Можно теперь отключиться от вебсокета (кнопка Disconnect). При повторном подключении будут автоматически подгружены последние сообщения из базы, с обратной сортировкой по времени.

Логирование

Логи Django включены по умолчанию.

В .env можно указать настройки, см. секцию Настройки логирования в .env.example.

Логирование при разработке

При разработке в код можно добавлять свои логи. Для этого нужно импортировать логгер из config.logging.

Пример:

from config.logging import logger

def some_func():
    logger.debug("Сообщение")

Декоратор log

Кроме того, из config.logging можно импортировать декоратор log, который запишет в логи факт вызова функции и ее аргументы, а также возвращаемые функцией значения.

Пример:

from config.logging import log

@log()
def some_func(a, b):
    return a + b

some_func(5, 10)

В логи запишется:

[CUSTOM_LOGGER_NAME] DEBUG 2024-03-22 16:33:25,922 find_friends logging.wrapper:38 Функция some_func api.module вызвана с аргументами 5, 10.
[FIND_FRIENDS] DEBUG 2024-03-22 16:33:25,922 find_friends logging.wrapper:44 Функция some_func модуля api.module вернула: 15

Декоратору можно передать два аргумента: