feat: can deploy with docker

fastapi-admin
Pierre-Louis Guhur 1 year ago
parent c8044acd75
commit 51bdf7ffc1

21
.env

@ -0,0 +1,21 @@
DB_NAME=mj
DB_HOST=mj_db
DB_PORT=5433
DB_USER=mj
DB_PASS=
DOMAIN=
EMAIL=
TIMEZONE=
# This is used by restic's backup
SMTP_HOST=
SMTP_USER=
SMTP_PASS=
RESTIC_REPOSITORY=s3:s3.amazonaws.com/your-bucket
RESTIC_PASSWORD=
RESTIC_SEND_MAIL=
RESTIC_DEST_MAIL=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

1
.gitignore vendored

@ -3,7 +3,6 @@ __pycache__/
*.mo
.#*
.ipynb_checkpoints/
.env
.env.local
backup
.venv/

@ -2,54 +2,27 @@
This API allows you to create elections, vote and obtain results with [majority judgment](https://en.wikipedia.org/wiki/Majority_judgment).
You can use our server at [demo.mieuxvoter.fr/api/](demo.mieuxvoter.fr/api/).
You can use our server at [api.mieuxvoter.fr/](api.mieuxvoter.fr/).
Since our API relies on OpenAPI, documentation is automatically generated and it is available at [api.mieuxvoter.fr/redoc](api.mieuxvoter.fr/redoc) or [api.mieuxvoter.fr/docs](api.mieuxvoter.fr/docs).
## Installation with Docker
Edit the `.env` with your own settings. A secret key can be generated in Python REPL:
```
>>> from django.core.management.utils import get_random_secret_key
>>> get_random_secret_key()
```
Create a `.env.local` with :
```
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=smtp.gmail.com
EMAIL_USE_TLS=True
EMAIL_USE_SSL=False
EMAIL_PORT=587
EMAIL_HOST_USER= address of a gmail account
EMAIL_HOST_PASSWORD=gmail account password
```
For the gmail account, it is better to create one specially for this.
In "Manage your google account" / "security" activated the option "Less secure access of applications"
## Installation with Docker
Copy the `.env` into `.env.local` with your own settings.
Then launch the dockers with:
`sudo docker-compose up -d`
`sudo docker-compose up -d --profiles all`
You certainly want to apply databases migrations with:
`sudo docker/migrate.sh`
## Browse the admin
Create a super-user:
```
sudo docker exec -it mvapi_web_1 python ./manage.py createsuperuser
```
Visit the admin page at [http://localhost:8012/admin/](http://localhost:8012/admin/).
## Run the tests
`sudo docker/test.sh`
`docker/test.sh`
## Create databases migrations
@ -60,17 +33,14 @@ Visit the admin page at [http://localhost:8012/admin/](http://localhost:8012/adm
## Local development
1. Install [postgresql](https://www.postgresql.org/download/).
2. Install `virtualenv`:
```bash
pip install virtualenv
```
2. Install python 3.11.
3. Create a new virtual environment and activate it:
```bash
virtualenv --python python3.11 .venv
venv .venv
source .venv/bin/activate
```
@ -81,21 +51,13 @@ pip install -r requirements.txt
pip install -r requirements-dev.txt
```
5. Edit a `.env` with environment variables:
5. Copy `.env` into `.env.local` and edit environment variables
```
# All variables are described in app/settings.py
POSTGRES_PASSWORD=
POSTGRES_DB=mv
POSTGRES_NAME=postgresql
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
```
6. Start the server:
```
uvicorn app.main:app --reload
uvicorn app.main:app --reload --env-file .env.local
```
7. Visit the generated documentation:
@ -106,23 +68,18 @@ http://127.0.0.1:8000/redoc
## API
## TODO
POST elections: creation election
--> return a JWT token for administration
--> and the election link
--> and eventually a series of JWT tokens for voting
GET elections/[election-id] get all data about a specific election. Might need a JWT token
PUT elections/[election-id] get all data about a specific election. Might need a JWT token
--> might return new invites
GET elections/[election-id]/proposals: only get the proposals. Might need a JWT token
GET elections/[election-id]/candidates: only get the candidates. Might need a JWT token
GET elections/[election-id]/votes: only get the votes. Might need a JWT token
GET grades/[election-id]: only get the grades related to an election. Might need a JWT token
GET candidates/[election-id]: only get the candidates related to an election. Might need a JWT token
GET votes/[election-id]: only get the votes. Might need a JWT token
POST elections/[election-id]/votes: to vote. Might need a JWT token
GET /metrics a few metrics, among them the number of elections, number of voters and number of votes.
## TODO
[] Clean up nginx.conf

@ -12,9 +12,9 @@ if settings.sqlite:
else:
database_url = (
"postgresql+psycopg2://"
f"{settings.postgres_name}:{quote(settings.postgres_password)}"
f"{settings.postgres_user}:{quote(settings.postgres_password)}"
f"@{settings.postgres_host}:{settings.postgres_port}"
f"/{settings.postgres_db}"
f"/{settings.postgres_name}"
)
engine = create_engine(database_url)

@ -5,7 +5,7 @@ class Settings(BaseSettings):
sqlite: bool = False
postgres_password: str = ""
postgres_db: str = "mj"
postgres_user: str = "mj"
postgres_name: str = "mj"
postgres_host: str = "mj_db"
postgres_port: int = 5432

@ -4,6 +4,7 @@ services:
mj_db:
image: postgres:15
restart: unless-stopped
hostname: mj_db
environment:
- POSTGRES_USER=${DB_USER:-mj}
- POSTGRES_PASSWORD=$DB_PASS
@ -12,7 +13,7 @@ services:
networks:
- lan
volumes:
- data/db:/var/lib/mysql
- db:/var/lib/mysql
mj_api:
build:
@ -20,13 +21,18 @@ services:
dockerfile: docker/Dockerfile
image: majority-judgment/api-python:latest
restart: unless-stopped
command: uvicorn main:app --host 0.0.0.0 --port 8877 --proxy-headers
command: uvicorn app.main:app --host 0.0.0.0 --port 8877 --proxy-headers --env-file ${ENV_FILE:-.env.local}
healthcheck:
start_period: 30s
test: ['CMD-SHELL', 'curl localhost:8877/liveness -s -f -o /dev/null || exit 1']
interval: 30s
depends_on:
- mj_db
volumes:
- .:/code
networks:
- lan
- traefik_network
environment:
- POSTGRES_USER=${DB_USER:-mj}
- POSTGRES_PASSWORD=$DB_PASS
@ -39,7 +45,7 @@ services:
- "traefik.enable=true"
- "traefik.docker.network=traefik_network"
- "traefik.http.routers.mj.entrypoints=web,websecure"
- "traefik.http.routers.mj.rule=Host(${API_PREFIX:-api}.`${DOMAIN}`)"
- "traefik.http.routers.mj.rule=Host(`${API_PREFIX:-apiv2}.${DOMAIN}`)"
- "traefik.http.services.mj.loadbalancer.server.port=8877"
- "traefik.http.routers.mj.tls=true"
- "traefik.http.routers.mj.tls.certresolver=leresolver"
@ -59,7 +65,8 @@ services:
RESTIC_PASSWORD: $RESTIC_PASSWORD
restart: unless-stopped
volumes:
- data:/data
- db:/data/db
- imgpush:/data/images
environment:
- TZ=${TIMEZONE:-Europe/Paris}
- RESTIC_REPOSITORY=$RESTIC_REPOSITORY
@ -74,12 +81,11 @@ services:
- image
- all
image: hauxir/imgpush:latest
container_name: imgpush
restart: unless-stopped
environment:
PUID: $PUID
PGID: $PUID
TZ: ${TIMEZONE:Europe/Paris}
TZ: ${TIMEZONE:-Europe/Paris}
IMAGES_DIR: /images
MAX_SIZE_MB: 16
MAX_UPLOADS_PER_DAY: 100
@ -96,7 +102,7 @@ services:
- lan
- traefik_network
volumes:
- data/imgpush:/images
- imgpush:/images
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_network"
@ -124,19 +130,20 @@ services:
MB_DB_USER: ${DB_USER:-mj}
MB_DB_PASS: $DB_PASS
MB_DB_HOST: mj_db
TZ: ${TIMEZONE:Europe/Paris}
TZ: ${TIMEZONE:-Europe/Paris}
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_network"
- "traefik.http.routers.metabase.entrypoints=web,websecure"
- "traefik.http.routers.metabase.rule=Host(${METABASE_PREFIX:-metabase}.`${DOMAIN}`)"
- "traefik.http.routers.metabase.rule=Host(`${METABASE_PREFIX:-metabase}.${DOMAIN}`)"
- "traefik.http.services.metabase.loadbalancer.server.port=3000"
- "traefik.http.routers.metabase.tls=true"
- "traefik.http.routers.metabase.tls.certresolver=leresolver"
volumes:
data:
imgpush:
db:
networks:
lan:

Loading…
Cancel
Save