Skip to content

Commit

Permalink
Merge pull request #13 from stephengtuggy/development
Browse files Browse the repository at this point in the history
Merge latest changes from development into master in preparation for a release
  • Loading branch information
stephengtuggy authored Aug 12, 2019
2 parents c74ff32 + 55344a7 commit 09de229
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 73 deletions.
55 changes: 9 additions & 46 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,55 +1,18 @@
version: '2'
jobs:
build_and_test:
machine: true
working_directory: ~/job-history-circleci
docker:
# The primary container is an instance of the first image listed. The job's commands run in this container.
- image: circleci/python:3.7-buster
name: job_history_web
environment:
JOB_HISTORY_SECRET_KEY: xoB:hNW?ap`A8{RA2]Kips%5)<-_H2-,d/pn@*e:SczdrY!\dzt4#mG
JOB_HISTORY_DEBUG: True
JOB_HISTORY_ALLOWED_HOSTS: 0.0.0.0
JOB_HISTORY_DB_NAME: job_history
JOB_HISTORY_DB_USERNAME: postgres
JOB_HISTORY_DB_PASSWORD: yR*TBPaYpB@68bQ=@m;nzsE(wi*C})zZA4pT]XLkBVV6TT*tkG;QFor
JOB_HISTORY_DB_HOST: job_history_db
JOB_HISTORY_DB_PORT: 5432
JOB_HISTORY_STATIC_ROOT: /home/circleci/job-history-circleci/app/public/static/
JOB_HISTORY_STATIC_URL: /static/
# The secondary container is an instance of the second listed image which is run in a common network where ports exposed on the primary container are available on localhost.
- image: mdillon/postgis:11
name: job_history_db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: yR*TBPaYpB@68bQ=@m;nzsE(wi*C})zZA4pT]XLkBVV6TT*tkG;QFor
POSTGRES_DB: job_history
steps:
- checkout
- run:
name: Update Debian Package List
command: sudo apt-get -y update
- run:
name: Install Debian Packages
command: sudo apt-get -y install netcat postgresql-client libgdal-dev
# - run:
# name: Upgrade Debian Packages
# command: sudo apt-get -y dist-upgrade
- run:
name: Pip Install
command: sudo pip install -r ./app/requirements.txt
- run:
name: Make sure docker-entrypoint.sh is executable
command: chmod u+x app/docker-entrypoint.sh
- run:
name: Make sure tcp-port-wait.sh is executable
command: chmod u+x app/tcp-port-wait.sh
- run:
name: Make sure manage.py is executable
command: chmod u+x app/manage.py
- run:
name: Actually run the tests
command: cd app/ && ./docker-entrypoint.sh ./manage.py test
- run: |
curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o ~/docker-compose
chmod +x ~/docker-compose
sudo mv ~/docker-compose /usr/local/bin/docker-compose
- run: |
mv docker-compose.circleci.yml docker-compose.yml
- run: |
docker-compose up --build --exit-code-from web --abort-on-container-exit
workflows:
version: 2
on_push:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ Also, you will need a copy of a file called `.env`. Ask me for this file, and I

Once you have these items in place, run the command `docker-compose up --build`, either in PowerShell on Windows, or in Terminal on macOS or Linux. You should see Docker Compose pulling the latest copy of each source docker image, then building the main image for this app, and finally, spinning up both containers.

Assuming that this command completes successfully, you can now open your favorite web browser, and enter the URL: [http://localhost:8000/administrate](http://localhost:8000/administrate). Oh, wait. The first time you run this app, you will need to create a user account for yourself. To do so, open another PowerShell / Terminal window in the `app` folder, and run this sequence of commands, one at a time:
Assuming that this command completes successfully, you can now open your favorite web browser, and enter the URL: [http://localhost:8000/administrate/](http://localhost:8000/administrate/). Oh, wait. The first time you run this app, you will need to create a user account for yourself. To do so, open another PowerShell / Terminal window in the `app` folder, and run this sequence of commands, one at a time:

```sh
docker-compose exec web bash
./manage.py createsuperuser
exit
```

After the createsuperuser command, follow the prompts to set up your first user account / login. You should then be able to log in at [the above URL](http://localhost:8000/administrate). From that point, you can create other user accounts if you wish using the web UI.
After the createsuperuser command, follow the prompts to set up your first user account / login. You should then be able to log in at [the above URL](http://localhost:8000/administrate/). From that point, you can create other user accounts if you wish using the web UI.

## Use

Expand Down
1 change: 1 addition & 0 deletions app/jobHistory/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default_app_config = 'jobHistory.apps.JobHistoryConfig'
41 changes: 23 additions & 18 deletions app/jobHistory/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import datetime

from django.db import models
from django.utils.translation import gettext_lazy as _


class Employer(models.Model):
class Meta:
verbose_name = _('Employer')

short_name = models.CharField(max_length=50, unique=True, blank=False, null=False, verbose_name=_('Short Name'))
long_name = models.CharField(max_length=254, unique=True, blank=False, null=True, verbose_name=_('Long Name'))
industry = models.CharField(max_length=254, blank=True, null=False, verbose_name=_('Industry'))
Expand All @@ -27,7 +29,7 @@ def __str__(self):
class Position(models.Model):
class Meta:
verbose_name = _('Position')

employer = models.ForeignKey(Employer, on_delete=models.CASCADE, verbose_name=_('Employer'))
title = models.CharField(max_length=200, blank=False, null=False, verbose_name=_('Title'))
responsibilities = models.TextField(blank=True, null=False, verbose_name=_('Responsibilities'))
Expand Down Expand Up @@ -56,7 +58,7 @@ def __str__(self):
class JobTimePeriod(models.Model):
class Meta:
verbose_name = _('Job Time Period')

position = models.ForeignKey(Position, on_delete=models.CASCADE, verbose_name=_('Position'))
start_year = models.PositiveIntegerField(null=False, verbose_name=_('Start Year'))
start_month = models.PositiveSmallIntegerField(null=True, verbose_name=_('Start Month'))
Expand All @@ -75,21 +77,24 @@ class Meta:
work_zip_or_postal_code = models.CharField(max_length=50, blank=True, null=False, verbose_name=_('Work Zip Code or Postal Code'))
work_country = models.CharField(max_length=200, blank=True, null=False, verbose_name=_('Work Country'))

@property
def startDate(self):
return datetime.date(self.start_year, self.start_month, self.start_day)

@property
def endDate(self):
if self.is_current_position:
return datetime.date.today()
else:
return datetime.date(self.end_year, self.end_month, self.end_day)

def __str__(self):
retVal = str(self.position)
retVal += " from "
retVal += str(self.start_year)
if self.start_month is not None:
retVal += "-" + str(self.start_month)
if self.start_day is not None:
retVal += "-" + str(self.start_day)
retVal += " to "
ret_val = str(self.position)
ret_val += " from "
ret_val += str(self.startDate)
ret_val += " to "
if self.is_current_position:
retVal += "present"
ret_val += "present"
else:
retVal += str(self.end_year)
if self.end_month is not None:
retVal += "-" + str(self.end_month)
if self.end_day is not None:
retVal += "-" + str(self.end_day)
return retVal
ret_val += str(self.endDate)
return ret_val
8 changes: 8 additions & 0 deletions app/jobHistory/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path
from .views import IndexView

app_name = 'jobHistory'

urlpatterns = [
path('', IndexView.as_view(), name='index'),
]
13 changes: 13 additions & 0 deletions app/jobHistory/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import operator

from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.views import generic

from .models import JobTimePeriod

# Create your views here.
class IndexView(LoginRequiredMixin, generic.ListView):
template_name = 'jobHistory/index.html'
context_object_name = 'chronological_job_list'

def get_queryset(self):
job_time_periods = JobTimePeriod.objects.all()
return sorted(job_time_periods, key=operator.attrgetter('endDate'), reverse=True)
27 changes: 23 additions & 4 deletions app/jobHistorySite/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,21 @@

import os

from django.urls import reverse_lazy

import environ
env = environ.Env()
env = environ.Env(
JOB_HISTORY_SECRET_KEY=str,
JOB_HISTORY_DEBUG=bool,
JOB_HISTORY_ALLOWED_HOSTS=list,
JOB_HISTORY_DB_NAME=str,
JOB_HISTORY_DB_USERNAME=str,
JOB_HISTORY_DB_PASSWORD=str,
JOB_HISTORY_DB_HOST=str,
JOB_HISTORY_DB_PORT=int,
JOB_HISTORY_STATIC_URL=str,
JOB_HISTORY_STATIC_ROOT=str
)

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Expand All @@ -30,11 +43,12 @@

ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]', '[::]']
if env('JOB_HISTORY_ALLOWED_HOSTS'):
ALLOWED_HOSTS += env('JOB_HISTORY_ALLOWED_HOSTS').split(',')
ALLOWED_HOSTS += env('JOB_HISTORY_ALLOWED_HOSTS')

# Application definition

INSTALLED_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -46,6 +60,7 @@

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
Expand All @@ -59,7 +74,9 @@
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
Expand Down Expand Up @@ -125,7 +142,9 @@

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
STATICFILES_STORAGE='whitenoise.storage.CompressedManifestStaticFilesStorage'

STATIC_URL = env('JOB_HISTORY_STATIC_URL')
STATIC_ROOT = env('JOB_HISTORY_STATIC_ROOT')

LOGIN_URL = reverse_lazy('login')
8 changes: 6 additions & 2 deletions app/jobHistorySite/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include, reverse_lazy
from django.views.generic import RedirectView

urlpatterns = [
path('administrate/', admin.site.urls, name="admin"),
path('administrate/', admin.site.urls),
path('registration/', include('django.contrib.auth.urls')),
path('jobHistory/', include('jobHistory.urls')),
path('', RedirectView.as_view(url=reverse_lazy('jobHistory:index'), permanent=False))
]
3 changes: 2 additions & 1 deletion app/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Django>=2.2.4,<2.3
django-environ>=0.4.5,<0.5
psycopg2-binary>=2.8.3,<2.9
gdal>=2.3.0,<2.4
GDAL>=2.3.0,<2.4
whitenoise>=4.1.2,<4.2

astroid>=2.2.5,<2.3
colorama>=0.4.1,<0.5
Expand Down
19 changes: 19 additions & 0 deletions app/templates/base/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<div id="header-block">
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. <a href="{% url 'admin:index' %}">Enter data</a>. <a href="{% url 'jobHistory:index' %}">View job history</a>. <a href="{% url 'logout' %}">Log out</a>.</p>
{% else %}
<p>Please <a href="{% url 'login' %}">log in</a>.</p>
{% endif %}
</div>
<div id="content-block">
{% block content %}
{% endblock %}
</div>
</body>
</html>
9 changes: 9 additions & 0 deletions app/templates/jobHistory/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "base/base.html" %}

{% block title %}Your Job History{% endblock %}

{% block content %}
{% for job_time_period in chronological_job_list %}
<p>{{ job_time_period }}</p>
{% endfor %}
{% endblock %}
40 changes: 40 additions & 0 deletions app/templates/registration/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{% extends "base/base.html" %}

{% block title %}Login{% endblock %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>

{# Assumes you setup the password_reset view in your URLconf #}
{% comment %} <p><a href="{% url 'password_reset' %}">Lost password?</a></p> {% endcomment %}

{% endblock %}
50 changes: 50 additions & 0 deletions docker-compose.circleci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
version: "3.7"
services:
web:
build: ./app
container_name:
job_history_web
environment:
- JOB_HISTORY_SECRET_KEY
- JOB_HISTORY_DEBUG
- JOB_HISTORY_ALLOWED_HOSTS
- JOB_HISTORY_DB_NAME
- JOB_HISTORY_DB_USERNAME
- JOB_HISTORY_DB_PASSWORD
- JOB_HISTORY_DB_HOST
- JOB_HISTORY_DB_PORT
- JOB_HISTORY_STATIC_ROOT
- JOB_HISTORY_STATIC_URL
command:
/usr/src/app/manage.py test
depends_on:
- db
ports:
- "8000:8000"
networks:
- job_history_net_1
restart:
"no"
db:
image:
mdillon/postgis:11
container_name:
job_history_db
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
volumes:
- "pg_data:/var/lib/postgresql/data"
ports:
- "5432:5432"
networks:
- job_history_net_1
restart:
"no"

networks:
job_history_net_1:

volumes:
pg_data:

0 comments on commit 09de229

Please sign in to comment.