diff --git a/.elasticbeanstalk/config.yml b/.elasticbeanstalk/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..cd558c9735f25e36cd220c7eea685b88c92b1996 --- /dev/null +++ b/.elasticbeanstalk/config.yml @@ -0,0 +1,12 @@ +branch-defaults: + $GIT_BRANCH: + environment: $EB_ENV +global: + application_name: $EB_APP + default_ec2_keyname: EastCoastBPKey + default_platform: 64bit Amazon Linux 2015.09 v2.0.8 running Docker 1.9.1 + default_region: us-east-1 + profile: null + sc: git +deploy: + artifact: deployment.zip diff --git a/.env.default b/.env.default index c6fe427a7cc62b79731d861895690d98250d3f57..c5ef14bdcc5a5eff7cf508bfbe2d554ee1dad1a5 100644 --- a/.env.default +++ b/.env.default @@ -7,3 +7,9 @@ DB_USER=$DB_USER DB_PASSWORD=$DB_PASSWORD DB_HOST=$DB_HOST DB_PORT=$DB_PORT +BUILDING_DB_NAME=$BUILDING_DB_NAME +BUILDING_DB_USER=$BUILDING_DB_USER +BUILDING_DB_PASSWORD=$BUILDING_DB_PASSWORD +BUILDING_DB_HOST=$BUILDING_DB_HOST +BUILDING_DB_PORT=$BUILDING_DB_PORT + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d8d1b6b4511eae316d3a9e6b0b93179717526a6f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +# Dockerfile + +# FROM directive instructing base image to build upon +FROM ubuntu:16.10 + +ENV CODEROOT=/home/docker/code + +# Log enironment variables. +ENV NGINXERR=/var/log/nginx.err.log +ENV NGINXREQ=/var/log/nginx.req.log +ENV UWSGIERR=/var/log/uwsgi.err.log +ENV UWSGIREQ=/var/log/uwsgi.req.log + +# Custom environment variables. These change from project to project. +ARG DOMAIN +ENV DOMAIN=${DOMAIN} +ARG NUM_PROCESSES +ENV NUM_PROCESSES=${NUM_PROCESSES} +ARG NUM_THREADS +ENV NUM_THREADS=${NUM_THREADS} + +# Add the nginx reposoitory. We need 1.8 in order to support adding CORS headers to error responses. +RUN apt-get update +RUN apt-get install -y --no-install-recommends software-properties-common +RUN add-apt-repository ppa:nginx/stable + +# Install dependencies. +RUN apt-get update +RUN apt-get install -y --no-install-recommends python3 python3-software-properties python3-dev python3-setuptools python3-pip +RUN apt-get install -y --no-install-recommends nginx supervisor +RUN apt-get install -y --no-install-recommends build-essential git +RUN apt-get install -y --no-install-recommends libpq-dev +RUN apt-get install -y libpcre3 libpcre3-dev +RUN pip3 install uwsgi -I +RUN rm -rf /var/lib/apt/lists/* + +COPY ./requirements.txt $CODEROOT/requirements.txt + +# Install application requirements. +RUN pip3 install -r $CODEROOT/requirements.txt + +# Put the code somewhere. +ADD . $CODEROOT/ + +# Create the www user. +RUN useradd -ms /bin/bash www + +# Create the log files. +RUN \ + touch $NGINXERR && touch $NGINXREQ && \ + touch $UWSGIERR && touch $UWSGIREQ + +RUN \ + replace_vars() { \ + echo "Copying environment variables from $1 to $2."; \ + sed -e "s/\$DOMAIN/$DOMAIN/g" \ + -e "s@\$CODEROOT@$CODEROOT@g" \ + -e "s@\$NUM_PROCESSES@$NUM_PROCESSES@g" \ + -e "s@\$NUM_THREADS@$NUM_THREADS@g" \ + -e "s@\$NGINXERR@$NGINXERR@g" \ + -e "s@\$NGINXREQ@$NGINXREQ@g" \ + -e "s@\$UWSGIERR@$UWSGIERR@g" \ + -e "s@\$UWSGIREQ@$UWSGIREQ@g" $1 > $2; \ + }; \ + replace_vars $CODEROOT/config/nginx.conf /etc/nginx/nginx.conf && \ + replace_vars $CODEROOT/config/supervisor.conf /etc/supervisor/conf.d/supervisor.conf && \ + replace_vars $CODEROOT/config/uwsgi.ini $CODEROOT/uwsgi.ini + +# Make migrations +RUN cd $CODEROOT && python3 manage.py migrate --noinput + +# Collect static files +RUN cd $CODEROOT && python3 manage.py collectstatic --noinput + +# EXPOSE port 80 to allow communication to/from server +EXPOSE 80 + +CMD ["supervisord", "-n"] diff --git a/Dockerrun.aws.json b/Dockerrun.aws.json new file mode 100644 index 0000000000000000000000000000000000000000..d334d795f3e285cefe8e903ea2479d5cdad07ab5 --- /dev/null +++ b/Dockerrun.aws.json @@ -0,0 +1,16 @@ +{ + "AWSEBDockerrunVersion": "1", + "Authentication": { + "Bucket": "dockerauth.blocpower.org", + "Key": "$DOCKER_REPO.json" + }, + "Image": { + "Name": "blocp/$DOCKER_REPO" + }, + "Ports": [ + { + "HostPort": "80", + "ContainerPort": "80" + } + ] +} diff --git a/blocnote/apps/financialInputs/templates/financialInputs/index.html b/blocnote/apps/financialInputs/templates/financialInputs/index.html new file mode 100644 index 0000000000000000000000000000000000000000..580a3fd1eb3198bf92d90f9d2701d3357c0f837e --- /dev/null +++ b/blocnote/apps/financialInputs/templates/financialInputs/index.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} +{% load staticfiles %} + +{% block content %} +

+ This is finance inputs +

+
+ Building id: {{ id }}
+ Address: {{ address }} +
+{% endblock %} + +{% block scripts %} + + + +{% endblock %} diff --git a/blocnote/apps/financialInputs/views.py b/blocnote/apps/financialInputs/views.py index 5c1ddf7b8a4bf7d5d48a00aac15f59de67ce4cd4..89bc0b7b4181c292eaee8557bf0a9311e5c39057 100644 --- a/blocnote/apps/financialInputs/views.py +++ b/blocnote/apps/financialInputs/views.py @@ -1,6 +1,14 @@ from django.shortcuts import render from django.http import HttpResponse +from django.db import connections -def index(request): - return HttpResponse("Hello, world. You're at the financial-inputs index.") +def index(request, building_id): + cursor = connections['building_db'].cursor() + cursor.execute('SELECT * FROM public.get_building(in_building_id := {})'.format(building_id)) + + columns = [col[0] for col in cursor.description] + row = cursor.fetchone() + building = dict(zip(columns, row)) + context = {'address': building['address'], 'id': building['building_id']} + return render(request, 'financialInputs/index.html', context=context) diff --git a/blocnote/settings.py b/blocnote/settings.py index 47b7329269e4cc0162aff0d62ab503474fa08803..eef190ff4ac4b02e7a27679855501695620cc5d2 100644 --- a/blocnote/settings.py +++ b/blocnote/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'blocnote.apps.financialInputs', ] MIDDLEWARE = [ @@ -58,7 +59,7 @@ ROOT_URLCONF = 'blocnote.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [(os.path.join(BASE_DIR, 'blocnote/templates')), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -85,6 +86,14 @@ DATABASES = { 'PASSWORD': config('DB_PASSWORD'), 'HOST': config('DB_HOST'), 'PORT': config('DB_PORT'), + }, + 'building_db': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': config('BUILDING_DB_NAME'), + 'USER': config('BUILDING_DB_USER'), + 'PASSWORD': config('BUILDING_DB_PASSWORD'), + 'HOST': config('BUILDING_DB_HOST'), + 'PORT': config('BUILDING_DB_PORT'), } } diff --git a/blocnote/static/favicon.ico b/blocnote/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4734fd6c1602259f6c542b50fff102ae6bdf22be Binary files /dev/null and b/blocnote/static/favicon.ico differ diff --git a/blocnote/static/scripts/request.js b/blocnote/static/scripts/request.js new file mode 100644 index 0000000000000000000000000000000000000000..2c9af26653af4f5b71e12b2787780b21dd957beb --- /dev/null +++ b/blocnote/static/scripts/request.js @@ -0,0 +1,36 @@ +/** + * Checks if a network request came back fine, and throws an error if not + * + * @param {object} response A response from a network request + * + * @return {object|undefined} Returns either the response, or throws an error + */ +function checkStatus(response) { + if (response.ok) { + return response; + } + + + + + const error = new Error(response.statusText); + error.response = response; + error.responseBody = response.json(); + throw error; +} + +/** + * Requests a URL, returning a promise + * + * @param {string} url The URL we want to request + * @param {object} [options] The options we want to pass to "fetch" + * + * @return {object} An object containing either "payload" or "err" + */ +function request(url, options) { + return fetch(url, options) + .then(checkStatus) + .then(response => response.json()) + .then(payload => ({ payload })) + .catch(err => ({ err })); +} diff --git a/blocnote/static/styles/header.css b/blocnote/static/styles/header.css new file mode 100644 index 0000000000000000000000000000000000000000..8be475004ab6af21bfb0fce77f47d95bac7e6b5f --- /dev/null +++ b/blocnote/static/styles/header.css @@ -0,0 +1,13 @@ +.navbar { + height: 70px; + padding: 0; +} + +.bg-inverse { + background-color: #343434 !important; +} + +.navbar-brand { + border-right: 2px solid #343434; + padding: 0 20px; +} diff --git a/blocnote/static/svg/logo.svg b/blocnote/static/svg/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..e869e2bbbce2cbb0f6fc1fe78d70127cd1ce595a --- /dev/null +++ b/blocnote/static/svg/logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/blocnote/templates/base.html b/blocnote/templates/base.html new file mode 100644 index 0000000000000000000000000000000000000000..3e4727eef5394dac81384e3337815d310bf5c934 --- /dev/null +++ b/blocnote/templates/base.html @@ -0,0 +1,20 @@ +{% load staticfiles %} + + + + + + + + + {% block title %}BlocNote{% endblock %} + + + {% block head %}{% endblock %} + + + + {% block content %}{% endblock %} + + + diff --git a/blocnote/urls.py b/blocnote/urls.py index 81711c8c0d3c1951d321265292c3127d2754ea7f..b55bc834d9683a21f7deb1d2ecd11b97418b8ab6 100644 --- a/blocnote/urls.py +++ b/blocnote/urls.py @@ -17,6 +17,6 @@ from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ - url(r'^financial-inputs/', include('blocnote.apps.financialInputs.urls')), + url(r'^building/(?P[0-9]+)/financial-inputs', include('blocnote.apps.financialInputs.urls')), url(r'^admin/', admin.site.urls), ] diff --git a/config/nginx.conf b/config/nginx.conf new file mode 100644 index 0000000000000000000000000000000000000000..cdf6e0e33b0e337ba219eb10dbaea1ec786bce26 --- /dev/null +++ b/config/nginx.conf @@ -0,0 +1,34 @@ +daemon off; +user www; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + gzip on; + charset utf-8; + client_max_body_size 10M; + + access_log $NGINXREQ; + error_log $NGINXERR; + + server { + listen 80; + listen [::]:80; + server_name $DOMAIN; + + location / { + include uwsgi_params; + uwsgi_pass unix:$CODEROOT/uwsgi.sock; + } + location /static/ { + autoindex on; + root $CODEROOT; + } + } +} diff --git a/config/supervisor.conf b/config/supervisor.conf new file mode 100644 index 0000000000000000000000000000000000000000..477f24b2c5f97b6cbcedb1ad3830bb0630b0bb2d --- /dev/null +++ b/config/supervisor.conf @@ -0,0 +1,5 @@ +[program:uwsgi] +command = /usr/local/bin/uwsgi --ini $CODEROOT/uwsgi.ini -O 2 + +[program:nginx] +command = /usr/sbin/nginx diff --git a/config/uwsgi.ini b/config/uwsgi.ini new file mode 100644 index 0000000000000000000000000000000000000000..b6300f5e13713e4ec82bdaba56476dc9838be3fe --- /dev/null +++ b/config/uwsgi.ini @@ -0,0 +1,22 @@ +[uwsgi] +# This is used if no configuration is specified. +ini = :base + +socket = $CODEROOT/uwsgi.sock +# Nginx should be able to find this socket. +chmod-socket = 666 + +master = true +# Number of processes and workers should be determined at build time +# Should be based on the type of instance that it is running on +processes = $NUM_PROCESSES +threads = $NUM_THREADS + +# Set loggers. +req-logger = file:$UWSGIREQ +logger = file:$UWSGIERR + +[base] +# cd into the app directory +chdir = $CODEROOT/ +module = blocnote.wsgi:application