init commit
This commit is contained in:
40
.drone.yml
Normal file
40
.drone.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: build_test_local
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: docker:27
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
commands:
|
||||
- docker compose -f docker-compose.yml build --pull
|
||||
|
||||
- name: migrate
|
||||
image: docker:27
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
commands:
|
||||
- docker compose up -d db
|
||||
- |
|
||||
for i in $(seq 1 60); do
|
||||
if docker compose ps db | grep -q "(healthy)"; then
|
||||
echo "DB healthy"; break
|
||||
fi
|
||||
echo "Waiting DB... $i"
|
||||
sleep 2
|
||||
done
|
||||
- docker compose run --rm bot alembic upgrade head
|
||||
|
||||
- name: lint
|
||||
image: python:3.12-slim
|
||||
commands:
|
||||
- pip install ruff==0.5.7
|
||||
- ruff check services/bot
|
||||
|
||||
volumes:
|
||||
- name: dockersock
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
13
.env
Normal file
13
.env
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=soulmate_bot_v1
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=seoulmate
|
||||
MYSQL_USER=match_admin
|
||||
MYSQL_PASSWORD=3uHU66gnRloyQ2zQ9L516R4DPSiwUzJyCD9h5zCVcuBykJlLm3
|
||||
MYSQL_ROOT_PASSWORD=eiKVznWb13FZMCoXvlFRIfozzP752qWkMTEE7kzlus3vSUdPtg
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
176
.gitignore
vendored
176
.gitignore
vendored
@@ -1,176 +0,0 @@
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
|
||||
13
.history/.env_20250812203631
Normal file
13
.history/.env_20250812203631
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=korea-marriage-bot
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=match_agency
|
||||
MYSQL_USER=match_user
|
||||
MYSQL_PASSWORD=match_password_change_me
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=replace_with_your_bot_token
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=123456789
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812203658
Normal file
13
.history/.env_20250812203658
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=korea-marriage-bot
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=match_agency
|
||||
MYSQL_USER=match_user
|
||||
MYSQL_PASSWORD=match_password_change_me
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=replace_with_your_bot_token
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812203723
Normal file
13
.history/.env_20250812203723
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=korea-marriage-bot
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=match_agency
|
||||
MYSQL_USER=match_user
|
||||
MYSQL_PASSWORD=match_password_change_me
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812203740
Normal file
13
.history/.env_20250812203740
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=soulmate_bot_v1
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=match_agency
|
||||
MYSQL_USER=match_user
|
||||
MYSQL_PASSWORD=match_password_change_me
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812204515
Normal file
13
.history/.env_20250812204515
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=soulmate_bot_v1
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=seoulmate
|
||||
MYSQL_USER=match_admin
|
||||
MYSQL_PASSWORD=match_password_change_
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812204538
Normal file
13
.history/.env_20250812204538
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=soulmate_bot_v1
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=seoulmate
|
||||
MYSQL_USER=match_admin
|
||||
MYSQL_PASSWORD=3uHU66gnRloyQ2zQ9L516R4DPSiwUzJyCD9h5zCVcuBykJlLm3
|
||||
MYSQL_ROOT_PASSWORD=root_password_change_me
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.env_20250812204549
Normal file
13
.history/.env_20250812204549
Normal file
@@ -0,0 +1,13 @@
|
||||
COMPOSE_PROJECT_NAME=soulmate_bot_v1
|
||||
TZ=Asia/Seoul
|
||||
|
||||
MYSQL_DATABASE=seoulmate
|
||||
MYSQL_USER=match_admin
|
||||
MYSQL_PASSWORD=3uHU66gnRloyQ2zQ9L516R4DPSiwUzJyCD9h5zCVcuBykJlLm3
|
||||
MYSQL_ROOT_PASSWORD=eiKVznWb13FZMCoXvlFRIfozzP752qWkMTEE7kzlus3vSUdPtg
|
||||
|
||||
DATABASE_URL=mysql+pymysql://match_user:match_password_change_me@db:3306/match_agency?charset=utf8mb4
|
||||
|
||||
BOT_TOKEN=7839684534:AAGAUmO756P1T81q8ImndWgIBU9OsZkY06s
|
||||
PRIMARY_ADMIN_TELEGRAM_ID=556399210
|
||||
PYTHONUNBUFFERED=1
|
||||
13
.history/.gitignore_20250812203631
Normal file
13
.history/.gitignore_20250812203631
Normal file
@@ -0,0 +1,13 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
14
.history/.gitignore_20250812205206
Normal file
14
.history/.gitignore_20250812205206
Normal file
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
15
.history/.gitignore_20250812205412
Normal file
15
.history/.gitignore_20250812205412
Normal file
@@ -0,0 +1,15 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.history
|
||||
0
.history/.gitignore_20250812205847
Normal file
0
.history/.gitignore_20250812205847
Normal file
191
.history/.gitignore_20250812205903
Normal file
191
.history/.gitignore_20250812205903
Normal file
@@ -0,0 +1,191 @@
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
191
.history/.gitignore_20250812205906
Normal file
191
.history/.gitignore_20250812205906
Normal file
@@ -0,0 +1,191 @@
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
14
.history/.gitignore_20250812205947
Normal file
14
.history/.gitignore_20250812205947
Normal file
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
14
.history/.gitignore_20250812205949
Normal file
14
.history/.gitignore_20250812205949
Normal file
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.venv/
|
||||
.env.local
|
||||
.env
|
||||
node_modules/
|
||||
*.log
|
||||
docker-data/
|
||||
volumes/
|
||||
alembic/*.pyc
|
||||
alembic/versions/__pycache__/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
0
.history/.gitignore_20250812205953
Normal file
0
.history/.gitignore_20250812205953
Normal file
0
.history/alembic_20250812205533.env
Normal file
0
.history/alembic_20250812205533.env
Normal file
108
.history/alembic_20250812205541.env
Normal file
108
.history/alembic_20250812205541.env
Normal file
@@ -0,0 +1,108 @@
|
||||
# 1) Создаём структуру Alembic
|
||||
mkdir -p services/bot/alembic/versions
|
||||
|
||||
# 2) env.py
|
||||
cat > services/bot/alembic/env.py <<'PY'
|
||||
from __future__ import annotations
|
||||
import os
|
||||
from logging.config import fileConfig
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from alembic import context
|
||||
|
||||
config = context.config
|
||||
# Подменяем URL из переменных окружения контейнера
|
||||
if os.getenv("DATABASE_URL"):
|
||||
config.set_main_option("sqlalchemy.url", os.getenv("DATABASE_URL"))
|
||||
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# Метаданные моделей
|
||||
from app.models.base import Base # noqa: E402
|
||||
target_metadata = Base.metadata
|
||||
|
||||
def run_migrations_offline():
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(url=url, target_metadata=target_metadata, literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"})
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online():
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section, {}),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
with connectable.connect() as connection:
|
||||
context.configure(connection=connection, target_metadata=target_metadata)
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
PY
|
||||
|
||||
# 3) Первая миграция
|
||||
cat > services/bot/alembic/versions/0001_init.py <<'PY'
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = '0001_init'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'admins',
|
||||
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column('telegram_id', sa.Integer(), unique=True, index=True),
|
||||
sa.Column('full_name', sa.String(length=120), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP')),
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
'candidates',
|
||||
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column('telegram_id', sa.Integer(), unique=True, index=True),
|
||||
sa.Column('username', sa.String(length=100), nullable=True),
|
||||
sa.Column('full_name', sa.String(length=120), nullable=True),
|
||||
sa.Column('gender', sa.String(length=20), nullable=True),
|
||||
sa.Column('birth_date', sa.Date(), nullable=True),
|
||||
sa.Column('height_cm', sa.Float(), nullable=True),
|
||||
sa.Column('weight_kg', sa.Float(), nullable=True),
|
||||
sa.Column('country', sa.String(length=80), nullable=True),
|
||||
sa.Column('city', sa.String(length=120), nullable=True),
|
||||
sa.Column('citizenship', sa.String(length=80), nullable=True),
|
||||
sa.Column('visa_status', sa.String(length=60), nullable=True),
|
||||
sa.Column('languages', sa.String(length=200), nullable=True),
|
||||
sa.Column('education', sa.String(length=120), nullable=True),
|
||||
sa.Column('occupation', sa.String(length=120), nullable=True),
|
||||
sa.Column('income_range', sa.String(length=60), nullable=True),
|
||||
sa.Column('religion', sa.String(length=80), nullable=True),
|
||||
sa.Column('marital_status', sa.String(length=60), nullable=True),
|
||||
sa.Column('has_children', sa.Boolean(), nullable=True),
|
||||
sa.Column('children_notes', sa.String(length=200), nullable=True),
|
||||
sa.Column('smoking', sa.String(length=20), nullable=True),
|
||||
sa.Column('alcohol', sa.String(length=20), nullable=True),
|
||||
sa.Column('health_notes', sa.String(length=300), nullable=True),
|
||||
sa.Column('hobbies_tags', sa.String(length=300), nullable=True),
|
||||
sa.Column('hobbies_free', sa.Text(), nullable=True),
|
||||
sa.Column('goal', sa.String(length=120), nullable=True),
|
||||
sa.Column('partner_prefs', sa.Text(), nullable=True),
|
||||
sa.Column('avatar_file_id', sa.String(length=200), nullable=True),
|
||||
sa.Column('gallery_file_ids', sa.Text(), nullable=True),
|
||||
sa.Column('consent_personal', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('consent_policy', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('is_verified', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('is_active', sa.Boolean(), nullable=False, server_default=sa.text('1')),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP')),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP')),
|
||||
)
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('candidates')
|
||||
op.drop_table('admins')
|
||||
PY
|
||||
55
.history/docker-compose_20250812203631.yml
Normal file
55
.history/docker-compose_20250812203631.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u2462276MYSQL_USER -p2462276MYSQL_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
55
.history/docker-compose_20250812203841.yml
Normal file
55
.history/docker-compose_20250812203841.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u2462276MYSQL_USER -p2462276MYSQL_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
57
.history/docker-compose_20250812204453.yml
Normal file
57
.history/docker-compose_20250812204453.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 40s
|
||||
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
60
.history/docker-compose_20250812204732.yml
Normal file
60
.history/docker-compose_20250812204732.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 40s
|
||||
command: [
|
||||
"--character-set-server=utf8mb4",
|
||||
"--collation-server=utf8mb4_unicode_ci"
|
||||
]
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
60
.history/docker-compose_20250812204816.yml
Normal file
60
.history/docker-compose_20250812204816.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 40s
|
||||
command: [
|
||||
"--character-set-server=utf8mb4",
|
||||
"--collation-server=utf8mb4_unicode_ci"
|
||||
]
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
67
.history/docker-compose_20250812205020.yml
Normal file
67
.history/docker-compose_20250812205020.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"([ -x /usr/bin/mariadb-admin ] && mariadb-admin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent) || \
|
||||
([ -x /usr/bin/mysqladmin ] && mysqladmin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent) || \
|
||||
(command -v bash >/dev/null 2>&1 && bash -c '</dev/tcp/127.0.0.1/3306' >/dev/null 2>&1)"
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 40s
|
||||
|
||||
command: [
|
||||
"--character-set-server=utf8mb4",
|
||||
"--collation-server=utf8mb4_unicode_ci"
|
||||
]
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
29
Makefile
Normal file
29
Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
.PHONY: up down logs build stop restart botsh dbsh migrate
|
||||
|
||||
up:
|
||||
docker compose up -d
|
||||
|
||||
down:
|
||||
docker compose down
|
||||
|
||||
build:
|
||||
docker compose build --pull
|
||||
|
||||
logs:
|
||||
docker compose logs -f --tail=200
|
||||
|
||||
stop:
|
||||
docker compose stop
|
||||
|
||||
restart: down up
|
||||
|
||||
botsh:
|
||||
docker compose exec bot bash || true
|
||||
|
||||
dbsh:
|
||||
docker compose exec db bash || true
|
||||
|
||||
migrate:
|
||||
docker compose run --rm bot alembic upgrade head
|
||||
67
docker-compose.yml
Normal file
67
docker-compose.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.6
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"([ -x /usr/bin/mariadb-admin ] && mariadb-admin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent) || \
|
||||
([ -x /usr/bin/mysqladmin ] && mysqladmin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent) || \
|
||||
(command -v bash >/dev/null 2>&1 && bash -c '</dev/tcp/127.0.0.1/3306' >/dev/null 2>&1)"
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 40s
|
||||
|
||||
command: [
|
||||
"--character-set-server=utf8mb4",
|
||||
"--collation-server=utf8mb4_unicode_ci"
|
||||
]
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
bot:
|
||||
build:
|
||||
context: ./services/bot
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- PY_VERSION=3.12
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
- ./services/bot:/app
|
||||
command: ["/app/entrypoint.sh"]
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- appnet
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
11
services/bot/Dockerfile
Normal file
11
services/bot/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
ARG PY_VERSION=3.12
|
||||
FROM python:${PY_VERSION}-slim
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends tzdata \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . .
|
||||
RUN chmod +x entrypoint.sh
|
||||
CMD ["./entrypoint.sh"]
|
||||
3
services/bot/alembic.ini
Normal file
3
services/bot/alembic.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[alembic]
|
||||
script_location = alembic
|
||||
sqlalchemy.url = ${DATABASE_URL}
|
||||
39
services/bot/alembic/env.py
Normal file
39
services/bot/alembic/env.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from __future__ import annotations
|
||||
import os
|
||||
from logging.config import fileConfig
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from alembic import context
|
||||
|
||||
config = context.config
|
||||
# Подменяем URL из переменных окружения контейнера
|
||||
if os.getenv("DATABASE_URL"):
|
||||
config.set_main_option("sqlalchemy.url", os.getenv("DATABASE_URL"))
|
||||
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# Метаданные моделей
|
||||
from app.models.base import Base # noqa: E402
|
||||
target_metadata = Base.metadata
|
||||
|
||||
def run_migrations_offline():
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(url=url, target_metadata=target_metadata, literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"})
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online():
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section, {}),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
with connectable.connect() as connection:
|
||||
context.configure(connection=connection, target_metadata=target_metadata)
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
59
services/bot/alembic/versions/0001_init.py
Normal file
59
services/bot/alembic/versions/0001_init.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = '0001_init'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'admins',
|
||||
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column('telegram_id', sa.Integer(), unique=True, index=True),
|
||||
sa.Column('full_name', sa.String(length=120), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP')),
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
'candidates',
|
||||
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column('telegram_id', sa.Integer(), unique=True, index=True),
|
||||
sa.Column('username', sa.String(length=100), nullable=True),
|
||||
sa.Column('full_name', sa.String(length=120), nullable=True),
|
||||
sa.Column('gender', sa.String(length=20), nullable=True),
|
||||
sa.Column('birth_date', sa.Date(), nullable=True),
|
||||
sa.Column('height_cm', sa.Float(), nullable=True),
|
||||
sa.Column('weight_kg', sa.Float(), nullable=True),
|
||||
sa.Column('country', sa.String(length=80), nullable=True),
|
||||
sa.Column('city', sa.String(length=120), nullable=True),
|
||||
sa.Column('citizenship', sa.String(length=80), nullable=True),
|
||||
sa.Column('visa_status', sa.String(length=60), nullable=True),
|
||||
sa.Column('languages', sa.String(length=200), nullable=True),
|
||||
sa.Column('education', sa.String(length=120), nullable=True),
|
||||
sa.Column('occupation', sa.String(length=120), nullable=True),
|
||||
sa.Column('income_range', sa.String(length=60), nullable=True),
|
||||
sa.Column('religion', sa.String(length=80), nullable=True),
|
||||
sa.Column('marital_status', sa.String(length=60), nullable=True),
|
||||
sa.Column('has_children', sa.Boolean(), nullable=True),
|
||||
sa.Column('children_notes', sa.String(length=200), nullable=True),
|
||||
sa.Column('smoking', sa.String(length=20), nullable=True),
|
||||
sa.Column('alcohol', sa.String(length=20), nullable=True),
|
||||
sa.Column('health_notes', sa.String(length=300), nullable=True),
|
||||
sa.Column('hobbies_tags', sa.String(length=300), nullable=True),
|
||||
sa.Column('hobbies_free', sa.Text(), nullable=True),
|
||||
sa.Column('goal', sa.String(length=120), nullable=True),
|
||||
sa.Column('partner_prefs', sa.Text(), nullable=True),
|
||||
sa.Column('avatar_file_id', sa.String(length=200), nullable=True),
|
||||
sa.Column('gallery_file_ids', sa.Text(), nullable=True),
|
||||
sa.Column('consent_personal', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('consent_policy', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('is_verified', sa.Boolean(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('is_active', sa.Boolean(), nullable=False, server_default=sa.text('1')),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP')),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP')),
|
||||
)
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('candidates')
|
||||
op.drop_table('admins')
|
||||
5
services/bot/app/core/config.py
Normal file
5
services/bot/app/core/config.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import os
|
||||
class Settings:
|
||||
BOT_TOKEN = os.getenv("BOT_TOKEN", "")
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "")
|
||||
settings = Settings()
|
||||
14
services/bot/app/main.py
Normal file
14
services/bot/app/main.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import asyncio
|
||||
from telegram.ext import Application, CommandHandler
|
||||
from app.core.config import settings
|
||||
async def start(update, context):
|
||||
await update.message.reply_text("Привет! Бот запущен.")
|
||||
async def main():
|
||||
app = Application.builder().token(settings.BOT_TOKEN).build()
|
||||
app.add_handler(CommandHandler("start", start))
|
||||
await app.initialize()
|
||||
await app.start()
|
||||
await app.updater.start_polling()
|
||||
await app.updater.wait_until_closed()
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
26
services/bot/entrypoint.sh
Executable file
26
services/bot/entrypoint.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
if [ -f "/app/.env" ]; then
|
||||
set -a; source /app/.env; set +a
|
||||
fi
|
||||
echo "Waiting for DB..."
|
||||
python - <<'PY'
|
||||
import os, time, pymysql
|
||||
url = os.environ["DATABASE_URL"]
|
||||
u = url.split("://",1)[1].split("@",1)
|
||||
auth, host_db = u[0], u[1]
|
||||
host, port_db = host_db.split("/",1)[0], host_db.split("/",1)[1]
|
||||
host, port = host.split(":")[0], int(host.split(":")[1] or 3306)
|
||||
user, password = auth.split(":")[0], ":".join(auth.split(":")[1:])
|
||||
db = port_db.split("?")[0]
|
||||
for i in range(60):
|
||||
try:
|
||||
conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
|
||||
conn.close()
|
||||
break
|
||||
except Exception as e:
|
||||
print("Waiting DB...", e)
|
||||
time.sleep(2)
|
||||
PY
|
||||
alembic upgrade head
|
||||
exec python -m app.main
|
||||
7
services/bot/requirements.txt
Normal file
7
services/bot/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
python-telegram-bot==21.6
|
||||
SQLAlchemy==2.0.30
|
||||
alembic==1.13.2
|
||||
pymysql==1.1.1
|
||||
python-dotenv==1.0.1
|
||||
tenacity==9.0.0
|
||||
ruff==0.5.7
|
||||
Reference in New Issue
Block a user