Merge branch 'dashboard' into testing
diff --git a/exp_portal/email.py b/exp_portal/email.py
index e17ec33..820d94c 100644
--- a/exp_portal/email.py
+++ b/exp_portal/email.py
@@ -2,8 +2,10 @@
 from op_tasks.models import UserProfile
 from django.core import mail
 from django.conf import settings
+from django.contrib.auth.decorators import login_required
 
 
+@login_required(login_url='/tasking/login')
 def send_email(request):
     if request.method == 'POST':
         email_to = request.POST.get('email_to', 'xdataonlineerrors@gmail.com')
@@ -20,8 +22,4 @@
         statusMessage = "Email sent!"
     elif status == 2:
         statusMessage = ""
-    return render(request, 'email_form.html', {'userprofiles': userprofiles, 'status': status, 'statusMessage': statusMessage})
-
-
-def printme(string):
-    print string
\ No newline at end of file
+    return render(request, 'email_form.html', {'userprofiles': userprofiles, 'status': status, 'statusMessage': statusMessage})
\ No newline at end of file
diff --git a/exp_portal/products.py b/exp_portal/products.py
index e299d19..140cc0f 100644
--- a/exp_portal/products.py
+++ b/exp_portal/products.py
@@ -1,15 +1,21 @@
 from django.shortcuts import render, redirect
 from op_tasks.models import Product, Dataset
+from django.contrib.auth.decorators import login_required
 
+@login_required(login_url='/tasking/login')
 def view_products(request):
 	products = Product.objects.all()
 	return render(request, 'products.html', {'products': products})
 
+
+@login_required(login_url='/tasking/login')
 def view_product_details(request, productname):
 	product = Product.objects.all().filter(name=productname)[0]
 	datasets = Dataset.objects.all()
 	return render(request, 'product_details.html', {'product': product, 'datasets': datasets})
 
+
+@login_required(login_url='/tasking/login')
 def edit_product(request, productpk):
 	product = Product.objects.get(id=productpk)
 	product.name = request.POST['product_name']
@@ -27,14 +33,20 @@
 
 	return redirect('exp_portal:view_products')
 
+
+@login_required(login_url='/tasking/login')
 def manage_products(request):
 	products = Product.objects.all()
 	return render(request, 'products.html', {'products': products})
 
+
+@login_required(login_url='/tasking/login')
 def add_product(request):
 	datasets = Dataset.objects.all()
 	return render(request, 'add_product.html', {'datasets': datasets})
 
+
+@login_required(login_url='/tasking/login')
 def new_product(request):
 	product = Product(name=request.POST['product_name'])
 	product.url = request.POST['product_url']
diff --git a/exp_portal/tasks.py b/exp_portal/tasks.py
index d9898af..7bd10b4 100644
--- a/exp_portal/tasks.py
+++ b/exp_portal/tasks.py
@@ -3,23 +3,32 @@
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import User
 
+@login_required(login_url='/tasking/login')
 def view_tasks(request):
 	tasks = OpTask.objects.all()
 	datasets = Dataset.objects.all()
 	return render(request, 'tasks.html', {'tasks': tasks, 'datasets':datasets})
 
+
+@login_required(login_url='/tasking/login')
 def view_completed(request):
 	completed_tasks = TaskListItem.objects.all().filter(task_complete=True).order_by('-date_complete')
 	return render(request, 'completed.html', {'completed_tasks': completed_tasks})
 
+
+@login_required(login_url='/tasking/login')
 def view_incomplete(request):
 	incomplete_tasks = TaskListItem.objects.all().filter(task_complete=False)
 	return render(request, 'incomplete.html', {'incomplete_tasks': incomplete_tasks})
-	
+
+
+@login_required(login_url='/tasking/login')
 def add_task(request):
 	datasets = Dataset.objects.all()
 	return render(request, 'add_task.html', {'datasets': datasets})
 
+
+@login_required(login_url='/tasking/login')
 def new_task(request):
 	dataset = Dataset.objects.get(name=request.POST['task_dataset'])
 	task = OpTask()
@@ -32,9 +41,13 @@
 	task.save()
 	return redirect('exp_portal:view_tasks')
 
+
+@login_required(login_url='/tasking/login')
 def manage_tasks(request):
 	return view_tasks(request)
 
+
+@login_required(login_url='/tasking/login')
 def view_task_details(request, taskname):
 	task = OpTask.objects.all().filter(name=taskname)[0]
 	datasets = Dataset.objects.all()
@@ -43,6 +56,8 @@
 		print dataset.name
 	return render(request, 'task_details.html', {'task': task, 'datasets': datasets})
 
+
+@login_required(login_url='/tasking/login')
 def edit_task(request, taskpk):
 	task = OpTask.objects.get(id=taskpk)
 	task.name = request.POST['task_name']
@@ -59,6 +74,8 @@
 
 	return redirect('exp_portal:view_tasks')
 
+
+@login_required(login_url='/tasking/login')
 def delete_task(request, taskpk):
 	task = OpTask.objects.get(id=taskpk)
 	task.delete()
diff --git a/exp_portal/users.py b/exp_portal/users.py
index 500ddf4..f4138fb 100644
--- a/exp_portal/users.py
+++ b/exp_portal/users.py
@@ -4,14 +4,18 @@
 from django.contrib.auth.models import User
 from django.http import JsonResponse
 
+@login_required(login_url='/tasking/login')
 def view_users(request):
 	userprofiles = UserProfile.objects.all().order_by('-user__last_login')
 	return render(request, 'users.html', {'userprofiles': userprofiles})
 
+@login_required(login_url='/tasking/login')
 def manage_users(request):
 	userprofiles = UserProfile.objects.all().order_by('-user__last_login')
 	return render(request, 'users.html', {'userprofiles': userprofiles})
 
+
+@login_required(login_url='/tasking/login')
 def edit_user(request, userprofilepk):
 	userprofile = UserProfile.objects.get(id=userprofilepk)
 	experiment = Experiment.objects.get(name=request.POST['experiment_name'])
@@ -20,11 +24,15 @@
 
 	return redirect('exp_portal:view_users')
 
+
+@login_required(login_url='/tasking/login')
 def add_user(request):
 	experiments = Experiment.objects.all()
 	products = Product.objects.all()
 	return render(request, 'add_user.html', {'experiments': experiments, 'products':products})
 
+
+@login_required(login_url='/tasking/login')
 def delete_user(request, userprofilepk):
 	userprofile = UserProfile.objects.get(id=userprofilepk)
 	user = userprofile.user
@@ -38,6 +46,8 @@
 
 	return redirect('exp_portal:view_users')
 
+
+@login_required(login_url='/tasking/login')
 def new_user(request):
 	user = User(username=request.POST['username'])
 	user.set_password(request.POST['password_1'])
@@ -97,9 +107,13 @@
 
 	return redirect('exp_portal:view_users')
 
+
+@login_required(login_url='/tasking/login')
 def user_added(request):
 	return render(request, 'user_added.html')
 
+
+@login_required(login_url='/tasking/login')
 def view_user_tasks(request, profile):
 	userprofile = UserProfile.objects.all().filter(user_hash=profile)[0]
 	usertasks = userprofile.tasklistitem_set.all()
@@ -115,6 +129,8 @@
 
 	return render(request, 'user_tasks.html', {'userprofile': userprofile, 'experiments':experiments})
 
+
+@login_required(login_url='/tasking/login')
 def add_user_task(request, userpk):
 	userprofile = UserProfile.objects.get(id=userpk)
 	datasets = Dataset.objects.all()
@@ -123,6 +139,8 @@
 	return render(request, 'add_user_task.html', {'userprofile':userprofile, 
 		'datasets': datasets, 'products': products, 'tasks': tasks})
 
+
+@login_required(login_url='/tasking/login')
 def update_user_tasks(request, userpk, datasetpk, productpk, taskpk):
 	dataset = Dataset.objects.get(id=datasetpk)
 	userprofile = UserProfile.objects.get(id=userpk)
@@ -138,6 +156,8 @@
 
 	return redirect('exp_portal:add_user_task', userpk)
 
+
+@login_required(login_url='/tasking/login')
 def view_users_experiment(request, experiment_name):
 	experiment = Experiment.objects.get(name=experiment_name)
 	userprofiles = experiment.userprofile_set.all()
diff --git a/exp_portal/views.py b/exp_portal/views.py
index c2e2b78..6e05ec3 100644
--- a/exp_portal/views.py
+++ b/exp_portal/views.py
@@ -13,6 +13,8 @@
 def home_page(request):
 	return render(request, 'experimenthome.html')
 
+
+@login_required(login_url='/tasking/login')
 def view_status(request):
 	experiments = Experiment.objects.all()
 	masterList = {}
@@ -49,16 +51,19 @@
 	return render(request, 'status.html', {'experimentList': masterList})	
 
 
+@login_required(login_url='/tasking/login')
 def manage_exps(request):
 	experimentlist = Experiment.objects.all()
 	return render(request, 'experiments.html', {'experimentlist': experimentlist})
 
 
+@login_required(login_url='/tasking/login')
 def view_exp_details(request, exppk):
 	experiment = Experiment.objects.get(id=exppk)
 	return render(request, 'experiment_details.html', {'experiment':experiment})
 
 
+@login_required(login_url='/tasking/login')
 def add_exp(request):
 	if request.method == 'POST':
 		experiment = Experiment()
@@ -79,6 +84,7 @@
 	return render(request, 'add_experiment.html')
 
 
+@login_required(login_url='/tasking/login')
 def edit_exp(request, exppk):
 	experiment = Experiment.objects.get(id=exppk)
 	experiment.name = request.POST['exp_name']
@@ -97,16 +103,19 @@
 	return redirect('exp_portal:manage_exps')
 
 
+@login_required(login_url='/tasking/login')
 def manage_datasets(request):
 	datasets = Dataset.objects.all()
 	return render(request, 'datasets.html', {'datasets':datasets})
 
 
+@login_required(login_url='/tasking/login')
 def view_dataset_details(request, datasetpk):
 	dataset = Dataset.objects.get(id=datasetpk)
 	return render(request, 'dataset_details.html', {'dataset':dataset})
 
 
+@login_required(login_url='/tasking/login')
 def add_dataset(request):
 	if request.method == 'POST':
 		# do update
@@ -121,6 +130,7 @@
 	return render(request, 'add_dataset.html')
 
 
+@login_required(login_url='/tasking/login')
 def edit_dataset(request, datasetpk):
 	dataset = Dataset.objects.get(id=datasetpk)
 	dataset.name = request.POST['dataset_name']
@@ -132,6 +142,7 @@
 	return redirect('exp_portal:manage_datasets')
 
 
+@login_required(login_url='/tasking/login')
 def view_experiment_products(request):
 	experiments = Experiment.objects.all()
 	masterList = {}
diff --git a/op_tasks/views.py b/op_tasks/views.py
index d20c68a..b7ea8e0 100755
--- a/op_tasks/views.py
+++ b/op_tasks/views.py
@@ -9,12 +9,21 @@
 from django.contrib.auth.models import User
 from django.utils import timezone
 from elasticsearch import Elasticsearch
+from Crypto.Cipher import AES
 
 import exp_portal
 import datetime
 
 from op_tasks.models import Product, UserProfile, TaskListItem, Experiment
 
+import exceptions
+import hashlib
+import logging
+#import zlib
+#import sqlite
+
+from op_tasks.models import Dataset, Product, OpTask, UserProfile, TaskListItem, Experiment
+logger = logging.getLogger('op_tasks')
 
 def set_cookie(response, key, value, days_expire = 7):
   if days_expire is None:
@@ -44,6 +53,7 @@
     return len(timestamps)
    
 # manages which prodct is delivered to the current user
+@login_required(login_url='/tasking/login')
 def product(request, task_pk):
     if request.method == 'POST':
         user = request.user
@@ -155,8 +165,46 @@
 
     return render(request, 'task_launch.html', {'tasklistitem': tasklistitem})
 
+# Get unencrypted username
+def decryptUsername(request):
+	user = request.user
+	return aesDecryptor(user.username)
+
+# decrypt the text passed in
+def aesDecryptor(encryptedText):
+	key = readInKey('fileLocation') #'0123456789abcdef0123456789abcdef'
+	IV = 16 * '\x00'           # Initialization vector: discussed later
+	mode = AES.MODE_CBC
+	decryptor = AES.new(key, mode, IV=IV)
+	plainText = decryptor.decrypt(ciphertext)
+	return plainText
+
+# encrypt the text passed in
+def aesEncryptor(plainText):
+	key = readInKey('fileLocation') #'0123456789abcdef0123456789abcdef'
+	IV = 16 * '\x00'           # Initialization vector: discussed later
+	mode = AES.MODE_CBC
+	encryptor = AES.new(key, mode, IV=IV)
+	if len(plainText) % 16 != 0:
+	    plainText += ' ' * (16 - len(plainText) % 16)
+	cipherText = encryptor.encrypt(plainText)
+	return cipherText;
+
+def readInKey(fileLocation):
+	# Open file and read in key (TODO)
+	# For now, create a 32-bit key from a phrase
+	key = createKeyFromPhrase("WouldYouLike12Muffins?")
+	return key
+
+# Will not need this function when key is read in from file while running operationally
+def createKeyFromPhrase(phrase):
+	key = hashlib.sha256(phrase).digest()
+	return key
+
 # cretaes a new user and assigns tasks 
 def register(request):
+    logging.basicConfig(filename='/home/ubuntu/logs/log.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
+    logger.debug("Logging is working.")
     # Like before, get the request's context.
     context = RequestContext(request)
 
@@ -171,6 +219,10 @@
         # Once hashed, we can update the user object.
         user = User(username=request.POST['username'])
         user.set_password(request.POST['password'])
+        logger.debug("This is the username: ", user.username, " and password, before encryption: ", user.password)
+        user.username = aesEncryptor(user.username).decode('utf-16')
+        #user.username = sqlite3.Binary(zlib.compress(aesEncryptor(user.username)))
+        logger.debug("This is the username: ", user.username, " and password, after encryption: ", user.password)
         user.email = user.username
         user.save()
 
@@ -186,6 +238,7 @@
 
         # Now we save the UserProfile model instance.
         userprofile.save()
+        logger.debug("Saved the user profile successfully")
 
         # Finally we assign tasks to the new user
         # Get a random product, get a random order of tasks
@@ -242,6 +295,8 @@
         # Gather the username and password provided by the user.
         # This information is obtained from the login form.
         username = request.POST['username']
+        #username = sqlite3.Binary(zlib.compress(aesEncryptor(username)))
+        username = aesEncryptor(username).decode('utf-16')
         password = request.POST['password']
         # print "Login attempt by " + username + " at " + datetime
 
@@ -356,4 +411,4 @@
 
 
 def view_profile(request):
-    return render(request, 'user_profile.html', {'user': request.user})
\ No newline at end of file
+    return render(request, 'user_profile.html', {'user': request.user})
diff --git a/uploads/views.py b/uploads/views.py
index a070caa..a75fea1 100644
--- a/uploads/views.py
+++ b/uploads/views.py
@@ -2,6 +2,7 @@
 from op_tasks.models import Experiment
 from django.http import HttpResponseRedirect
 from django.core.urlresolvers import reverse
+from django.contrib.auth.decorators import login_required
 
 import pandas
 import numpy as np
@@ -11,6 +12,7 @@
 from models import Document
 from forms import DocumentForm
 
+@login_required(login_url='/tasking/login')
 def expuploads(request):
     # Handle file uploads
     if request.method == 'POST':
@@ -28,13 +30,14 @@
         return render(request, 'expuploads.html', {'form': form, 'experiments': experiments})
 
 def handle_uploaded_file(f, dirname):
-    path = os.path.join('static/results/', dirname)
+    path = os.path.join('../static/results', dirname)
     try:
-        os.mkdir(path)
-    except:
-        pass
+        os.makedirs(path)
+    except OSError as e:
+        print e
+        print 'unable to create directory ' + path
     file = f['docfile']
-    with open(path  + '/' + file.name, 'wb+') as destination:
+    with open(path + '/' + file.name, 'wb+') as destination:
         for chunk in file.chunks():
             destination.write(chunk)
 
@@ -54,7 +57,7 @@
     tools = pandas.DataFrame(workingData['SYS.FIL.APP.']).drop_duplicates().sort('SYS.FIL.APP.').reset_index();
     del tools['index']
     tools.columns = ['Tools']
-    tools.to_json(path_or_buf=path + '\/' + "tools.json")
+    tools.to_json(path_or_buf=path + '/' + "tools.json")
 
 
     metrics = {'load':{'col':'PST.EXP.CLD.CP.','max':5},
@@ -86,4 +89,4 @@
                 array.append(subarray)
         d = pandas.DataFrame(array, columns=('Tool', 'Range'))
         result = pandas.ordered_merge(df,d)
-        result.to_csv(path_or_buf=path + '\/' + str(key) + '.csv', sep=',',na_rep='0',index=False)
\ No newline at end of file
+        result.to_csv(path_or_buf=path + '/' + str(key) + '.csv', sep=',',na_rep='0',index=False)
\ No newline at end of file
diff --git a/xdata/settings.py b/xdata/settings.py
index b1f45a8..493429f 100755
--- a/xdata/settings.py
+++ b/xdata/settings.py
@@ -46,6 +46,7 @@
     'exp_portal',
     'developer',
     'uploads',
+    'axes',
 )
 
 MIDDLEWARE_CLASSES = (
@@ -55,6 +56,7 @@
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'axes.middleware.FailedLoginMiddleware',
 )
 
 ROOT_URLCONF = 'xdata.urls'
@@ -72,9 +74,17 @@
 # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
 
 DATABASES = {
+#    'default': {
+#        'ENGINE': 'django.db.backends.sqlite3',
+#        'NAME': os.path.join(BASE_DIR, '../db', 'db.sqlite3'),
+#    }
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, '../db', 'db.sqlite3'),
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',
+        'NAME': 'xdatadb',
+        'USER': 'xdatauser',
+        'PASSWORD': 'xd@t@!',
+        'HOST': '127.0.0.1',
+        'PORT': '',
     }
 }
 
@@ -118,4 +128,9 @@
 EMAIL_HOST = 'smtp.gmail.com'
 EMAIL_HOST_USER = 'xdataonline@gmail.com'
 EMAIL_HOST_PASSWORD = MY_EMAIL_PASSWORD
-EMAIL_PORT = 587
\ No newline at end of file
+EMAIL_PORT = 587
+
+# After three failed logins, require users to wait 5 minutes before they can attempt to log in again
+AXES_LOGIN_FAILURE_LIMIT = 3
+from datetime import timedelta
+AXES_COOLOFF_TIME=timedelta(seconds = 300)
diff --git a/xdata/urls.py b/xdata/urls.py
index b9feb46..6b8c79a 100755
--- a/xdata/urls.py
+++ b/xdata/urls.py
@@ -10,7 +10,7 @@
 	# include urls for op_tasks and administration pages
     url(r'^tasking/', include('op_tasks.urls', namespace="op_tasks")),
     url(r'^experiment/', include('exp_portal.urls', namespace="exp_portal")),
-    url(r'^developer/', include('developer.urls', namespace="developer")),
+    # url(r'^developer/', include('developer.urls', namespace="developer")),
     url(r'^user_feedback/', views.user_feedback_home, name='user_feedback_home'),
     url(r'^admin/', include(admin.site.urls)),
     url(r'^', include('uploads.urls')),