Commit cd2972ad authored by David Haynes's avatar David Haynes
Browse files

Merge branch 'master' into issue69

- so many conflicts squashed
parents 4573d745 6e326338
Pipeline #508 passed with stage
in 7 minutes and 31 seconds
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
##Redirect queries to the /rd script
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /rd [L]
</IfModule>
......@@ -2,23 +2,33 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
# App Imports
from go.models import URL, RegisteredUser
# Define what attributes display in the URL Admin
"""
Define what attributes display in the URL Admin
"""
class URLAdmin(admin.ModelAdmin):
list_display = ("target", "short", "owner", "clicks", "date_created", "expires")
# Define an inline admin descriptor for User model
# Register URLAdmin
admin.site.register(URL, URLAdmin)
"""
Define an inline admin descriptor for User model
"""
class RegisteredUserInline(admin.StackedInline):
model = RegisteredUser
can_delete = False
model = RegisteredUser
can_delete = False
# Define a new User admin
"""
Define a new User admin
"""
class UserAdmin(UserAdmin):
inlines = (RegisteredUserInline, )
# see above class that we defined
inlines = (RegisteredUserInline, )
# Register URLAdmin and modify User to use new UserAdmin
admin.site.register(URL, URLAdmin)
# and modify User to use our new UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
from __future__ import absolute_import, print_function
# core django imports
# python 3 imports ^^^
# Django Imports
from django.contrib.auth.models import User
from django.conf import settings
from django.contrib import messages
# third party imports
import requests
"""
parse what peoplefinder sends back to us and make a list out of it
"""
def pfparse(pf_name_result):
# name comes in format of Anderson, Nicholas J
name_list = pf_name_result.split(',')
......@@ -19,10 +24,13 @@ def pfparse(pf_name_result):
first_name = ' '.join(mi_q[:-1])
else:
first_name = first_name_section
# our list containing the name of the person in a usable list
new_name_list = [first_name, name_list[0]]
return new_name_list
"""
get information from peoplefinder
"""
def pfinfo(uname):
base_url = settings.PF_URL
url = base_url + "basic/all/" + str(uname)
......@@ -64,7 +72,9 @@ def pfinfo(uname):
print("Returning empty user info tuple.")
return [u'', u'']
"""
create a django user based off of the peoplefinder info we parsed earlier
"""
def create_user(tree):
print("Parsing CAS information.")
......
......@@ -14,11 +14,16 @@ from crispy_forms.bootstrap import StrictButton, PrependedText, Accordion, Accor
from bootstrap3_datetime.widgets import DateTimePicker
from datetime import date, datetime, timedelta
"""
The form that is used in URL creation.
"""
class URLForm(forms.ModelForm):
# Prevent redirect loop links
def clean_target(self):
# get the entered target link
target = self.cleaned_data.get('target')
# if the host (go.gmu.edu) is in the entered target link
if self.host in target:
raise ValidationError("You can't make a Go link to Go silly!")
else:
......@@ -37,27 +42,31 @@ class URLForm(forms.ModelForm):
# Check to make sure the short url has not been used
def unique_short(value):
try:
# if we're able to get a URL with the same short url
URL.objects.get(short__iexact=value)
except URL.DoesNotExist:
return
# then raise a ValidationError
raise ValidationError('Short url already exists.')
# Custom short-url field with validators.
short = forms.SlugField(
required=False,
label='Short URL (Optional)',
widget=forms.TextInput(),
validators=[unique_short],
max_length=20,
min_length=3,
required = False,
label = 'Short URL (Optional)',
widget = forms.TextInput(),
validators = [unique_short],
max_length = 20,
min_length = 3,
)
# define some string date standards
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),
......@@ -68,16 +77,19 @@ class URLForm(forms.ModelForm):
# Add preset expiration choices.
expires = forms.ChoiceField(
required=True,
label='Expiration (Required)',
choices=EXPIRATION_CHOICES,
initial=NEVER,
widget=forms.RadioSelect(),
required = True,
label = 'Expiration (Required)',
choices = EXPIRATION_CHOICES,
initial = NEVER,
widget = forms.RadioSelect(),
)
# Check if the selected date is a valid date
def valid_date(value):
# a valid date is one that is greater than today
if value > timezone.now():
return
# raise a ValidationError if the date is invalid
else:
raise ValidationError('Date must be after today.')
......@@ -85,20 +97,22 @@ class URLForm(forms.ModelForm):
# Add a custom expiration choice.
expires_custom = forms.DateTimeField(
required = False,
label='Custom Date',
input_formats=['%m-%d-%Y'],
validators=[valid_date],
initial=lambda: datetime.now() + timedelta(days=1),
widget=DateTimePicker(
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",
})
},
)
)
# on initialization of the form, crispy forms renders this layout
def __init__(self, *args, **kwargs):
# Grab that host info
self.host = kwargs.pop('host', None)
......@@ -159,35 +173,42 @@ class URLForm(forms.ModelForm):
<br />"""),
StrictButton('Shorten', css_class="btn btn-primary btn-md col-md-4", type='submit')))
# metadata about this ModelForm
class Meta:
# what model this form is for
model = URL
fields = ('target',)
exclude = ('owner', 'short', 'date_created', 'clicks', 'expires')
# what attributes are included
fields = ['target',]
"""
The form that is used when a user is signing up to be a RegisteredUser
"""
class SignupForm(forms.ModelForm):
# The full name of the RegisteredUser
full_name = forms.CharField(
required=True,
label='Full Name (Required)',
max_length=100,
widget=forms.TextInput(attrs={
}),
required = True,
label = 'Full Name (Required)',
max_length = 100,
widget = forms.TextInput(),
)
# The RegisteredUser's chosen organization
organization = forms.CharField(
required=True,
label='Organization (Required)',
max_length=100,
widget=forms.TextInput(attrs={
})
required = True,
label = 'Organization (Required)',
max_length = 100,
widget = forms.TextInput(),
)
# The RegisteredUser's reason for signing up to us Go
description = forms.CharField(
required=False,
label='Description (Optional)',
max_length=200,
widget=forms.Textarea(attrs={
}),
required = False,
label = 'Description (Optional)',
max_length = 200,
widget = forms.Textarea(),
)
# A user becomes registered when they agree to the TOS
registered = forms.BooleanField(
required=True,
......@@ -195,6 +216,7 @@ class SignupForm(forms.ModelForm):
label = mark_safe('Do you accept the <a href="http://127.0.0.1:8000/about#terms">Terms of Service</a>?'),
)
# on initialization of the form, crispy forms renders this layout
def __init__(self, request, *args, **kwargs):
# Necessary to call request in forms.py, is otherwise restricted to views.py and models.py
self.request = request
......@@ -218,7 +240,10 @@ class SignupForm(forms.ModelForm):
# Extras at bottom
StrictButton('Submit',css_class='btn btn-primary btn-md col-md-4', type='submit'),
css_class='col-md-6')))
# metadata about this ModelForm
class Meta:
# what model this form is for
model = RegisteredUser
fields = ('full_name', 'organization', 'description', 'registered',)
exclude = ('user',)
# what attributes are included
fields = ['full_name', 'organization', 'description', 'registered',]
# Django Imports
from django.core.management.base import BaseCommand
from django.utils import timezone
from go.models import URL
# App Imports
from go.models import URL
# Define a new custom django-admin command
class Command(BaseCommand):
# Define help text for this command
help = 'Removes expired links from the database'
# The handle function handles the main component of the django-admin command
def handle(self, *args, **options):
# Loop through a list of all URL objects that have expired
# (expires field is less than or equal to today's date)
for toexpire in URL.objects.filter(expires__lte=timezone.now()):
# Delete the current URL
toexpire.delete()
......@@ -8,16 +8,17 @@ from django.dispatch import receiver
# Other Imports
import string
# http://hashids.org/python/
from hashids import Hashids
# generate the salt and initialize Hashids
hashids = Hashids(salt="srct.gmu.edu", alphabet=(string.ascii_lowercase + string.digits))
"""
This is simply a wrapper model for the user object which, if an object
exists, indicates that that user is registered.
"""
class RegisteredUser(models.Model):
"""
This is simply a wrapper model which, if an object exists, indicates
that that user is registered.
"""
# Is this User Blocked?
blocked = models.BooleanField(default=False)
......@@ -59,31 +60,44 @@ def handle_regUser_creation(sender, instance, created, **kwargs):
RegisteredUser.objects.create(user=instance)
class URL(models.Model):
"""
"""
This model represents a stored URL redirection rule. Each URL has an
owner, target url, short identifier, click counter, and expiration
date.
"""
"""
class URL(models.Model):
# Who is the owner of this Go link
owner = models.ForeignKey(RegisteredUser)
# When was this link created?
date_created = models.DateTimeField(default=timezone.now)
# What is the target URL for this Go link
target = models.URLField(max_length=1000)
short = models.SlugField(primary_key=True, max_length=20)
clicks = models.IntegerField(default=0)
# What is the actual go link (short url) for this URL
short = models.SlugField(max_length=20, primary_key=True)
# how many people have visited this Go link
clicks = models.IntegerField(default=0)
# how many people have visited this Go link through the qr code
qrclicks = models.IntegerField(default=0)
# how many people have visited the go link through social media
socialclicks = models.IntegerField(default=0)
# does this Go link expire on a certain date
expires = models.DateTimeField(blank=True, null=True)
# print(URL)
def __unicode__(self):
return '<%s : %s>' % (self.owner.user, self.target)
# metadata for URL's
class Meta:
# they should be ordered by their short links
ordering = ['short']
# legacy method to ensure that generated short URL's are valid
# should be updated to be simpler
@staticmethod
def generate_valid_short():
if cache.get("hashids_counter") is None:
......
<!-- include the base html template -->
{% extends 'layouts/base.html' %}
<!-- define the page title block -->
{% block title %}
404 Error &bull; Page Not Found
{% endblock %}
<!-- define the content block for the page -->
{% block content %}
<!-- div that contains the 404 page content -->
<div class="row">
<div class="col-md-10 col-md-offset-1 text-center">
<h1>404 Error - Page Not Found</h1>
<h3>The link you provided is invalid or may have been deleted.</h3>
<h3>If you are registered to use Go, you can verify your links <a href="{% url 'my_links' %}">here</a>.</h3>
<img id="squirrels" src="/static/img/squirrels.png">
<a href="/"><img src="/static/img/acorn.png" style="width:10vw;"></a>
<h3>
If you are registered to use Go, you can verify your links
<a href="{% url 'my_links' %}">here</a>.
</h3>
<img id="squirrels" src="{% static "img/acorn.png" %}">
<a href="/"><img src="{% static "img/acorn.png" %}" style="width:10vw;"></a>
</div>
</div>
{% endblock %}
<!-- include the base html template -->
{% extends 'layouts/base.html' %}
<!-- define the page title block -->
{% block title %}
500 Error &bull; Internal Server Error
{% endblock %}
<!-- define the content block for the page -->
{% block content %}
<!-- div that contains the 500 page content -->
<div class="row">
<div class="col-md-10 col-md-offset-1 text-center">
<h1>500 Error - Internal Server Error</h1>
<img id="squirrels" src="/static/img/squirrels.png">
<a href="/"><img src="/static/img/acorn.png" style="width:10vw;"></a>
<img id="squirrels" src="{% static "img/acorn.png" %}">
<a href="/"><img src="{% static "img/acorn.png" %}" style="width:10vw;"></a>
</div>
</div>
{% endblock %}
<!-- include the base html template -->
{% extends 'layouts/base.html' %}
<!-- define the page title block -->
{% block title %}
SRCT Go &bull; Administration Panel
{% endblock %}
<!-- define the content block for the page -->
{% block content %}
<!-- define the page header div -->
<div class="page-header" id="banner">
<div class="row">
<div class="col-md-12">
<h1><strong>
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
......@@ -19,170 +20,168 @@ SRCT Go &bull; Administration Panel
</span>
<i class="fa">Moderation Panel</i>
</strong></h1>
</div>
</div>
</div>
<!-- TABLE 1 -->
<!-- define the div where we can select users from a table to judge them -->
<div class="row">
<div class="col-md-12">
<h3>Users awaiting moderation</h3>
<form method="post" action="useradmin">{% csrf_token %}
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Selected</th>
<th>Username</th>
<th>Full Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for unapproved in need_approval %}
<tr>
<td><input type="checkbox" name="username" value={{ unapproved.user }}></td>
<td>{{ unapproved.user }}</td>
<td>{{ unapproved.full_name }}</td>
<td>{{ unapproved.description|default:"No description provided" }}</td>
</tr>
{% empty %}
<tr>
<td>none</td>
<td>none</td>
<td>none</td>
<td>none</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<input type="submit" name="_approve" value="Approve" class="btn btn-primary btn-sm">
<input type="submit" name="_deny" value="Deny" class="btn btn-danger btn-sm">
<input type="submit" name="_block" value="Block" class="btn btn-default btn-sm btn-blockUsr" style="background-color: black; color: white;">
<div class="col-md-12">
<h3>Users awaiting moderation</h3>
<form method="post" action="useradmin">
<!-- csrf protection -->
{% csrf_token %}
<!-- define out table of users that need approval -->
<table class="table table-striped table-hover">
<!-- define the header row -->
<thead>
<tr>
<th>Selected</th>
<th>Username</th>
<th>Full Name</th>
<th>Description</th>
</tr>
</thead>
<!-- define the body rows -->
<tbody>
<!-- loop through all users in the need_approval list -->
{% for unapproved in need_approval %}
<!-- ..and make a new row for each user -->
<tr>
<td><input type="checkbox" name="username" value={{ unapproved.user }}></td>
<td>{{ unapproved.user }}</td>
<td>{{ unapproved.full_name }}</td>
<td>{{ unapproved.description|default:"No description provided" }}</td>
</tr>
<!-- unless it's empty in which case we show nothing -->
{% empty %}
<tr>
<td>none</td>
<td>none</td>
<td>none</td>
<td>none</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- a div containing our form submission buttons -->
<div class="form-group">
<input type="submit" name="_approve" value="Approve" class="btn btn-primary btn-sm">
<input type="submit" name="_deny" value="Deny" class="btn btn-danger btn-sm">
<input type="submit" name="_block" value="Block" class="btn btn-default btn-sm btn-blockUsr" style="background-color: black; color: white;">
</div>
</form>
</div>
</form>
</div>
</div>
<!-- TABLE 2 -->
<!-- define the table that displays blocked users and allows us to unblock
them -->
<div class="row">
<div class="col-md-12">
<h3>Blocked Users</h3>
<form method="post" action="useradmin">{% csrf_token %}
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Selected</th>
<th>Username</th>
<th>Full Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for blockedUsers in blocked_users %}
<tr>
<td><input type="checkbox" name="username" value={{ blockedUsers.user }}></td>
<td>{{ blockedUsers.user }}</td>
<td>{{ blockedUsers.full_name }}</td>
<td>{{ blockedUsers.description|default:"No description provided" }}</td>
</tr>
{% empty %}
<tr>
<td>none</td>
<td>none</td>
<td>none</td>
<td>none</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<!-- <input type="submit" name="_approve" value="Approve" class="btn btn-primary btn-sm"> -->
<!-- <input type="submit" name="_deny" value="Deny" class="btn btn-danger btn-sm"> -->
<input type="submit" name="_unblock" value="Un-Block" class="btn btn-default btn-sm btn-Unblock">
<div class="col-md-12">
<h3>Blocked Users</h3>
<form method="post" action=