Commit c31a9907 authored by David Haynes's avatar David Haynes 🙆
Browse files

Project cleanup + updates + docker yarn build

parent b67231a2
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
*.swp *.swp
*.pyc *.pyc
.virtualenv .virtualenv
.vagrant/
venv venv
.venv .venv
/provisioning/playbook.retry /provisioning/playbook.retry
...@@ -14,7 +13,122 @@ htmlcov/ ...@@ -14,7 +13,122 @@ htmlcov/
.idea .idea
__pycache__/ __pycache__/
.vscode .vscode
go/sourceme.sh
.DS_STORE .DS_STORE
node_modules/ node_modules/
go/static/main.js go/static/main.js
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
...@@ -14,3 +14,9 @@ ADD . /go/ ...@@ -14,3 +14,9 @@ ADD . /go/
# Install pip dependecies # Install pip dependecies
RUN pip install pipenv RUN pip install pipenv
RUN pipenv install --system --deploy RUN pipenv install --system --deploy
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get install -y nodejs
RUN apt-get install -y build-essential
RUN npm install -g yarn
\ No newline at end of file
...@@ -32,19 +32,19 @@ ...@@ -32,19 +32,19 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:25df265e1fdb74f7e7305a1de620a84681bcc9c05e84a3ed97e4a1a63024f18d", "sha256:0292a7ad7d8ffc9cfc6a77f043d2e81f5bbc360c0c4a1686e130ef3432437d23",
"sha256:d6d94554abc82ca37e447c3d28958f5ac39bd7d4adaa285543ae97fb1129fd69" "sha256:e89f613e3c1f7ff245ffee3560472f9fa9c07060b11f65e1de3cb763f8dcd4b9"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.9" "version": "==2.0.10"
}, },
"django-cas-client": { "django-cas-client": {
"hashes": [ "hashes": [
"sha256:2a190c9e651df3a65840206b38a9fc1c2c404696fcaf66fc69a684591f56d978", "sha256:6d71d59db35f8a7677ee654dc9d4eac5c8aea3205273710fb71e077d139f6f7d",
"sha256:4d941d58769437e56656464c91461e61eee27ff2dac3ed53766e0042bc33169a" "sha256:f1b3106447c4e0920ffaf9a7d8fd63829c7105e88b89bbdc90fbf65112897131"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.4.0" "version": "==1.5.0"
}, },
"django-crispy-forms": { "django-crispy-forms": {
"hashes": [ "hashes": [
...@@ -100,10 +100,10 @@ ...@@ -100,10 +100,10 @@
}, },
"pytz": { "pytz": {
"hashes": [ "hashes": [
"sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca", "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
"sha256:8e0f8568c118d3077b46be7d654cc8167fa916092e28320cde048e54bfc9f1e6" "sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
], ],
"version": "==2018.7" "version": "==2018.9"
}, },
"redis": { "redis": {
"hashes": [ "hashes": [
......
#! /bin/bash #! /bin/bash
export GO_SECRET_KEY
until nc -z db 3306; do until nc -z db 3306; do
echo "waiting for database to start..." echo "waiting for database to start..."
sleep 1 sleep 1
done done
export GO_SECRET_KEY
export GO_CREATE_SUPERUSER
GO_SECRET_KEY=$(dd if=/dev/urandom count=100 | tr -dc "A-Za-z0-9" | fold -w 60 | head -n1 2>/dev/null) GO_SECRET_KEY=$(dd if=/dev/urandom count=100 | tr -dc "A-Za-z0-9" | fold -w 60 | head -n1 2>/dev/null)
yarn build
python go/manage.py makemigrations python go/manage.py makemigrations
python go/manage.py makemigrations go_back python go/manage.py makemigrations go_back
python go/manage.py makemigrations go_ahead python go/manage.py makemigrations go_ahead
python go/manage.py migrate python go/manage.py migrate
python go/manage.py runserver 0.0.0.0:8000 python go/manage.py runserver 0.0.0.0:8000
\ No newline at end of file
"""
go_ahead/urls.py
"""
from django.urls import path from django.urls import path
from . import views from . import views
......
...@@ -17,6 +17,7 @@ class RegisteredUserInline(admin.StackedInline): ...@@ -17,6 +17,7 @@ class RegisteredUserInline(admin.StackedInline):
Allow for RegisteredUsers to be displayed alongside their Django user Allow for RegisteredUsers to be displayed alongside their Django user
objects. objects.
""" """
model = RegisteredUser model = RegisteredUser
can_delete = False can_delete = False
...@@ -25,7 +26,8 @@ class RegUserAdmin(UserAdmin): ...@@ -25,7 +26,8 @@ class RegUserAdmin(UserAdmin):
""" """
Stick information about RegisteredUsers into its own Admin panel. Stick information about RegisteredUsers into its own Admin panel.
""" """
inlines = (RegisteredUserInline, )
inlines = (RegisteredUserInline,)
# Default ModelAdmin # Default ModelAdmin
......
"""
go/forms.py
Configure the layout and styling of the Go's forms.
"""
# Django Imports
from django.forms import (BooleanField, CharField, ChoiceField, DateTimeField,
ModelForm, RadioSelect, Textarea, TextInput,
URLField, URLInput)
from django.utils.safestring import mark_safe
from django.utils import timezone
# Third party imports
from crispy_forms.bootstrap import (Accordion, AccordionGroup, PrependedText,
StrictButton)
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Field, Fieldset, Layout
# App Imports
from .models import URL, RegisteredUser
from .validators import regex_short_validator, valid_date
class URLForm(ModelForm):
"""
The form that is used in URL creation.
Define custom fields and then render them onto the template.
"""
# destination -------------------------------------------------------------
destination = URLField(
required=True,
label='Long URL (Required)',
max_length=1000,
widget=URLInput(attrs={
'placeholder': 'https://yoursite.com/'
})
)
# short -------------------------------------------------------------------
short = CharField(
required=False,
label='Short URL (Optional)',
widget=TextInput(),
validators=[regex_short_validator],
max_length=20,
min_length=1,
)
# expires -----------------------------------------------------------------
DAY = '1 Day'
WEEK = '1 Week'
MONTH = '1 Month'
CUSTOM = 'Custom Date'
NEVER = 'Never'
# Define a tuple of string date standards to be used as our date choices
EXPIRATION_CHOICES = (
(DAY, DAY),
(WEEK, WEEK),
(MONTH, MONTH),
(NEVER, NEVER),
(CUSTOM, CUSTOM),
)
expires = ChoiceField(
required=True,
label='Expiration (Required)',
choices=EXPIRATION_CHOICES,
initial=NEVER,
widget=RadioSelect(),
)
expires_custom = DateTimeField(
required=False,
label='Custom Date',
input_formats=['%m-%d-%Y'],
validators=[valid_date],
initial=lambda: timezone.now() + timezone.timedelta(days=1)
)
def __init__(self, *args, **kwargs):
# Grab that host info
self.host = kwargs.pop('host', None)
super(URLForm, self).__init__(*args, **kwargs)
# Define the basics for crispy-forms
self.helper = FormHelper()
self.helper.form_method = 'POST'
# Some extra vars for form css purposes
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-1'
self.helper.field_class = 'col-md-6'
# The main "layout" defined
self.helper.layout = Layout(
Fieldset('',
#######################
Accordion(
# Step 1: Long URL
AccordionGroup('Step 1: Long URL',
Div(
HTML("""
<h4>Paste the URL you would like to shorten:</h4>
<br />"""),
'destination',
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html'),
# Step 2: Short URL
AccordionGroup('Step 2: Short URL',
Div(
HTML("""
<h4>Create a custom Go address:</h4>
<br />"""),
PrependedText(
'short', 'https://go.gmu.edu/', template='crispy/customPrepended.html'),
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html',),
# Step 3: Expiration
AccordionGroup('Step 3: URL Expiration',
Div(
HTML("""
<h4>Set when you would like your Go address to expire:</h4>
<br />"""),
'expires',
Field('expires_custom'),
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html'),
# FIN
template='crispy/accordian.html'),
#######################
HTML("""
<br />"""),
StrictButton('Shorten', css_class="btn btn-primary btn-md col-md-4", type='submit')))
class Meta:
"""
Metadata about this ModelForm
"""
# what model this form is for
model = URL
# what attributes are included
fields = ['destination']
class EditForm(URLForm):
"""
The form that is used in editing URLs.
A modification of the URL creation form... now for editing URLs. Inherit
custom form fields for DRY purposes.
"""
def __init__(self, *args, **kwargs):
"""
On initialization of the form, crispy forms renders this layout.
"""
# Grab that host info
self.host = kwargs.pop('host', None)
super(URLForm, self).__init__(*args, **kwargs)
# Define the basics for crispy-forms
self.helper = FormHelper()
self.helper.form_method = 'POST'
# Some xtra vars for form css purposes
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-1'
self.helper.field_class = 'col-md-6'
# The main "layout" defined
self.helper.layout = Layout(
Fieldset('',
#######################
Accordion(
# Step 1: Long URL
AccordionGroup('Step 1: Long URL',
Div(
HTML("""
<h4>Modify the URL you would like to shorten:</h4>
<br />"""),
'destination',
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html'),
# Step 2: Short URL
AccordionGroup('Step 2: Short URL',
Div(
HTML("""
<h4>Modify the Go address:</h4>
<br />"""),
PrependedText(
'short', 'https://go.gmu.edu/', template='crispy/customPrepended.html'),
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html',),
# Step 3: Expiration
AccordionGroup('Step 3: URL Expiration',
Div(
HTML("""
<h4>Modify the expiration date:</h4>
<br />"""),
'expires',
Field('expires_custom',
template="crispy/customDateField.html"),
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html'),
# FIN
template='crispy/accordian.html'),
#######################
HTML("""
<br />"""),
StrictButton('Submit Changes', css_class="btn btn-primary btn-md col-md-4", type='submit')))
class Meta(URLForm.Meta):
"""
Metadata about this ModelForm
"""
# what attributes are included
fields = URLForm.Meta.fields
class SignupForm(ModelForm):
"""
The form that is used when a user is signing up to be a RegisteredUser
"""
full_name = CharField(
required=True,
label='Full Name (Required)',
max_length=100,
widget=TextInput(),
help_text="We can fill in this field based on information provided by https://peoplefinder.gmu.edu.",
)
organization = CharField(
required=True,
label='Organization (Required)',
max_length=100,
widget=TextInput(),
help_text="Or whatever \"group\" you would associate with on campus.",
)
description = CharField(
required=False,
label='Description (Optional)',
max_length=200,
widget=Textarea(),
help_text="Describe what type of links you would intend to create with Go.",
)
# A user becomes registered when they agree to the TOS
registered = BooleanField(
required=True,
# ***Need to replace lower url with production URL***
# ie. go.gmu.edu/about#terms
label=mark_safe(
'Do you accept the <a href="about">Terms of Service</a>?'
),
help_text="Esssentially the GMU Responsible Use of Computing policies.",
)
def __init__(self, request, *args, **kwargs):
"""
On initialization of the form, crispy forms renders this layout.
"""
# Necessary to call request in forms.py, is otherwise restricted to
# views.py and models.py
self.request = request
super(SignupForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-4'
self.helper.field_class = 'col-md-6'
self.helper.layout = Layout(
Fieldset('',
Div(
# Place in form fields
Div(
'full_name',
'organization',
'description',
'registered',
css_class='well'),
# Extras at bottom
StrictButton(
'Submit', css_class='btn btn-primary btn-md col-md-4', type='submit'),
css_class='col-md-6')))
class Meta:
"""
Metadata about this ModelForm
"""
# what model this form is for
model = RegisteredUser
# what attributes are included
fields = ['full_name', 'organization', 'description', 'registered']
"""
go/commands/expirelinks.py
Remove expired links from the database.
"""
# Django Imports
from django.core.management.base import BaseCommand
from django.utils import timezone
# App Imports
from go_back.models import URL
class Command(BaseCommand):
"""
Define a new custom django-admin command to remove expired links from the
database.
"""
help = 'Removes expired links from the database'
def handle(self, *args, **options):
"""
Handle the main component of the django-admin command. Loop
through a list of all URL objects that have expired (expires field is
less than or equal [lte] to today's date)
"""
for expired_url in URL.objects.filter(expires__lte=timezone.now()):
expired_url.delete()
"""
go/commands/test_expirelinks.py
Test that the function to expire Go links actually works.
"""
# Python stdlib Imports
from datetime import timedelta
# Django Imports
from django.contrib.auth.models import User
from django.core.management import call_command
from django.test import TestCase
from django.utils import timezone
# App Imports
from go_back.models import URL, RegisteredUser
# class ExpireLinksTest(TestCase):
# def setUp(self):