Verified Commit 9ba9ca02 authored by David Haynes's avatar David Haynes 🙆

Merge branch '2.3-dev' into secret-refactor

parents 4867e7bf aaaaa9ef
go/settings/settings.py
go/settings/secret.py
docker-compose.yml
**/*.pyc
Dockerfile
Vagrantfile
.dockerignore
\ No newline at end of file
......@@ -17,6 +17,7 @@ before_script:
- cd go/
- export GO_SECRET_KEY=$(dd if=/dev/urandom count=100 | tr -dc "A-Za-z0-9" | fold -w 60 | head -n1 2>/dev/null)
- export GO_DB_NAME="go"
- export GO_ENV="production"
- export GO_DB_USER="root"
- export GO_DB_PASSWORD="root"
- export GO_DB_HOST="mysql"
......@@ -35,12 +36,6 @@ before_script:
- python manage.py migrate
- echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('root', 'root@srct.gmu.edu', 'root') " | python manage.py shell
Go-py2.7:
image: library/python:2.7
stage: test
script:
- python manage.py test
Go-py3.4:
image: library/python:3.4
stage: test
......@@ -53,17 +48,16 @@ Go-py3.5:
script:
- python manage.py test
#Go-py3.6:
# image: library/python:3.6
# stage: test
# script:
# - if pip list --outdated | grep "Latest" | wc -l > 0; then pip list --outdated && exit 1; else exit 0; fi
# - coverage run --source=go --omit=*migrations/*,*admin.py,*manage.py,*wsgi.py,*settings.py,*secret.py,*__init__.py,*.pyc,*templates/*,*static/* manage.py test
# - coverage html -i && grep pc_cov htmlcov/index.html | egrep -o "[0-9]+\%" | awk '{ print "covered " $1;}'
Go-py3.6:
image: library/python:3.6
stage: test
script:
# - if pip list --outdated | grep "Latest" | wc -l > 0; then pip list --outdated && exit 1; else exit 0; fi
- coverage run --source=go --omit=*migrations/*,*admin.py,*manage.py,*wsgi.py,*settings.py,*secret.py,*__init__.py,*.pyc,*templates/*,*static/* manage.py test
- coverage html -i && grep pc_cov htmlcov/index.html | egrep -o "[0-9]+\%" | awk '{ print "covered " $1;}'
Go-flake8:
image: library/python:3.5
stage: lint
script:
- pip install flake8
- flake8 go/ --statistics --exit-zero
\ No newline at end of file
- flake8 go/ --statistics --exit-zero
......@@ -5,7 +5,7 @@ about the current issue. Maybe a picture? Some details that could best help some
especially someone new, understand the goal of the issue and how they should best
approach the problem.
# Helpful Links
## Helpful Links
Here you should include a bullet point list of links to documentation, stack overflow,
whatever, that could help guide someone on what it is they are trying to do.
......
......@@ -17,15 +17,16 @@ add, modify, or remove features/bugs from Go. Our list of tasks can be found on
the issues page.
If you decide to take on an issue for Go you will need to work in a branch off
of the current development branch (ie. `2.2-dev` with 2.2 being the version in
development).
of the current development branch (ie. `2.3-dev` with 2.3 being the version in
development).
This can be done with the following chain of `git` commands within `go/`:
git pull
git checkout 2.2-dev
git checkout -B ##-shortdescription
```sh
git pull
git checkout 2.3-dev
git checkout -B ##-shortdescription
```
**Note:**
......@@ -35,9 +36,11 @@ does.
**Example:**
git pull
git checkout 2.2-dev
git checkout -B 102-readmeUpdates
```sh
git pull
git checkout 2.3-dev
git checkout -B 102-readmeUpdates
```
If you are working on something that does not have an issue please open a new
issue before creating your branch.
......
# Build on top of the python image and install any external packages
FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN apt-get update
RUN apt-get install netcat -y
RUN mkdir /go
WORKDIR /go
ADD /requirements/ /go/
RUN pip install -r base.txt
# Set enviornment variables
ENV PYTHONUNBUFFERED 1
# Copy over all project files into /go/
RUN mkdir /go/
WORKDIR /go/
ADD . /go/
# Install pip dependecies
RUN pip install -r /go/requirements/dev.txt
Copyright 2017 George Mason Student-Run Computing and Technology
Copyright 2018 George Mason Student-Run Computing and Technology
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......
This diff is collapsed.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Import securerandom for secret key generation
require 'securerandom'
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure(2) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/trusty64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network "forwarded_port", guest: 8000, host: 8000
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
# such as FTP and Heroku are also available. See the documentation at
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
# config.push.define "atlas" do |push|
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
# end
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# sudo apt-get update
# sudo apt-get install -y apache2
# SHELL
config.vm.provision "ansible", run: "always" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
ansible.sudo = true
ansible.extra_vars = {
nginx: {
port: 8000,
https: false
},
mysql: {
root_user: "root",
root_pass: "",
user: "go",
pass: "go",
db: "go"
},
django: {
secret_key: SecureRandom.base64,
host: "*",
debug: "True",
email_domain: "@masonlive.gmu.edu",
requirements_path: "/vagrant/requirements.txt",
venv_path: "/vagrant/venv",
cas_url: "https://cas.srct.gmu.edu/",
app_path: "/vagrant/go",
sourceme_dest: "/vagrant/go/",
superuser: "dhaynes3"
}
}
end
=begin
# Picks up from any failed runs
# Run this with: "vagrant provision --provision-with resume"
config.vm.provision "resume", type: "ansible" do |resume|
resume.playbook = "provisioning/playbook.yml"
resume.limit = "@provisioning/playbook.retry"
resume.sudo = true
resume.extra_vars = {
nginx: {
port: 8000,
https: false
},
mysql: {
root_user: "root",
root_pass: "",
user: "go",
pass: "go",
db: "go"
},
django: {
secret_key: SecureRandom.base64,
host: "*",
debug: "True",
email_domain: "@masonlive.gmu.edu",
requirements_path: "/vagrant/requirements.txt",
venv_path: "/vagrant/venv",
cas_url: "https://cas.srct.gmu.edu/",
app_path: "/vagrant/go",
settings_path: "/vagrant/go/settings",
superuser: "dhaynes3"
}
}
end
=end
end
version: '2'
version: "3"
services:
db:
image: mysql
deploy:
replicas: 1
restart_policy:
condition: on-failure
networks:
- go
ports:
- "3306:3306"
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: go
MYSQL_USER: go
MYSQL_PASSWORD: go
web:
build: .
restart: always
image: go_web
deploy:
replicas: 1
restart_policy:
condition: on-failure
networks:
- go
ports:
- '8000:8000'
command: /bin/bash ./startup.sh -python go/manage.py runserver 0.0.0.0:8000
command: ./startup.sh
volumes:
- .:/go
depends_on:
- db
environment:
- GO_ENV=dev
- GO_ALLOWED_HOSTS=*
- GO_EMAIL_DOMAIN=@masonlive.gmu.edu
- GO_CAS_URL=https://cas.srct.gmu.edu/
- GO_DB_NAME=go
- GO_DB_USER=go
- GO_DB_PASSWORD=go
......@@ -25,12 +46,7 @@ services:
- GO_EMAIL_HOST_PASSWORD=
- GO_EMAIL_FROM=
- GO_EMAIL_TO=
- superuser=dhaynes3
- SUPERUSER=dhaynes3
db:
image: mysql
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: go
MYSQL_USER: go
MYSQL_PASSWORD: go
networks:
go:
#!/bin/bash
# Cron job to automatically expire outdated links, put this in cron.hourly
ACTIVATE_PATH=/path/to/virtualenv/activate
MANAGE_PATH=/path/to/go/manage.py
source ${ACTIVATE_PATH}
python ${MANAGE_PATH} expirelinks
"""
go/admin.py
"""
# Future Imports
from __future__ import (absolute_import, division, print_function,
unicode_literals)
Configure the Django admin pages and apply optional formatting.
"""
# Django Imports
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
......@@ -18,7 +15,6 @@ class URLAdmin(admin.ModelAdmin):
"""
Define what attributes display in the URL Admin
"""
list_display = ("target", "short", "owner", "clicks", "date_created", "expires")
# Register URLAdmin
......@@ -28,7 +24,6 @@ class RegisteredUserInline(admin.StackedInline):
"""
Define an inline admin descriptor for User model
"""
model = RegisteredUser
can_delete = False
......@@ -36,10 +31,7 @@ class UserAdmin(UserAdmin):
"""
Define a new User admin
"""
# see above class that we defined
inlines = (RegisteredUserInline, )
# and modify User to use our new UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
"""
go/cas_callbacks.py
"""
# Future Imports
from __future__ import (absolute_import, division, print_function,
unicode_literals)
Parse the CAS/PF responses and create users in the database.
"""
# Django Imports
from django.conf import settings
from django.contrib.auth.models import User
......@@ -17,7 +14,6 @@ def pfparse(pf_name_result):
"""
Parse what peoplefinder sends back to us and make a list out of it
"""
# name comes in format of Anderson, Nicholas J
name_list = pf_name_result.split(',')
# there's random whitespace with the first name
......@@ -37,7 +33,6 @@ def pfinfo(uname):
"""
Get information from peoplefinder
"""
base_url = settings.PF_URL
url = base_url + "basic/all/" + str(uname)
try:
......@@ -80,9 +75,8 @@ def pfinfo(uname):
def create_user(tree):
"""
Create a django user based off of the peoplefinder info we parsed earlier
Create a django user based off of the peoplefinder info we parsed earlier.
"""
print("Parsing CAS information.")
try:
username = tree[0][0].text
......@@ -112,10 +106,8 @@ def create_user(tree):
print("Added user's name, %s %s." % (info_name[0], info_name[1]))
print("User object creation process completed.")
else:
print("User object already exists.")
print("CAS callback successful.")
except Exception as ex:
print("Unhandled user creation error:", ex)
"""
go/forms.py
"""
# Future Imports
from __future__ import (absolute_import, division, print_function,
unicode_literals)
Configure the layout and styling of the Go's forms.
"""
# Python stdlib Imports
from datetime import datetime, timedelta
......@@ -30,29 +28,10 @@ from crispy_forms.layout import HTML, Div, Field, Fieldset, Layout
class URLForm(ModelForm):
"""
The form that is used in URL creation.
"""
# target -------------------------------------------------------------------
def clean_target(self):
"""
Prevent redirect loop links
"""
# get the entered target link
target = self.cleaned_data.get('target')
# Commented out as this check cannont properly be tested since we cannot
# dynamically generate request.META.get('HTTP_HOST')
# # if the host (go.gmu.edu) is in the entered target link or where it
# # redirects
# if self.host in final_url or self.host in target:
# raise ValidationError("You can't make a Go link to Go silly!")
# else:
# return target
return target
# Custom target URL field
Define custom fields and then render them onto the template.
"""
# target ------------------------------------------------------------------
target = URLField(
required=True,
label='Long URL (Required)',
......@@ -62,23 +41,21 @@ class URLForm(ModelForm):
})
)
# short --------------------------------------------------------------------
# short -------------------------------------------------------------------
def unique_short(value):
"""
Check to make sure the short url has not been used
"""
try:
# if we're able to get a URL with the same short url
URL.objects.get(short__iexact=value)
except URL.DoesNotExist as ex:
print(ex)
return
# then raise a ValidationError
raise ValidationError('Short url already exists.')
# Custom short-url field with validators.
short = SlugField(
required=False,
label='Short URL (Optional)',
......@@ -88,9 +65,7 @@ class URLForm(ModelForm):
min_length=3,
)
# expires ------------------------------------------------------------------
# Define some string date standards
# expires -----------------------------------------------------------------
DAY = '1 Day'
WEEK = '1 Week'
MONTH = '1 Month'
......@@ -106,7 +81,6 @@ class URLForm(ModelForm):
(CUSTOM, CUSTOM),
)
# Add preset expiration choices.
expires = ChoiceField(
required=True,
label='Expiration (Required)',
......@@ -119,7 +93,6 @@ class URLForm(ModelForm):
"""
Check if the selected date is a valid date
"""
# a valid date is one that is greater than today
if value > timezone.now():
return
......@@ -127,30 +100,18 @@ class URLForm(ModelForm):
else:
raise ValidationError('Date must be after today.')
# Add a custom expiration choice.
expires_custom = DateTimeField(
required=False,
label='Custom Date',
input_formats=['%m-%d-%Y'],
validators=[valid_date],
initial=lambda: datetime.now() + timedelta(days=1),
widget=DateTimePicker(
options={
"format": "MM-DD-YYYY",
"pickTime": False,
},
icon_attrs={
"class": "fa fa-calendar",
},
)
initial=lambda: datetime.now() + timedelta(days=1)
)
def __init__(self, *args, **kwargs):
"""
On initialization of the form, crispy forms renders this layout
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)
......@@ -158,7 +119,7 @@ class URLForm(ModelForm):
self.helper = FormHelper()
self.helper.form_method = 'POST'
# Some xtra vars for form css purposes
# 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'
......@@ -198,7 +159,7 @@ class URLForm(ModelForm):
<h4>Set when you would like your Go address to expire:</h4>
<br />"""),
'expires',
Field('expires_custom', template="crispy/customDateField.html"),
Field('expires_custom'),
style="background: rgb(#F6F6F6);"),
active=True,
template='crispy/accordian-group.html'),
......@@ -214,19 +175,22 @@ class URLForm(ModelForm):
"""
Metadata about this ModelForm
"""
# what model this form is for
model = URL
# what attributes are included
fields = ['target']
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
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)
......@@ -285,8 +249,11 @@ class EditForm(URLForm):
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
......@@ -294,8 +261,6 @@ class SignupForm(ModelForm):
"""
The form that is used when a user is signing up to be a RegisteredUser
"""
# The full name of the RegisteredUser
full_name = CharField(
required=True,
label='Full Name (Required)',
......@@ -304,7 +269,6 @@ class SignupForm(ModelForm):
help_text="We can fill in this field based on information provided by https://peoplefinder.gmu.edu.",
)
# The RegisteredUser's chosen organization
organization = CharField(
required=True,
label='Organization (Required)',
......@@ -313,7 +277,6 @@ class SignupForm(ModelForm):
help_text="Or whatever \"group\" you would associate with on campus.",
)
# The RegisteredUser's reason for signing up to us Go
description = CharField(
required=False,
label='Description (Optional)',
......@@ -328,16 +291,15 @@ class SignupForm(ModelForm):
# ***Need to replace lower url with production URL***
# ie. go.gmu.edu/about#terms
label=mark_safe(
'Do you accept the <a href="http://127.0.0.1:8000/about#terms">Terms of Service</a>?'
'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
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
......@@ -366,7 +328,6 @@ class SignupForm(ModelForm):
"""
Metadata about this ModelForm
"""
# what model this form is for