Skip to content
This repository has been archived by the owner on Jan 4, 2023. It is now read-only.

Commit

Permalink
Link frontend and backend (#3)
Browse files Browse the repository at this point in the history
* Add a login page and link frontend and backend
* Replace basic authentication with JWT auth
* Fix yarn timeout
* Shared volume between api and nginx is now limited to django static files and the socket file
* Change env variables management
* The uwsgi server is run by a dedicated non root user
  • Loading branch information
tevariou authored Dec 15, 2020
1 parent 63ee6ba commit 9f69b10
Show file tree
Hide file tree
Showing 47 changed files with 1,098 additions and 286 deletions.
13 changes: 0 additions & 13 deletions .env

This file was deleted.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# AVC Forms

## Usage
Run `docker-compose up -d` and visit `host:port` (default `localhost:8080`)
Run `docker-compose up`.
Visit `host:port` (default `localhost:8080`).
Default user Admin credentials are `{ username: admin, password: admin }`.

## Configuration
Set up your custom configuration in the `.env` file
14 changes: 14 additions & 0 deletions api/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# DJANGO_SECRET should be a crypto secure random 50 bytes key
DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY:-secret}
DJANGO_ALLOWED_HOSTS="${DJANGO_ALLOWED_HOST:-localhost 127.0.0.1}"
DJANGO_CORS_ALLOWED_ORIGINS="${DJANGO_CORS_ALLOWED_ORIGINS:-http://localhost:8080 http://localhost:3000}"
DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME:-admin}
DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD:-admin}
DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL:[email protected]}
# DJANGO_DEBUG should be equal to 0 in production
DJANGO_DEBUG=${DJANGO_DEBUG:-1}
POSTGRES_DB=${POSTGRES_DB:-postgres}
POSTGRES_USER=${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
POSTGRES_HOST=${POSTGRES_HOST:-db}
POSTGRES_PORT=${POSTGRES_PORT:-5432}
1 change: 1 addition & 0 deletions api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env.local
18 changes: 10 additions & 8 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
FROM python:3.9.0-slim-buster as builder
WORKDIR /tmp
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
COPY ./requirements.txt .
RUN apt-get update && apt-get install -y libpq-dev gcc
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /tmp/wheels -r requirements.txt

FROM python:3.9.0-slim-buster
ENV DJANGO_SETTINGS_MODULE=avc_forms.settings
ENV PYTHONPATH=/api
RUN apt-get update && \
apt-get install -y --no-install-recommends netcat libpq-dev && \
apt-get autoremove -y && \
apt-get clean
COPY --from=builder /tmp/wheels /wheels
RUN pip install --no-cache /wheels/*
WORKDIR /api
COPY . .
RUN groupadd -r api && useradd --create-home --no-log-init -r -g api api
USER api:api
WORKDIR /home/api
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH=/home/api
ENV PATH /home/api/.local/bin:${PATH}
COPY --from=builder --chown=api:api /tmp/wheels wheels
RUN pip install --user --no-cache wheels/* && rm -rf wheels
COPY --chown=api:api . .
ENTRYPOINT ["sh", "docker-entrypoint.sh"]
61 changes: 51 additions & 10 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
# AVC Forms API

## Recommended requirements
* Python 3.9
* Pip 20.3.1
* Postresql 13.1
* Prerequesites for [psycopg](https://www.psycopg.org/docs/install.html)

## Usage
* Run a postgresql database `postgres` at `localhost:5432` (user `postgres`, no password)
* Install dependencies `pip install -r requirements.txt`
* Apply migration `python manage.py migrate`
* Create an admin user `python manage.py createsuperuser`
* Run `python manage.py runserver`
* Visit `localhost:8080` and login

* API root at `host:port/api`
* Admin interface at `host:port/api/admin`
## Base configuration override for local development
* Add environment variables in a `.env.local` file in the API project directory

## Routes
* `/api-auth/login` accepts basic authentication
* `/api-auth/logout`
* API documentation at `host:port/api`
* Admin interface at `host:port/api/admin`

* `/token/`
* `POST` request
```json
{
"username": "username",
"password": "password"
}
```
* Response
```json
{
"refresh": "refresh_jwt_token",
"access": "access_jwt_token"
}
```
* `/token/refresh/`
* Request
```shell script
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"refresh":"refresh_token_jwt"}' \
http://host:port/api/token/refresh/
```
* Response
```json
{ "access": "access_jwt_token" }
```
* `/users`
* `/patients`
```json
{
"code": "unique_text_field",
"data": { }
}
```
* Example request
```shell script
curl \
-H "Bearer access_jwt_token"
http://host:port/api/patients
```
19 changes: 19 additions & 0 deletions api/avc_forms/api/migrations/0005_auto_20201209_1524.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 3.1.4 on 2020-12-09 15:24

from django.db import migrations, models
import uuid


class Migration(migrations.Migration):

dependencies = [
('api', '0004_auto_20201125_1839'),
]

operations = [
migrations.AlterField(
model_name='patient',
name='code',
field=models.TextField(default=uuid.uuid4, unique=True),
),
]
3 changes: 2 additions & 1 deletion api/avc_forms/api/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from django.db import models
import uuid


class Patient(models.Model):
code = models.TextField(default='', unique=True)
code = models.TextField(default=uuid.uuid4, unique=True)
data = models.JSONField()
created_by = models.ForeignKey('auth.User', related_name='+', on_delete=models.RESTRICT)
created_at = models.DateTimeField(auto_now_add=True)
Expand Down
16 changes: 0 additions & 16 deletions api/avc_forms/asgi.py

This file was deleted.

33 changes: 20 additions & 13 deletions api/avc_forms/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'secret')
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'secret')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = int(os.getenv('DJANGO_DEBUG', 0))

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
DEBUG = bool(int(os.environ.get('DJANGO_DEBUG', 1)))

ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS').split(' ') if os.getenv('DJANGO_ALLOWED_HOSTS') else []
CORS_ALLOW_ALL_ORIGINS = DEBUG
CORS_ALLOWED_ORIGINS = os.environ\
.get('DJANGO_CORS_ALLOWED_ORIGINS', 'http://localhost:8080 http://localhost:3000')\
.split(' ')

# Application definition

INSTALLED_APPS = [
'avc_forms.api',
'corsheaders',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -45,6 +49,7 @@
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
Expand Down Expand Up @@ -79,11 +84,11 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv("POSTGRES_DB", 'avc'),
'USER': os.getenv("POSTGRES_USER", 'postgres'),
'PASSWORD': os.getenv("POSTGRES_PASSWORD", ''),
'HOST': os.getenv("POSTGRES_HOST", 'localhost'),
'PORT': os.getenv("POSTGRES_PORT", 5432),
'NAME': os.environ.get('POSTGRES_DB', 'postgres'),
'USER': os.environ.get('POSTGRES_USER', 'postgres'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
'HOST': os.environ.get('POSTGRES_HOST', 'localhost'),
'PORT': os.environ.get('POSTGRES_PORT', 5432),
}
}

Expand Down Expand Up @@ -123,12 +128,14 @@

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_DIR, 'django_static')
STATIC_ROOT = '/tmp/django_static'
STATIC_URL = '/django_static/'

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 42
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication'
),
'PAGE_SIZE': 100
}
6 changes: 6 additions & 0 deletions api/avc_forms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
from django.contrib import admin
from rest_framework import routers
from avc_forms.api import views
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
Expand All @@ -28,5 +32,7 @@
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('admin/', admin.site.urls)
]
7 changes: 4 additions & 3 deletions api/avc_forms/uwsgi.ini
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[uwsgi]
chdir=/api/avc_forms
chdir=/home/api/avc_forms
mount = /api=avc_forms.wsgi:application
manage-script-name=true
master=True
pidfile=/tmp/project-master.pid
vacuum=True
max-requests=5000
env=LANG=en_US.UTF-8
processes=5
threads=2
socket=avc_forms.sock
socket=/tmp/avc_forms.sock
chmod-socket=666
uid=api
gid=api
10 changes: 5 additions & 5 deletions api/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/bash

# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput

# Wait for db
echo "Waiting for postgres..."
while ! nc -z "$POSTGRES_HOST" "$POSTGRES_PORT"; do
Expand All @@ -12,10 +16,6 @@ python manage.py migrate

# Create superuser
echo "Create superuser"
django-admin createsuperuser --noinput

# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput
python manage.py createsuperuser --noinput

exec "$@"
7 changes: 7 additions & 0 deletions api/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
"""Django's command-line utility for administrative tasks."""
import os
import sys
from pathlib import Path
from dotenv import load_dotenv


def main():
"""Run administrative tasks."""

# Load optional .env.local file in the project directory to override base configuration
env_path = Path('.') / '.env.local'
load_dotenv(dotenv_path=env_path)

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'avc_forms.settings')
try:
from django.core.management import execute_from_command_line
Expand Down
6 changes: 5 additions & 1 deletion api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
asgiref==3.3.1
Django==3.1.3
Django==3.1.4
django-cors-headers==3.6.0
django-filter==2.4.0
djangorestframework==3.12.2
djangorestframework-simplejwt==4.6.0
Markdown==3.3.3
psycopg2==2.8.6
PyJWT==1.7.1
python-dotenv==0.15.0
pytz==2020.4
sqlparse==0.4.1
uWSGI==2.0.19.1
2 changes: 2 additions & 0 deletions app/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
./node_modules
./build
5 changes: 5 additions & 0 deletions app/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# REACT_APP_API_URL=${APP_API_URL}
# REACT_APP_AUTH_API_URL=${APP_API_AUTH}

REACT_APP_API_URL=http://localhost:8080/api
REACT_APP_AUTH_API_URL=http://localhost:8080/api/token/
1 change: 1 addition & 0 deletions app/.yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
network-timeout 600000
24 changes: 11 additions & 13 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
#FROM node:15.3.0-alpine3.10 as builder
#WORKDIR /app
#ENV PATH /app/node_modules/.bin:$PATH
#COPY ./package.json .
#RUN yarn
#COPY . .
#RUN yarn build
#
#FROM busybox
#WORKDIR /app
#COPY --from=builder /app/build .
FROM node:15.3.0 as builder
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY ./package.json .
COPY ./.yarnrc .
COPY ./yarn.lock .
RUN yarn
COPY . .
RUN yarn build

FROM busybox
FROM busybox:1.32.0
WORKDIR /app
COPY ./build .
COPY --from=builder /app/build build
Loading

0 comments on commit 9f69b10

Please sign in to comment.