Permalink
Browse files

Merge branch 'dev'

  • Loading branch information...
vicgarcia committed Dec 19, 2018
2 parents f8083ad + fc701ae commit 7e341563beee0230ceebc6d77edc298457f14baa
@@ -1,8 +1,28 @@
A simple Django application I built to power the website for my upcoming wedding.
A simple Django application I built to power the website for my wedding.

Utilizes services from Stripe, Plivo, and Mapbox
We used the website to ...

See it in action at https://GertieAndVicGetMarried.com
Collect RSVPs via a form on the website.
Integrated with Plivo to send text messages to confirm RSVP.
Displayed a Mapbox widget to show the venue location, local hotels, and public transit.
Integrated with Stripe to accept monetary gifts via credit card form on the site.

Vic Garcia | http://vicg4rcia.com

The site is no longer live, but the application can be run locally using Docker.

```bash
# clone the repository
git clone git@github.com:vicgarcia/getmarried.git
# start docker
docker-composer up --build
# visit the dev site
# http://127.0.0.1:8000
# create a superuser account
./docker/django/manage.sh createsuperuser
# visit the admin and log in
# http://127.0.0.1:8000/admin/
```
@@ -3,11 +3,10 @@
from .models import *



class RSVPAdmin(admin.ModelAdmin):
list_display = ( 'name', 'attending', 'guests', 'phone', 'timestamp' )
fields = ( 'name', 'phone', 'attending', 'guests', 'note', 'timestamp' )
readonly_fields = ( 'name', 'phone', 'attending', 'guests', 'note', 'timestamp' )
readonly_fields = ( 'name', 'note', 'timestamp' )

admin.site.register(RSVP, RSVPAdmin)

@@ -22,5 +21,6 @@ class GiftAdmin(admin.ModelAdmin):

admin.site.unregister(Group)


admin.site.unregister(User)

@@ -10,29 +10,29 @@ class Meta:
fields = [ 'name', 'attending', 'guests', 'phone', 'note' ]

name = forms.CharField(
error_messages={
'required': 'Please provide your name.',
'max_length': 'Please limit name to 250 characters.',
}
)
error_messages={
'required': 'Please provide your name.',
'max_length': 'Please limit name to 250 characters.',
}
)

phone = forms.CharField(
max_length=None,
error_messages={
'required': 'Please provide a phone number.',
}
)
max_length=None,
error_messages={
'required': 'Please provide a phone number.',
}
)

guests = forms.IntegerField(
required=False,
error_messages={
'invalid': 'Please provide a number of guests.',
}
)
required=False,
error_messages={
'invalid': 'Please provide a number of guests.',
}
)

attending = forms.BooleanField(
required=False
)
required=False
)

def clean(self):
''' override the clean method for special handling for the attending field
@@ -131,24 +131,24 @@ class Meta:
)

email = forms.EmailField(
error_messages={
'max_length': 'Please limit email address to 250 characters.',
'required': 'Please provide your email address.',
'invalid': 'Please provide a valid email address.',
}
)
error_messages={
'max_length': 'Please limit email address to 250 characters.',
'required': 'Please provide your email address.',
'invalid': 'Please provide a valid email address.',
}
)

amount = forms.DecimalField(
max_value=1000.00,
min_value=10.00,
error_messages={
'min_value': 'Please provide an amount over $10.',
'max_value': 'Please provide an amount below $1000.',
'max_decimal_places': 'Please specify gift amount with 2 decimal places.',
'required': 'Please provide a gift amount.',
'invalid': 'Please provide a valid gift amount.',
}
)
max_value=1000.00,
min_value=10.00,
error_messages={
'min_value': 'Please provide an amount over $10.',
'max_value': 'Please provide an amount below $1000.',
'max_decimal_places': 'Please specify gift amount with 2 decimal places.',
'required': 'Please provide a gift amount.',
'invalid': 'Please provide a valid gift amount.',
}
)

def error_list(self):
''' return a flat list of errors for use in ajax form '''
No changes.
@@ -0,0 +1,16 @@
from django.core.management.base import BaseCommand, CommandError
from app.models import RSVP
from app.sms import send_sms_message



class Command(BaseCommand):
help = 'Mass text to guests who are attending.'

def add_arguments(self, parser):
pass

def handle(self, *args, **options):
for rsvp in RSVP.objects.filter(attending=True):
resp = send_sms_message(rsvp.phone, message)

@@ -1,6 +1,7 @@
import json
import stripe
import decimal
import datetime

from django.shortcuts import render, redirect
from django.conf import settings
@@ -18,16 +19,26 @@


def landing(request):
''' render html landing page '''
""" render html landing page """
return render(request, 'landing.html', {
'stripe_public_key': settings.STRIPE['public_key'],
'mapbox_api_token': settings.MAPBOX['token'],
})


def _rsvp_are_closed():
''' accept rsvps until oct 21 2017 '''
last_day = datetime.date(2017, 10, 21)
today = datetime.date.today()
return today > last_day


def rsvp(request):
''' accept rsvp form submit via ajax '''
""" accept rsvp form submit via ajax """
if request.method == 'POST':
if _rsvp_are_closed():
messages = [ 'RSVP are no longer being accepted.' ]
return JsonResponse({'success': False, 'messages': messages})
form = RSVPForm(request.POST)
if form.is_valid():
rsvp = form.save()
@@ -44,14 +55,24 @@ def rsvp(request):


def _convert_amount_for_stripe(amount):
''' convert decimal value from form to int for stripe '''
""" convert decimal value from form to int for stripe """
amount_as_string = '{0:.2f}'.format(amount)
return int( amount_as_string.replace('.', '') )


def _gifts_are_closed():
''' accept gifts up until nov 12 '''
last_day = datetime.date(2017, 11, 12)
today = datetime.date.today()
return today > last_day


def gift(request):
''' accept gift form submit via ajax '''
""" accept gift form submit via ajax """
if request.method == 'POST':
if _gifts_are_closed():
message = [ 'Gifts are no longer being accepted.' ]
return JsonResponse({'success': False, 'messages': messages})
form = GiftForm(request.POST)
errors = []
if form.is_valid():
@@ -80,7 +101,7 @@ def gift(request):

@csrf_exempt
def sms(request):
''' accept an incoming sms message and forward it to me & gertie '''
""" accept an incoming sms message and forward it to me & gertie """
if request.method == 'POST':
try:
text = request.POST['Text']
@@ -0,0 +1,25 @@
version: '3'

services:

mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: getmarried
MYSQL_PASSWORD: getmarried
MYSQL_DATABASE: getmarried

django:
build:
context: ./
dockerfile: ./docker/django/Dockerfile
ports:
- "8000:8000"
command: /code/docker/django/start.sh
volumes:
- .:/code
depends_on:
- mysql
@@ -0,0 +1,7 @@
FROM python:3.5-jessie
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
ADD requirements.txt /code/
WORKDIR /code
RUN pip install -r requirements.txt
RUN apt-get update && apt-get install -y mysql-client
@@ -0,0 +1,18 @@
#!/bin/bash

# use manage.py inside the running container from the host's shell

# enter the django shell
# ./docker/django/manage.sh shell

# work with migrations
# ./docker/django/manage.sh makemigrations
# ./docker/django/manage.sh migrate

ARGS="$@"
if [[ -z $ARGS ]]
then
ARGS="help"
fi

docker-compose exec django python /code/manage.py $ARGS
@@ -0,0 +1,17 @@
#!/bin/bash

# use pip inside the running container from the host's shell

# interact with pip
# ./docker/django/pip.sh install -r requirements.txt --upgrade

# output the requirements.txt
# ./docker/django/pip.sh freeze | dos2unix > requirements.txt

ARGS="$@"
if [[ -z $ARGS ]]
then
ARGS="help"
fi

docker-compose exec django pip $ARGS
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

cd /code/

echo "waiting for other builds to finish"

until mysqladmin -h mysql -u root -proot ping &> /dev/null; do
echo "waiting for mysql to start ..." && sleep 10
done

echo "mysql is up"

python manage.py migrate
python manage.py runserver 0.0.0.0:8000

This file was deleted.

Oops, something went wrong.
@@ -36,7 +36,11 @@ server {

# proxy non-static requests to django server
location / {
uwsgi_pass django;
include /opt/getmarried/uwsgi_params;
proxy_pass http://127.0.0.1:5007;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
@@ -3,9 +3,9 @@ Babel==2.4.0
Django==1.11
django-phonenumber-field==1.3.0
gunicorn==19.7.1
mysqlclient==1.3.12
packaging==16.8
phonenumberslite==8.4.2
pkg-resources==0.0.0
plivo==0.11.3
pyparsing==2.2.0
pytz==2017.2

This file was deleted.

Oops, something went wrong.
@@ -3,7 +3,7 @@ Description=getMarried
After=network.target

[Service]
User=vicg4rcia
User=getmarried
Group=www-data
Restart=on-failure
WorkingDirectory=/opt/getmarried

0 comments on commit 7e34156

Please sign in to comment.