-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' of github.com:Studio-Yandex-Practicum-Hackatho…
…ns/cafe_azu_bot_2 into develop
- Loading branch information
Showing
33 changed files
with
627 additions
and
267 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
name: Django-app workflow | ||
|
||
on: [push] | ||
|
||
jobs: | ||
tests: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.11 | ||
|
||
- name: Install dependencies | ||
run: | | ||
# обновление pip | ||
python -m pip install --upgrade pip | ||
pip install flake8 pep8-naming flake8-broken-line flake8-return flake8-isort | ||
pip install -r requirements.txt | ||
- name: Test with flake8 and django tests | ||
run: | | ||
python -m flake8 | ||
build_and_push_to_docker_hub: | ||
name: Push Docker image to Docker Hub | ||
runs-on: ubuntu-latest | ||
needs: tests | ||
steps: | ||
- name: Check out the repo | ||
uses: actions/checkout@v2 | ||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v1 | ||
- name: Login to Docker | ||
uses: docker/login-action@v1 | ||
with: | ||
username: ${{ secrets.DOCKER_USERNAME }} | ||
password: ${{ secrets.DOCKER_PASSWORD }} | ||
- name: Push to Docker Hub | ||
uses: docker/build-push-action@v2 | ||
with: | ||
push: true | ||
tags: certelen/azu_cafe_django | ||
|
||
deploy: | ||
runs-on: ubuntu-latest | ||
needs: build_and_push_to_docker_hub | ||
steps: | ||
- name: executing remote ssh commands to deploy | ||
uses: appleboy/ssh-action@master | ||
with: | ||
host: ${{ secrets.HOST }} | ||
username: ${{ secrets.USER }} | ||
key: ${{ secrets.SSH_KEY }} | ||
passphrase: ${{ secrets.PASSPHRASE }} | ||
script: | | ||
# Выполняет pull образа с DockerHub | ||
sudo docker pull certelen/azu_cafe_django | ||
#остановка всех контейнеров | ||
sudo docker stop $(sudo docker ps -a -q) | ||
sudo docker run --rm -d -p 5000:5000 certelen/azu_cafe_django |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,103 +4,107 @@ | |
|
||
## Технологии | ||
- Python 3.11 | ||
- aiogram 3.1.1 | ||
- Django 4.2.7 | ||
- Django REST Framework 3.14.0 | ||
- Aiogram 3.1.1 | ||
- PostgreSQL 13.0 | ||
- Nginx 1.21.3 | ||
- Docker | ||
- Docker-compose | ||
- Docker Hub | ||
- SunriseSunset.io API | ||
|
||
# Установка | ||
## Копирование репозитория | ||
Клонируем репозиторий | ||
Клонируем репозиторий и переходим в директорию infra: | ||
``` | ||
~ git clone [email protected]:Studio-Yandex-Practicum-Hackathons/cafe_azu_bot_2.git | ||
~ cd ./cafe_azu_bot_2/infra/ | ||
``` | ||
Требуется изменить server_name и listen в ./infra/nginx/default.conf, ports в docker-compose.yml | ||
|
||
## Виртуальное окружение | ||
Переходим в клонированный репозиторий | ||
## Подготовка боевого сервера: | ||
1. Перейдите на боевой сервер: | ||
``` | ||
~ cd {путь до папки с клонированным репозиторем} | ||
~ cd cafe_azu_bot_2 | ||
ssh username@server_address | ||
``` | ||
Устанавливаем и активируем виртуальное окружение | ||
2. Обновите индекс пакетов APT: | ||
``` | ||
~ py -3.11 -m venv venv | ||
~ . venv/Scripts/activate | ||
sudo apt update | ||
``` | ||
Устанавливаем требуемые зависимости: | ||
и обновите установленные в системе пакеты и установите обновления безопасности: | ||
``` | ||
~ pip install -r requirements.txt | ||
sudo apt upgrade -y | ||
``` | ||
|
||
## База данных | ||
В azu_bot_django/azu_bot_django/settings.py выбрать нужную базу данных (sqlite3 или postgresql) | ||
### env | ||
Выполнять только если ваша база данных postgresql, иначе пропустить этот шаг. | ||
|
||
Создать файл .env со следующими строками для базы данных: | ||
- DATABASE_NAME = <Имя для подключения к базе данных> | ||
- DATABASE_USERNAME = <Имя пользователя для подключения к базе данных> | ||
- DATABASE_PASSWORD = <Пароль для подключения к базе данных> | ||
- DATABASE_HOST = <Адрес для подключения к базе данных> | ||
- DATABASE_PORT = <Порт для подключения к базе данных> | ||
|
||
### Миграция базы данных | ||
Переходим в раздел с базой данных: | ||
Создайте папку `nginx`: | ||
``` | ||
~ cd azu_bot_django | ||
mkdir nginx | ||
``` | ||
Скопируйте файлы docker-compose.yaml, nginx/default.conf из вашего проекта на сервер в home/<ваш_username>/docker-compose.yaml, home/<ваш_username>/nginx/default.conf соответственно: | ||
``` | ||
Создаем миграцию для базы данных: | ||
scp docker-compose.yaml <username>@<host>/home/<username>/docker-compose.yaml | ||
scp default.conf <username>@<host>/home/<username>/nginx/default.conf | ||
``` | ||
~ py manage.py makemigrations cafe tables menu admin_users reservation | ||
Установите Docker и Docker-compose: | ||
``` | ||
И применяем её: | ||
sudo apt install docker.io | ||
``` | ||
~ py manage.py migrate | ||
``` | ||
Создаем суперпользователя: | ||
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | ||
``` | ||
~ py manage.py createsuperuser | ||
``` | ||
Вводим поочередно Имя пользователя, почту и пароль. | ||
После чего запускаем базу данных: | ||
sudo chmod +x /usr/local/bin/docker-compose | ||
``` | ||
~ uvicorn azu_bot_django.asgi:application | ||
Проверьте правильность установки Docker-compose: | ||
``` | ||
|
||
### Наполнение базы данных | ||
Доступ к сервису становится доступен по [адресу](http://127.0.0.1:8000/admin/) | ||
|
||
По указаному адресу нужно создать хотя бы по одному экземпляру кафе, стола, блюда, сета. | ||
|
||
Так же можно наполнить базу данных готовыми сетами, блюдами, кафе и столам: | ||
|
||
sudo docker-compose --version | ||
``` | ||
~ py manage.py load_data | ||
На боевом сервере создайте файл .env: | ||
``` | ||
|
||
Создать пользователя-бота и по [адресу](http://127.0.0.1:8000/admin/authtoken/tokenproxy/) нужно создать токен для бота. | ||
|
||
## Телеграмм-бот | ||
### env | ||
В уже существующем файле .env добавить строки: | ||
touch .env | ||
``` | ||
и заполните переменные окружения | ||
``` | ||
nano .env | ||
- TOKEN = <Токен бота, можно получить у BotFather> | ||
- ADMIN_ID = <ID телеграмм-аккаунта админа> | ||
- PROVIDER_TOKEN = <Токен платежной системы> | ||
- DJANGO_TOKEN = <Токен для бота, который был создан в разделе базы данных> | ||
- SECRET_KEY=<SECRET_KEY> | ||
### Запуск | ||
Для полного запуска телеграмм-бота с базой данных нужно: | ||
- Выполнить все вышеуказанные действия по установке. | ||
- Перейти в папку с базой данных и запустить её: | ||
- POSTGRES_DB = postgres | ||
- POSTGRES_USER = postgres | ||
- POSTGRES_PASSWORD = postgres | ||
- POSTGRES_HOST = db | ||
- POSTGRES_PORT = 5432 | ||
- WEB_HOST = <ip сервера> | ||
- WEB_PORT = <Порт сервера> | ||
- WEB_PROTOKOL = <Протокол сервера> | ||
``` | ||
|
||
## Развертывание проекта с помощью Docker: | ||
Разворачиваем контейнеры в фоновом режиме из папки infra: | ||
``` | ||
sudo docker compose up -d | ||
``` | ||
При первом запуске выполняем миграции: | ||
``` | ||
~ cd azu_bot_django | ||
~ uvicorn azu_bot_django.asgi:application | ||
sudo docker compose exec backend python manage.py migrate | ||
``` | ||
- Выйти из папки с базой данных, перейти в папку бота, запустить бота: | ||
И собираем статику: | ||
``` | ||
~ cd azu_bot_aiogram | ||
~ py main.py | ||
sudo docker compose exec backend python manage.py collectstatic --no-input | ||
``` | ||
Телеграмм-бот готов к работе. | ||
Создаем суперпользователя: | ||
``` | ||
sudo docker compose exec backend python manage.py createsuperuser | ||
``` | ||
Загружаем данные из csv-таблиц в базу данных: | ||
``` | ||
sudo docker compose exec backend python manage.py load_data | ||
``` | ||
|
||
# Адресные пути | ||
- [Документация к API базе данных](http://127.0.0.1:8000/redoc) | ||
- [Админ-панель базы данных](http://127.0.0.1:8000/admin) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM python:3.11-slim | ||
|
||
WORKDIR /app | ||
|
||
COPY ./ ./ | ||
|
||
RUN pip3 install -r requirements.txt --no-cache-dir | ||
|
||
CMD ["python", "main.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,41 @@ | ||
import re | ||
|
||
from aiogram import Bot | ||
from aiogram.filters import BaseFilter | ||
from aiogram.fsm.context import FSMContext | ||
from aiogram.types import Message | ||
from handlers.api import get_cafe, post_quantity | ||
|
||
|
||
class IsPersonAmount(BaseFilter): | ||
async def __call__(self, message: Message) -> bool: | ||
"""Проверка корректности ввода количества человек.""" | ||
pattern = r'[1-4]$' | ||
pattern = r'^(0?[1-9]|[123][0-9]|4[0])$' | ||
if re.match(pattern, message.text): | ||
return {'amount': message.text} | ||
else: | ||
return False | ||
|
||
|
||
class TooManyPersons(BaseFilter): | ||
async def __call__(self, message: Message) -> bool: | ||
async def __call__( | ||
self, message: Message, bot: Bot, state: FSMContext | ||
) -> bool: | ||
"""Проверка числа клиентов для брони столов, если клиентов много.""" | ||
max_table_size = 4 | ||
if message.text.isdigit() and int(message.text) > max_table_size: | ||
cafes = await get_cafe(bot) | ||
context_data = await state.get_data() | ||
address_cafe = context_data.get('address') | ||
for cafe in cafes: | ||
if cafe['address'] == address_cafe: | ||
break | ||
data_dict = {} | ||
data_dict['date'] = '-'.join( | ||
context_data.get('date').split('.')[::-1] | ||
) | ||
data_dict['quantity'] = 0 | ||
check_current_cafe = await post_quantity(cafe['id'], data=data_dict) | ||
free_places = check_current_cafe['quantity'] | ||
if message.text.isdigit() and int(message.text) > int(free_places): | ||
return {'amount': message.text} | ||
else: | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,33 @@ | ||
import aiohttp | ||
from settings import django_token, settings | ||
|
||
|
||
async def get_session(): | ||
session = aiohttp.ClientSession( | ||
headers={"Authorization": f'Token {django_token}'} | ||
) | ||
return session | ||
async def get_cafe(bot=None): | ||
async with aiohttp.ClientSession() as session: | ||
async with session.get( | ||
'http://backend:8000/cafes/' | ||
) as response: | ||
return await response.json() | ||
|
||
|
||
async def get_cafe(bot=None): | ||
mysession = await get_session() | ||
async with mysession as session: | ||
async def get_cafe_admins(cafe): | ||
async with aiohttp.ClientSession() as session: | ||
async with session.get( | ||
'http://127.0.0.1:8000/cafes/' | ||
f'http://backend:8000/cafes/{cafe}/admins/' | ||
) as response: | ||
response = await response.json() | ||
if not isinstance(response, list): | ||
await bot.send_message( | ||
chat_id=settings.bots.admin_id, | ||
text='Нет связи с базой данных!' | ||
'Проверьте валидность django token!') | ||
return None | ||
return response | ||
return await response.json() | ||
|
||
|
||
async def post_quantity(cafe, data): | ||
mysession = await get_session() | ||
async with mysession as session: | ||
async with aiohttp.ClientSession() as session: | ||
async with session.post( | ||
f'http://127.0.0.1:8000/cafes/{cafe}/quantity/', json=data | ||
f'http://backend:8000/cafes/{cafe}/quantity/', json=data | ||
) as response: | ||
return await response.json() | ||
|
||
|
||
async def post_reservation(cafe_id, data): | ||
mysession = await get_session() | ||
async with mysession as session: | ||
async with aiohttp.ClientSession() as session: | ||
async with session.post( | ||
f'http://127.0.0.1:8000/cafes/{cafe_id}/reservations/', json=data | ||
f'http://backend:8000/cafes/{cafe_id}/reservations/', json=data | ||
) as response: | ||
return await response.json() |
Oops, something went wrong.