Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
*.pyc
madras/local_settings.py
__pycache__/

db.sqlite3
db.sqlite3-journal

venv/
env/
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Madras

Madras is the backend for a cloud-based hackathon management system that aims to bring together the many different hackathon organizing systems into one centralized service to minimize the need to migrate data between hacker applications, registration, check-in, announcements, reimbursement, judging, and prizes. Created with the goal of making organizing hackathons easier for everyone.

## Setup

```bash
virtualenv --python=python3 venv
source venv/bin/activate
pip install -r requirements.txt
./manage.py migrate
./manage.py runserver
```
2 changes: 1 addition & 1 deletion apps/director/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def __str__(self):

class Hackathon(models.Model):
name = models.CharField(max_length=128)
organization = models.ForeignKey(Organization, related_name="hackathons")
organization = models.ForeignKey(Organization, related_name="hackathons", on_delete=models.CASCADE)

def __str__(self):
return self.name
12 changes: 6 additions & 6 deletions apps/reader/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@


class Reader(models.Model):
user = models.OneToOneField(User, related_name="reader")
organization = models.ForeignKey(Organization, related_name="readers")
user = models.OneToOneField(User, related_name="reader", on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, related_name="readers", on_delete=models.CASCADE)
hackathons = models.ManyToManyField(Hackathon, related_name="readers")


class Rating(models.Model):
application = models.OneToOneField(Application, related_name="rating")
application = models.OneToOneField(Application, related_name="rating", on_delete=models.CASCADE)


class RatingField(models.Model):
Expand All @@ -24,7 +24,7 @@ class RatingField(models.Model):
(TYPE_MULTIPLE_CHOICE, "Multiple choice"),
)

rating = models.ForeignKey(Rating, related_name="fields")
rating = models.ForeignKey(Rating, related_name="fields", on_delete=models.CASCADE)
type = models.CharField(max_length=16, choices=TYPE_CHOICES)
prompt = models.CharField(max_length=64)
min_number = models.IntegerField(default=-1)
Expand All @@ -33,6 +33,6 @@ class RatingField(models.Model):


class RatingResponse(models.Model):
reader = models.ForeignKey(Reader, related_name="ratings")
applicant = models.ForeignKey(Applicant, related_name="ratings")
reader = models.ForeignKey(Reader, related_name="ratings", on_delete=models.CASCADE)
applicant = models.ForeignKey(Applicant, related_name="ratings", on_delete=models.CASCADE)
data = models.TextField()
66 changes: 65 additions & 1 deletion apps/reader/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import requests
import geopy.distance
from github3 import login


#helper function that gets the number of contributions in the last year
def get_contributions(github_user_name):
url = "https://github.com/" + github_user_name
resp = requests.get(url)
Expand All @@ -11,7 +13,9 @@ def get_contributions(github_user_name):
index_of_contribution + 37: index_of_contribution + 45]
return [int(s) for s in substring_of_contribution.split() if s.isdigit()][0]


#gets the number of followers, number of repositories,
#number of contributions in past year and number of
#self starred repositories
def get_metrics_github(github_user_name):
gh = login("GITHUB_USER_NAME", password="GITHUB_PASSWORD")
user = gh.user(github_user_name)
Expand All @@ -32,3 +36,63 @@ def get_metrics_github(github_user_name):
"num_contributions": get_contributions(github_user_name),
"self_star_repos": len(star_repos),
}


#
#Travel reimburstment
#

def address_to_lat_long(address):
location = geolocator.geocode(address)
return {
"lat": location.latitude,
"long": location.longitude
}

KM_TO_MILES = 0.621371

#Source: http://www.tps.ucsb.edu/commuter-cost-calculator
AVERAGE_TRANSIT_COST_PER_MILE = .608

#Source: https://goo.gl/rDjXe3
#Fare = $30 + (Distance * $0.08)
AVERAGE_AIRLINE_FARE = 30
AVERAGE_AIRLINE_COST_PER_MILE = .08

#because numbers are from 2015
INFLATION_FACTOR = 1.03

#constants to define
#DISTANCE_TO_NEAREST_AIRPORT is the distance to the nearest airport from
#from the venue in miles
VENUE_LAT = 0
VENUE_LONG = 0
NEAREST_AIRPORT_LAT = 0
NEAREST_AIRPORT_LONG = 0
DISTANCE_TO_NEAREST_AIRPORT = 0

#estimates the cost of travel from lat/long coordinates of user
#all lat and long are doubles

def calculate_travel_est(lat1, long1):
origin = (lat1, long1)
nearest_airport = (NEAREST_AIRPORT_LAT, NEAREST_AIRPORT_LONG)
venue = (VENUE_LAT, VENUE_LONG)
#multiply by 2 to travel both ways
origin_to_venue = (geopy.distance.vincenty(origin, venue).km)* \
KM_TO_MILES * 2
origin_to_airport = (geopy.distance.vincenty(origin, nearest_airport).km)* \
KM_TO_MILES * 2
just_transit_costs = .608 * origin_to_venue * INFLATION_FACTOR
airline_costs = origin_to_airport * AVERAGE_AIRLINE_COST_PER_MILE + \
AVERAGE_AIRLINE_FARE
airport_to_uni_costs = DISTANCE_TO_NEAREST_AIRPORT * \
AVERAGE_TRANSIT_COST_PER_MILE * 2
total_airline_costs = (airline_costs + airport_to_uni_costs) * \
INFLATION_FACTOR
#now compare prices
if (just_transit_costs >= total_airline_costs):
return(total_airline_costs)
else:
return(just_transit_costs)

9 changes: 7 additions & 2 deletions apps/reader/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from apps.reader import serializers
from apps.reader.models import Applicant, RatingResponse
from apps.reader.utils import get_metrics_github

from apps.reader.utils import calculate_travel_est
from apps.reader.utils import address_to_lat_long

class Rating(APIView):
permission_classes = (IsAuthenticated,)
Expand Down Expand Up @@ -42,6 +43,7 @@ def get(self, request):
rand_pk = random.randint(0, Applicant.objects.all().count() - 1)
rand_app = Applicant.objects.get(pk=rand_pk)
github_array = get_metrics_github(rand_app.github_user_name)
user_addresss_coords = address_to_lat_long(rand_app.address)
return Response(
{
"applicant_id": rand_app.pk,
Expand All @@ -51,7 +53,10 @@ def get(self, request):
"num_followers": github_array["NumFollowers"],
"num_repos": github_array["NumRepos"],
"num_contributions": github_array["NumContributions"],
"self_star_repos": github_array["selfStarRepos"]
"self_star_repos": github_array["selfStarRepos"],
"travel_reimbursement" : \
calculate_travel_est(user_addresss_coords["lat"], \
user_addresss_coords["long"])
},
status=status.HTTP_200_OK,
)
Expand Down
15 changes: 8 additions & 7 deletions apps/registration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Application(models.Model):

name = models.CharField(max_length=128)
status = models.CharField(max_length=16, choices=STATUS_CHOICES)
hackathon = models.ForeignKey(Hackathon, related_name="applications")
hackathon = models.ForeignKey(Hackathon, related_name="applications", on_delete=models.CASCADE)

def __str__(self):
return "{} ({})".format(self.name, self.hackathon)
Expand All @@ -36,7 +36,7 @@ class ApplicationField(models.Model):
(TYPE_LONG_ANSWER, "Long Answer"),
)

application = models.ForeignKey(Application, related_name="fields")
application = models.ForeignKey(Application, related_name="fields", on_delete=models.CASCADE)
ordering = models.IntegerField()
type = models.CharField(max_length=32, choices=TYPE_CHOICES)
prompt = models.CharField(max_length=256)
Expand All @@ -48,7 +48,7 @@ def __str__(self):


class ApplicantTeam(models.Model):
hackathon = models.ForeignKey(Hackathon)
hackathon = models.ForeignKey(Hackathon, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
entry_code = models.CharField(max_length=64)

Expand All @@ -57,12 +57,13 @@ def __str__(self):


class Applicant(models.Model):
user = models.OneToOneField(User, related_name="applicant", blank=True, null=True)
hackathon = models.ForeignKey(Hackathon, related_name="applicants")
application = models.ForeignKey(Application, related_name="applicants")
team = models.ForeignKey(ApplicantTeam, related_name="applicants", blank=True, null=True)
user = models.OneToOneField(User, related_name="applicant", blank=True, null=True, on_delete=models.CASCADE)
hackathon = models.ForeignKey(Hackathon, related_name="applicants", on_delete=models.CASCADE)
application = models.ForeignKey(Application, related_name="applicants", on_delete=models.CASCADE)
team = models.ForeignKey(ApplicantTeam, related_name="applicants", blank=True, null=True, on_delete=models.CASCADE)
data = models.TextField(blank=True, null=True)
github_user_name = models.CharField(max_length=39, unique=True, blank=True, null=True)
address = models.CharField(max_length=128)

def __str__(self):
return "{}'s Application".format(self.user)
18 changes: 0 additions & 18 deletions madras/local_settings_sample.py

This file was deleted.

24 changes: 11 additions & 13 deletions madras/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY")
SECRET_KEY = os.environ.get("SECRET_KEY", "=u!#c-2hid%(4lq3w--$64!%qmbmmo-ae=l2_&*jpf47l84iv4")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = os.environ.get("DEBUG", "true").lower() == "true"

ALLOWED_HOSTS = []
# Allow all host headers
ALLOWED_HOSTS = ['*']


# Application definition
Expand Down Expand Up @@ -107,15 +108,17 @@
# Heroku settings below
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES = {}
DATABASES['default'] = dj_database_url.config()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
DATABASES['default'].update(dj_database_url.config())

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers
ALLOWED_HOSTS = ['*']

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/

Expand All @@ -135,8 +138,3 @@
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

# SECURE_SSL_REDIRECT = True

try:
from local_settings import *
except ImportError:
pass
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ django-toolbelt==0.0.1
djangorestframework==3.6.4
enum34==1.1.6
github3.py==1.0.0a4
geopy==1.11.0
gunicorn==19.7.1
idna==2.6
ipaddress==1.0.18
Expand Down