diff --git a/.gitignore b/.gitignore index fa6fe3ed..f946ffff 100644 --- a/.gitignore +++ b/.gitignore @@ -293,4 +293,7 @@ cbv3_django_prototype/media/ .envs/* ## IDE ignores -.vscode \ No newline at end of file +.vscode + +## Docker ignores +db_data \ No newline at end of file diff --git a/README.md b/README.md index 41a292e3..df72f83c 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,143 @@ The API spec all the proof-of-concepts: https://app.swaggerhub.com/apis-docs/bil Crowdsourced brainstorm of problems we want to solve: https://pad.riseup.net/p/BecKdThFsevRmmG_tqFa-keep -# Setup +## Setup -Please see [instructions here](https://github.com/codebuddies/django-concept/wiki/Contribution-instructions) +Although it is possible to run this locally, we recommend you run CodeBuddies locally using Docker. We assume you have Docker installed, but if not head on over to the Docker [Getting Started](https://www.docker.com/products/docker-desktop) guide and install Docker for your operating system. -This project is not deployed yet, but will interact as the API supporting [https://github.com/codebuddies/react-concept](https://github.com/codebuddies/react-concept) +These instructions have been used on the following operating systems. + +* Linux +* Mac OS +* Windows 10 Pro + +Please note that Windows 10 Home is not supported by Docker Desktop at this time. + +1. Fork this repository. This creates a copy of the repository for you to work on. For more help see this GitHub guide: [Fork a repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo). +2. Clone your fork. This creates a copy on your local computer. For more help see this GitHub guide: [Cloning a repository](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository). + +```plain +git clone git@github.com:codebuddies/django-concept.git cb +``` + +3. Navigate into the project directory. + +```plain +cd cb +``` + +4. Start the local development environment. + +```plain +docker-compose up -d +``` + +This will run the following components: + +- Nginx, a web server: http://localhost:8000 +- Adminer, a DB front-end: http://localhost:8001 +- Mailhog, a dummy mailbox: http://localhost:8025 +- A PostgreSQL database +- The Django web application + +You can view the application or make API calls by using the Nginx URL. + +You can access the database through the Adminer front-end or using a local PostgreSQL client and the following URL: `postgres://babyyoda:mysecretpassword@localhost:5432/codebuddies`. + +To stop the application and remove all containers, run the following. + +```plain +docker-compose down +``` + +## Editing Code + +With the local environment running, you can modify the application code in your editor of choice. As you save changes, the application should reload automatically. There should be no need to restart containers to see code changes. + +## Other Tasks + +### Logs + +View logs from all containers. + +```plain +docker-compose logs +``` + +View logs from a single container (in this case the `app` container). + +```plain +docker-compose logs app +``` + +You can use the same structure to view logs for the other containers; `nginx`, `db`, `mailhog`, `adminer`, `app`. + +If you would like to tail the logs in the console then you remove the detach flag, `-d`, from the `docker-compose up` command that you use to start the application. + +### Django Management + +The following are examples of some common Django management commands that you may need to run. + +* Make Migrations: `docker-compose run --rm manage makemigrations` +* Merge Migrations: `docker-compose run --rm manage makemigrations --merge` +* Run Migrations: `docker-compose run --rm manage` +* Test: `docker-compose run --rm manage test` + +To see the full list of management commands use `help`. + +```plain +docker-compose run --rm manage help +``` + +## Removing Everything + +To remove all containers run the following: + +```plain +docker-compose rm +``` + +This will leave a copy of the data volume (holding the PostgreSQL data) behind. To remove that you will need to identify and remove the data volume. + +```plain +docker volume ls + +DRIVER VOLUME NAME +local django-concept_db_data +``` + +Note the name of the data volume, in this case `django-concept_db_data` and delete it. + +```plain +docker volume rm django-concept_db_data +``` + +Note: it is likely that cached copies of your container images will be retained by Docker on your local machine. This is done to speed things up if you require these images in future. To completely remove unused container images and networks, we recommend you follow Docker [pruning guide](https://docs.docker.com/config/pruning/). + +## Proof-of-concept Goals + +A resource datastore + +- save resource +- delete resource +- update resource +- list resource +- search resources + +Resource: + +- title +- description +- type +- credit +- url +- referrer + +The start of a resource bookmarking/archiving service. + +- Calendar/hangouts + - How easy would it be to make a calendar widget that lets users block out times they're free for hangouts? + +# Findings + +# Technologies Used diff --git a/cbv3_django_prototype/Dockerfile b/cbv3_django_prototype/Dockerfile new file mode 100644 index 00000000..c2db4caf --- /dev/null +++ b/cbv3_django_prototype/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.7 + +RUN apt-get update && \ + apt-get install -y && \ + pip3 install uwsgi + +COPY ./requirements/ /opt/cbv3_django_prototype/requirements/ + +RUN python3 -m pip install --upgrade pip +RUN pip3 install -r /opt/cbv3_django_prototype/requirements/local.txt + +RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi + +ENV DJANGO_ENV=prod +ENV PYTHONUNBUFFERED 1 +ENV PYTHONPATH /opt/cbv3_django_prototype/ + +COPY ./ /opt/cbv3_django_prototype/ + +EXPOSE 8000 + +CMD ["uwsgi", "--ini", "/opt/cbv3_django_prototype/uwsgi.ini"] \ No newline at end of file diff --git a/cbv3_django_prototype/cbv3_django_prototype/resources/migrations/0008_merge_20200116_0104.py b/cbv3_django_prototype/cbv3_django_prototype/resources/migrations/0008_merge_20200116_0104.py new file mode 100644 index 00000000..2a4839c5 --- /dev/null +++ b/cbv3_django_prototype/cbv3_django_prototype/resources/migrations/0008_merge_20200116_0104.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2020-01-16 09:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0007_auto_20200110_1032'), + ('resources', '0005_resource_tags'), + ] + + operations = [ + ] diff --git a/cbv3_django_prototype/config/settings/local.py b/cbv3_django_prototype/config/settings/local.py index d7d97038..813d00e8 100644 --- a/cbv3_django_prototype/config/settings/local.py +++ b/cbv3_django_prototype/config/settings/local.py @@ -26,7 +26,10 @@ # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-host -EMAIL_HOST = "localhost" +EMAIL_HOST = env( + "EMAIL_HOST", + default="localhost", +) # https://docs.djangoproject.com/en/dev/ref/settings/#email-port EMAIL_PORT = 1025 diff --git a/cbv3_django_prototype/config/wsgi.py b/cbv3_django_prototype/config/wsgi.py index facad167..5d50f7ed 100644 --- a/cbv3_django_prototype/config/wsgi.py +++ b/cbv3_django_prototype/config/wsgi.py @@ -28,7 +28,7 @@ # if running multiple sites in the same mod_wsgi process. To fix this, use # mod_wsgi daemon mode with each site in its own daemon process, or use # os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION diff --git a/cbv3_django_prototype/requirements/local.txt b/cbv3_django_prototype/requirements/local.txt index 9af4c30b..899e8518 100644 --- a/cbv3_django_prototype/requirements/local.txt +++ b/cbv3_django_prototype/requirements/local.txt @@ -27,3 +27,4 @@ django-debug-toolbar==2.0 # https://github.com/jazzband/django-debug-toolbar django-extensions==2.2.1 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==3.5.1 # https://github.com/pytest-dev/pytest-django +django-taggit==1.2.0 # https://github.com/jazzband/django-taggit diff --git a/cbv3_django_prototype/uwsgi.ini b/cbv3_django_prototype/uwsgi.ini new file mode 100644 index 00000000..f5342ca4 --- /dev/null +++ b/cbv3_django_prototype/uwsgi.ini @@ -0,0 +1,10 @@ +[uwsgi] +http-socket = :8000 +chdir = /opt/cbv3_django_prototype +wsgi-file = /opt/cbv3_django_prototype/config/wsgi.py +master = 1 +processes = 2 +threads = 2 +py-autoreload = 3 +uid = uwsgi +gid = uwsgi \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..98edc12c --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,92 @@ +version: "3" + +volumes: + db_data: {} + +services: + # The PostgreSQL container creates the codebuddies database on first launch. + # All data is stored in the db_data volume on the host machine. This ensures + # data is persisted across container restarts. + db: + image: postgres:11-alpine + container_name: db + restart: on-failure + ports: + - "5432:5432" + volumes: + - db_data:/var/lib/postgresql/data + environment: + - POSTGRES_PASSWORD=mysecretpassword + - POSTGRES_USER=babyyoda + - POSTGRES_DB=codebuddies + + # The app container uses uwsgi to run the Django application. It is configured + # to run migrations on first start-up and to use Mailhog as the mail server. + # The application is not exposed to the host as all traffic is proxied through + # nginx. The local project folder is mounted into the container as a volume to + # allow development to be done on the host machine. + app: + build: ./cbv3_django_prototype + container_name: app + restart: on-failure + command: > + sh -c "python /opt/cbv3_django_prototype/manage.py migrate && + uwsgi --ini /opt/cbv3_django_prototype/uwsgi.ini" + volumes: + - ./cbv3_django_prototype:/opt/cbv3_django_prototype + environment: + - DATABASE_URL=postgres://babyyoda:mysecretpassword@db:5432/codebuddies + - EMAIL_HOST=mailhog + depends_on: + - db + + # The nginx front-end is configured to proxy all traffic to the Django application. + # We may want to use this to host static content. It is configured to reload + # configuration every 6 hours. + nginx: + image: nginx:1.17-alpine + container_name: nginx + restart: on-failure + ports: + - "8000:80" + volumes: + - ./nginx:/etc/nginx/conf.d + command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"''' + depends_on: + - app + + # Adminer is a front-end for PostgreSQL. + # It isn't required to run CodeBuddies but may be useful as a graphical interface + # to the database. + adminer: + image: adminer:latest + container_name: adminer + restart: on-failure + ports: + - 8001:8080 + + # Mailhog is a mail server that traps all outbound mail and presents it in a web + # interface that is easily browsable. This may prove useful when testing functionality + # that results in emails to users. + mailhog: + image: mailhog/mailhog:latest + container_name: mailhog + restart: on-failure + ports: + - 8025:8025 + + # Manager allows you to run Django management tasks on the application. + manage: + container_name: manage + restart: on-failure + build: ./cbv3_django_prototype + command: shell + entrypoint: /usr/local/bin/python3 /opt/cbv3_django_prototype/manage.py + volumes: + - ./cbv3_django_prototype:/opt/cbv3_django_prototype + environment: + - DATABASE_URL=postgres://babyyoda:mysecretpassword@db:5432/codebuddies + - EMAIL_HOST=mailhog + depends_on: + - db + diff --git a/nginx/app.conf b/nginx/app.conf new file mode 100644 index 00000000..7021b069 --- /dev/null +++ b/nginx/app.conf @@ -0,0 +1,15 @@ +upstream app { + server app:8000; +} + +server { + listen 80; + server_name localhost; + + location / { + proxy_pass http://app; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} \ No newline at end of file