"
+
+ for j in range(width):
+ node = grid[i][j]
+ td = "
"
+
+ # if the node is empty, do nothing.
+ if node["type"] == "empty":
+ pass
+
+ # if the node is a connection, draw the right arrows in the
+ # right direction
+ elif node["type"] == "conn":
+
+ # for a double connection we need to add two divs
+ if node["prop"]["class"] == "tree_connect_top_lr":
+ td += ""
+ td += ""
+ # for a single connection we need to add one div
+ else:
+ td += ""
+ else:
+ if "is_filter" in node["prop"] and node["prop"]["is_filter"]:
+ key = escape(node["prop"]["key"])
+ value = escape(node["prop"]["value"])
+
+ box = """
+ """.format(classescape(node["prop"]["op"]))
+
+ td += renderBox(box, node["prop"]["input"],
+ node["prop"]["output"])
+
+ # close the cell and add it to the row
+ td += "
"
+ tr += td
+
+ # close the table row and add it to the table
+ tr += "
"
+ table += tr
+
+ # close the table
+ table += "
"
+ return table
+
+
+def renderStatusNode(addClass, status):
+ return ""
+
+
+def renderBox(contentNode, inStatus, outStatus):
+ # make a box to contain all the other items
+ box = "
"
+
+ # render a box for the output
+ box += renderStatusNode("status_node_center", outStatus)
+
+ # make a central box for the content
+ box += "
" + contentNode + "
"
+
+ # make two nodes for input / output
+ if (len(inStatus) == 1):
+ box += renderStatusNode("status_node_center", inStatus[0])
+ elif (len(inStatus) == 2):
+ box += renderStatusNode("status_node_left", inStatus[0])
+ box += renderStatusNode("status_node_right", inStatus[1])
+
+ # close the box
+ box += "
"
+
+ # and return it.
+ return box
diff --git a/filters/models.py b/filters/models.py
index dca5c8a..b706068 100644
--- a/filters/models.py
+++ b/filters/models.py
@@ -8,7 +8,8 @@
from settings.models import VotingSystem
-import filters.forest as forest
+from filters.forest import logic
+from jay import utils
# Create your models here.
@@ -23,7 +24,7 @@ def __str__(self):
def clean(self):
try:
- self.tree = json.dumps(forest.parse_and_simplify(self.value))
+ self.tree = json.dumps(logic.parse(self.value))
except Exception as e:
self.tree = None
@@ -41,23 +42,29 @@ def matches(self, obj):
"""
try:
- return forest.matches(json.loads(self.tree), obj)
+ return logic.matches(json.loads(self.tree), obj)
except Exception as e:
import sys
sys.stderr.write(e)
return False
- def map_matches(self, objs):
+ def count_matches(self, objs):
+ """ Counts the number of objects matching this filter"""
- try:
- return forest.map_match(json.loads(self.tree), objs)
- except Exception as e:
- return False
+ tree = json.loads(self.tree)
+ c = 0
+
+ for obj in objs:
+ try:
+ if logic.matches(tree, obj):
+ c += 1
+ except:
+ pass
+
+ return c
def canEdit(self, user):
- """
- Checks if a user can edit this UserFilter.
- """
+ """ Checks if a user can edit this UserFilter. """
return self.system.isAdmin(user)
diff --git a/filters/templatetags/filter.py b/filters/templatetags/filter.py
index f794437..a02fdac 100644
--- a/filters/templatetags/filter.py
+++ b/filters/templatetags/filter.py
@@ -1,5 +1,7 @@
from django import template
-import filters.forest as forest
+from django.utils.safestring import mark_safe
+
+from filters.forest import logic, layouter, renderer
import json
register = template.Library()
@@ -11,16 +13,16 @@ def render_full(src, inp):
obj = json.loads(inp)
# parse the source code
- tree = forest.parse(src)
+ tree = logic.parse(src)
# make a layout with the given object
- layout = forest.layouter(tree, obj)
+ layout = layouter.layouter(tree, obj)
# and finally render it
- render = forest.renderer(layout)
+ render = renderer.renderer(layout)
# that is what we return
- return render
+ return mark_safe(render)
@register.simple_tag(takes_context=False)
@@ -31,4 +33,4 @@ def render_lbox(name, inp, out):
inp = list(map(lambda x: x == '1', str(inp)))
out = (out == '1')
- return forest.renderer_box(box, inp, out)
+ return mark_safe(renderer.renderBox(box, inp, out))
diff --git a/filters/views.py b/filters/views.py
index deec2a2..b6fcf2f 100644
--- a/filters/views.py
+++ b/filters/views.py
@@ -10,13 +10,14 @@
from filters.models import UserFilter
from filters.forms import NewFilterForm, EditFilterForm, FilterTestForm, \
FilterTestUserForm
-import filters.forest as forest
-import json
+from filters.forest import logic
from votes.models import VotingSystem
-from jay.utils import priviliged
+from jay.utils import elevated, is_elevated, get_user_details
+
+import json
FILTER_FOREST_TEMPLATE = "filters/filter_forest.html"
FILTER_EDIT_TEMPLATE = "filters/filter_edit.html"
@@ -24,10 +25,10 @@
@login_required
-@priviliged
+@elevated
def Forest(request, alert_type=None, alert_head=None, alert_text=None):
# if the user does not have enough priviliges, throw an exception
- if not request.user.profile.isElevated():
+ if not is_elevated(request.user):
raise PermissionDenied
# build a new context
@@ -40,7 +41,7 @@ def Forest(request, alert_type=None, alert_head=None, alert_text=None):
{'url': reverse('filters:forest'), 'text': 'Filters', 'active': True})
ctx['breadcrumbs'] = bc
- (admin_systems, other_systems) = request.user.profile.getSystems()
+ (admin_systems, other_systems) = VotingSystem.splitSystemsFor(request.user)
# give those to the view
ctx['admin_systems'] = admin_systems
@@ -79,7 +80,7 @@ def FilterNew(request):
# check if the user can edit it.
# if not, go back to the overview
- if not system.isAdmin(request.user.profile):
+ if not system.isAdmin(request.user):
return Forest(request, alert_head="Creation failed",
alert_text="Nice try. You are not allowed to edit "
"this VotingSystem. ")
@@ -115,7 +116,7 @@ def FilterDelete(request, filter_id):
# check if the user can edit it.
# if not, go back to the overview
- if not system.isAdmin(request.user.profile):
+ if not system.isAdmin(request.user):
return Forest(request, alert_head="Deletion failed",
alert_text="Nice try. You don't have permissions to "
"delete this filter. ")
@@ -139,7 +140,7 @@ def FilterDelete(request, filter_id):
@login_required
-@priviliged
+@elevated
def FilterEdit(request, filter_id):
# make a context
ctx = {}
@@ -149,7 +150,7 @@ def FilterEdit(request, filter_id):
ctx["filter"] = filter
# check if the user can edit it
- if not filter.canEdit(request.user.profile):
+ if not filter.canEdit(request.user):
raise PermissionDenied
# Set up the breadcrumbs
@@ -175,7 +176,7 @@ def FilterEdit(request, filter_id):
# check if we have a valid tree manually
try:
- tree = forest.parse(form.cleaned_data['value'])
+ tree = logic.parse(form.cleaned_data['value'])
if not tree:
raise Exception
except Exception as e:
@@ -207,7 +208,7 @@ def FilterEdit(request, filter_id):
@login_required
-@priviliged
+@elevated
def FilterTest(request, filter_id, obj=None):
# try and grab the user filter
filter = get_object_or_404(UserFilter, id=filter_id)
@@ -244,7 +245,7 @@ def FilterTest(request, filter_id, obj=None):
@login_required
-@priviliged
+@elevated
def FilterTestUser(request, filter_id):
# try and grab the user filter
filter = get_object_or_404(UserFilter, id=filter_id)
@@ -259,7 +260,8 @@ def FilterTestUser(request, filter_id):
form = FilterTestUserForm(request.POST)
if form.is_valid():
obj = form.cleaned_data["user"]
- obj = User.objects.filter(username=obj)[0].profile.details
+ obj = json.dumps(get_user_details(
+ User.objects.filter(username=obj)[0]))
except Exception as e:
print(e)
pass
diff --git a/jay/settings.py b/jay/settings.py
index 825a9c0..1cdc6eb 100644
--- a/jay/settings.py
+++ b/jay/settings.py
@@ -25,7 +25,15 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'django.contrib.sites',
+
'django_forms_bootstrap',
+
+ 'allauth',
+ 'allauth.account',
+ 'allauth.socialaccount',
+ 'dreamjub.providers.oauth',
+
'filters',
'settings',
'users',
@@ -65,12 +73,21 @@
WSGI_APPLICATION = 'jay.wsgi.application'
# OpenJUB auth
-AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
- 'users.ojub_auth.OjubBackend')
+AUTHENTICATION_BACKENDS = (
+ 'django.contrib.auth.backends.ModelBackend',
+ 'allauth.account.auth_backends.AuthenticationBackend',
+)
+
+# the token and secret for oauth
+DREAMJUB_CLIENT_URL = 'http://localhost:9000/'
+DREAMJUB_CLIENT_ID = '7ZYpfROz1AEUDbsTQJJuy4RNL8LVSRTONOAXcjm4'
+DREAMJUB_CLIENT_SECRET = 'EkeeT0GgOGOQRHbgFE4n1RERxVNSiOD1HZ80TRfERiWj3cK1hZ' \
+ 'oTodH0kv8tz3gbqk53YMDuUFAsoaJkMEg1OM1RrZyd1xaYUGv5' \
+ 'CtmHrpmJavc2JvRDNUAkFJgORpUW'
# Default after login redirect
# These are named URL routes
-LOGIN_URL = "login"
+LOGIN_URL = "accounts/dreamjub/login"
LOGOUT_URL = "logout"
LOGIN_REDIRECT_URL = "home"
@@ -91,3 +108,6 @@
)
STATIC_URL = '/static/'
+SITE_ID = 1
+
+ACCOUNT_EMAIL_VERIFICATION = "none"
diff --git a/jay/urls.py b/jay/urls.py
index 34ffe79..6e77dd9 100644
--- a/jay/urls.py
+++ b/jay/urls.py
@@ -49,8 +49,7 @@
name="filter_help"),
# Authentication
- url(r'^login/', auth_views.login, {'template_name': 'auth/login.html'},
- name="login"),
+ url(r'^accounts/', include('allauth.urls'), name='login'),
url(r'^logout/', auth_views.logout,
{'template_name': 'auth/logout.html', 'next_page': 'home'},
name="logout"),
diff --git a/jay/utils.py b/jay/utils.py
index 698bda5..41ced99 100644
--- a/jay/utils.py
+++ b/jay/utils.py
@@ -13,24 +13,48 @@ def helper(*x):
return helper
+def is_superadmin(user):
+ """ Checks if a user is a superadmin. """
+ return user.is_superuser
+
+
+def is_elevated(user):
+ """ Checks if a user is an admin for some voting system """
+ if not user.is_superuser:
+ if not user.admin_set.count() > 0:
+ return False
+ return True
+
+
def superadmin(handler):
- """ Checks if a user is a super admin. """
+ """ Requires a user to be a superadmin. """
def helper(request, *args, **kwargs):
- if not request.user.profile.isSuperAdmin():
+ if not is_superadmin(request.user):
raise PermissionDenied
return handler(request, *args, **kwargs)
return helper
-def priviliged(handler):
- """ Checks that a user has elevated privileges. """
+def elevated(handler):
+ """ Requires a user to be elevated user """
def helper(request, *args, **kwargs):
- if not request.user.profile.isElevated():
+ if not is_elevated(request.user):
raise PermissionDenied
return handler(request, *args, **kwargs)
return helper
+
+
+def get_user_details(user):
+ """ Gets a dict() object representing user data """
+
+ try:
+ data = user.socialaccount_set.get(provider="dreamjub").extra_data
+ return data
+ except:
+ # fallback to an in-active user with just a username flag
+ return {'username': user.username, 'active': False}
diff --git a/requirements.txt b/requirements.txt
index 8b63007..b002762 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,10 +8,14 @@ django-forms-bootstrap==3.0.1
Markdown==2.6.5
# For filters
-PyExecJS==1.1.0
-
-# For OpenJUB auth backend
-requests==2.6.0
+pre-js-py==1.1.0
# For testing pep
-pep8 >= 1.7.0
\ No newline at end of file
+pep8 >= 1.7.0
+
+# For authing against dreamjub
+django-allauth==0.29.0
+django-allauth-dreamjub==0.1.3
+
+# for counting users
+requests-oauthlib==0.8.0
diff --git a/settings/models.py b/settings/models.py
index cfeea0a..06de8a4 100644
--- a/settings/models.py
+++ b/settings/models.py
@@ -3,6 +3,8 @@
from django.contrib import admin
from jay.restricted import is_restricted_word
+from jay.utils import is_superadmin
+from users.models import Admin
class VotingSystem(models.Model):
@@ -16,16 +18,47 @@ def clean(self):
is_restricted_word('machine_name', self.machine_name)
def canEdit(self, user):
- """
- Checks if a user can edit this voting system.
- """
- return user.isSuperAdmin()
+ """ Checks if a user can edit this voting system. """
+
+ return is_superadmin(user)
def isAdmin(self, user):
- """
- Checks if a user is an administrator for this voting system.
- """
- return user.isAdminFor(self)
+ """ Checks if a user is an administrator for this voting system. """
+ if user.is_anonymous:
+ return False
+ return self.canEdit(user) or \
+ Admin.objects.filter(system=self, user=user).exists()
+
+ @classmethod
+ def getAdminSystems(cls, user):
+ """ returns a pair (admin, others) of systems for a given user """
+
+ # if a user is a super admin all of them
+ if is_superadmin(user):
+ return VotingSystem.objects.all()
+ if user.is_anonymous:
+ return VotingSystem.objects.none()
+
+ return VotingSystem.objects.filter(admin__user=user)
+
+ @classmethod
+ def splitSystemsFor(cls, user):
+ """ returns a pair (admin, others) of systems for a given user """
+
+ # if a user is a super admin, return (all, none)
+ if is_superadmin(user):
+ return VotingSystem.objects.all(), VotingSystem.objects.none()
+
+ # if are anonymous return (none, all)
+ if user.is_anonymous:
+ return VotingSystem.objects.none(), VotingSystem.objects.all()
+
+ # else we need two quieries
+ administered = VotingSystem.objects.filter(admin__user=user)
+ others = VotingSystem.objects.exclude(admin__user=user)
+
+ # and return both QuerySets
+ return administered, others
admin.site.register(VotingSystem)
diff --git a/settings/urls.py b/settings/urls.py
index db501ca..a0de000 100644
--- a/settings/urls.py
+++ b/settings/urls.py
@@ -1,15 +1,15 @@
from django.conf.urls import url
from django.views.generic import TemplateView
-from settings.views import superadmins, systems
+from settings.views import systems
urlpatterns = [
# Superadmin management
- url(r'^$', superadmins.settings, name="settings"),
- url(r'^superadmins/add$', superadmins.superadmin_add, name="add"),
- url(r'^superadmins/(?P[\w-]+)/remove$',
- superadmins.superadmin_remove, name="remove"),
+ # url(r'^$', superadmins.settings, name="settings"),
+ # url(r'^superadmins/add$', superadmins.superadmin_add, name="add"),
+ # url(r'^superadmins/(?P[\w-]+)/remove$',
+ # superadmins.superadmin_remove, name="remove"),
# System management
url(r'^systems$', systems.systems, name='systems'),
diff --git a/settings/views/systems.py b/settings/views/systems.py
index 85f5f6c..5c1b580 100644
--- a/settings/views/systems.py
+++ b/settings/views/systems.py
@@ -52,7 +52,6 @@ def system_edit(request, system_id):
except Exception as e:
ctx['alert_head'] = 'Saving failed'
ctx['alert_text'] = 'Invalid data submitted'
- print(e)
return render(request, SETTINGS_SYSTEMS_EDIT_TEMPLATE, ctx)
diff --git a/static/js/forest/logic.js b/static/js/forest/logic.js
index 104b0cc..5a45508 100644
--- a/static/js/forest/logic.js
+++ b/static/js/forest/logic.js
@@ -331,207 +331,6 @@
return parse_binary(ast);
};
- // simplifies a boolean expression.
- var simplify = function (obj) {
-
- var left, left_op;
- var right, right_op;
-
- if (obj['operation'] == OP_AND[0]) {
- // simplifiy on the left and on the right
- left = simplify(obj['left']);
- right = simplify(obj['right']);
-
- // find left and right operations
- left_op = left['operation'];
- right_op = right['operation'];
-
- // if the right operation is a constant
- if (right_op == OP_TRUE[0]){
- return left;
- }
-
- if (right_op == OP_FALSE[0]){
- return {'operation': OP_FALSE[0]};
- }
-
- if (left_op == OP_TRUE[0]){
- return right;
- }
-
- if (left_op == OP_FALSE[0]){
- return {'operation': OP_FALSE[0]};
- }
-
- // else return the cleaned operation
- return {'operation': OP_AND[0], 'left': left, 'right': right}
- }
-
- if(obj['operation'] == OP_NAND[0]){
- // simplify on the left and on the right
- left = simplify(obj['left']);
- right = simplify(obj['right']);
-
- // find left and right operations
- left_op = left['operation'];
- right_op = right['operation'];
-
- // if the right operation is a constant
- if(right_op == OP_TRUE[0]){
- return simplify({
- operation: OP_NOT[0],
- 'right': left
- });
- }
-
- if(right_op == OP_FALSE[0]){
- return {'operation': OP_TRUE[0]};
- }
-
-
- // if the left operation is a constant
- if (left_op == OP_TRUE[0]){
- return simplify({
- operation: OP_NOT[0],
- 'right': right
- });
- }
-
- if(left_op == OP_FALSE[0]){
- return {'operation': OP_TRUE[0]};
- }
-
- // else return the cleaned operation
- return {'operation': OP_NAND[0], 'left': left, 'right': right}
- }
-
-
- if(obj['operation'] == OP_OR[0]){
- // simplify on the left and on the right
- left = simplify(obj['left']);
- right = simplify(obj['right']);
-
- // find left and right operations
- left_op = left['operation'];
- right_op = right['operation'];
-
- // if the right operation is a constant
- if(right_op == OP_TRUE[0]){
- return {'operation': OP_TRUE[0]};
- }
-
- if(right_op == OP_FALSE[0]){
- return left;
- }
-
-
- // if the left operation is a constant
- if(left_op == OP_TRUE[0]){
- return {'operation': OP_TRUE[0]};
- }
-
- if(left_op == OP_FALSE[0]){
- return right;
- }
-
-
- // else return the cleaned operation
- return {'operation': OP_OR[0], 'left': left, 'right': right};
- }
-
- if(obj['operation'] == OP_XOR[0]){
-
- // simplify on the left and on the right
- left = simplify(obj['left']);
- right = simplify(obj['right']);
-
- // find left and right operations
- left_op = left['operation'];
- right_op = right['operation'];
-
- // if the right operation is a constant
- if(right_op == OP_TRUE[0]){
- return simplify({
- 'operation': OP_NOT[0],
- 'right': left
- });
- }
-
- if(right_op == OP_FALSE[0]){
- return left;
- }
-
-
- // if the left operation is a constant
- if (left_op == OP_TRUE[0]) {
- return simplify({
- 'operation': OP_NOT[0],
- 'right': right
- });
- }
-
- if (left_op == OP_FALSE[0]) {
- return right;
- }
-
- // else return the cleaned operation
- return {'operation': OP_XOR[0], 'left': left, 'right': right};
- }
-
- if(obj['operation'] == OP_NOT[0]) {
- // simplify the sub operation
- right = simplify(obj['right']);
-
- // find the operation on the right
- right_op = right['operation'];
-
- // remove true / false
- if(right_op == OP_TRUE[0]) {
- return {'operation': OP_FALSE[0]};
- }
-
- if(right_op == OP_FALSE[0]) {
- return {'operation': OP_TRUE[0]};
- }
-
- // remove double nots
- if(right_op == OP_NOT[0]){
- return simplify(right['right']);
- }
-
- // ! nand => and
- if( right_op == OP_NAND[0]){
- return {
- 'operation': OP_AND[0],
- 'left': right['left'],
- 'right': right['right']
- };
- };
-
- // ! and => nand
- if(right_op == OP_AND[0]){
- return {
- 'operation': OP_NAND[0],
- 'left': right['left'],
- 'right': right['right']
- };
- }
-
- // ! or(a, b) = and(!a, !b)
- if (right_op == OP_OR[0]){
- return {
- 'operation': OP_AND[0],
- 'left': simplify({operation:OP_NOT[0], right: right['left']}),
- 'right': simplify({operation:OP_NOT[0], right: right['right']}),
- }
- }
-
- return {'operation': OP_NOT[0], 'right': simplify(obj['right'])}
- }
- // otherwise it is a filter, so return as is.
- return obj
- };
-
var matches_logical = function (tree, obj) {
// operation of the tree
@@ -685,7 +484,6 @@
// exports the entire thing in a namespace
var logic = {
'parse': parse,
- 'simplify': simplify,
'matches': matches,
'op_list': {
diff --git a/templates/auth/login.html b/templates/auth/login.html
deleted file mode 100644
index aadffe3..0000000
--- a/templates/auth/login.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{% extends "base/base.html" %}
-
-{% block page_title %}Login{% endblock %}
-
-{% block content %}
-
-{% if form.errors %}
-
- Invalid login. Your username and password didn't match. Please try again.
-
-{% endif %}
-
-{% if next %}
- {% if user.is_authenticated %}
-
- No rights. Your account doesn't have access to this page. To proceed,
- please login with an account that has access.
-
- {% else %}
-
- Login required. Please login to view this page.
-
diff --git a/templates/vote/fragments/vote_list.html b/templates/vote/fragments/vote_list.html
index f73dc3b..6c7cf1f 100644
--- a/templates/vote/fragments/vote_list.html
+++ b/templates/vote/fragments/vote_list.html
@@ -12,13 +12,13 @@
{{ vote.name }}
- {% if vote|can_delete:request.user.profile %}
+ {% if vote|can_delete:request.user %}
{% endif %}
- {% if vote|can_edit:request.user.profile %}
+ {% if vote|can_edit:request.user %}
diff --git a/templates/vote/fragments/vote_stage.html b/templates/vote/fragments/vote_stage.html
index bbd57a0..2f0a076 100644
--- a/templates/vote/fragments/vote_stage.html
+++ b/templates/vote/fragments/vote_stage.html
@@ -7,7 +7,7 @@
-
+
@@ -15,7 +15,8 @@
- Re-enter your password to stage the vote. This will prevent any further changes to be made. Staging the vote may take a few seconds.
+ Enter the name of this vote {{ vote.machine_name | escape }} to stage it.
+ This will prevent further edits from being made. Staging a vote may take a few seconds.
@@ -38,7 +39,8 @@
- Re-enter your password to update eligibility count. This may take a few seconds.
+ Enter the name of this vote, {{ vote.machine_name | escape }}, to update eligibility count.
+ This may take a few seconds.
diff --git a/users/models.py b/users/models.py
index b8f9d93..f7e15ac 100644
--- a/users/models.py
+++ b/users/models.py
@@ -1,19 +1,13 @@
from django.db import models
from django.contrib.auth.models import User
-from django.core.exceptions import ValidationError
-
from django.contrib import admin
-from settings.models import VotingSystem
-
-import json
-
# Create your models here.
class Admin(models.Model):
user = models.ForeignKey(User)
- system = models.ForeignKey(VotingSystem)
+ system = models.ForeignKey("settings.VotingSystem")
class Meta():
unique_together = (("system", "user"))
@@ -22,87 +16,4 @@ def __str__(self):
return u'[%s] %s' % (self.system.machine_name, self.user)
-class SuperAdmin(models.Model):
- user = models.ForeignKey(User)
-
- class Meta():
- unique_together = (("user",),)
-
- def __str__(self):
- return u'%s' % (self.user)
-
-
-class UserProfile(models.Model):
- user = models.OneToOneField(User, related_name="profile")
- details = models.TextField()
-
- def __str__(self):
- return u'[Profile] %s' % (self.user.username)
-
- def clean(self):
- # make sure that the details are a valid json object
- try:
- json.loads(self.details)
- except:
- raise ValidationError({
- 'details': ValidationError(
- 'Details needs to be a valid JSON object', code='invalid')
- })
-
- def isSuperAdmin(self):
- """
- Returns if this user is a SuperAdmin.
- """
- return self.user.superadmin_set.count() > 0
-
- def isAdminFor(self, system):
- """
- Checks if this user can administer a certain voting system.
- """
- return system in self.getAdministratedSystems()
-
- def getAdministratedSystems(self):
- """
- Returns all voting systems this user can administer.
- """
- # if we are a superadmin we can manage all systems
- if self.isSuperAdmin():
- return VotingSystem.objects.all()
-
- # else return only the systems we are an admin for.
- else:
- return list(
- map(lambda x: x.system, Admin.objects.filter(user=self.user)))
-
- def isElevated(self):
- """
- Checks if this user is an elevated user.
-
- (i. e. if they are a superadmin or admin for some voting system)
- """
-
- # thy are a superadmin
- if self.isSuperAdmin():
- return True
-
- # they administer some voting system
- return self.user.admin_set.count() > 0
-
- def getSystems(self):
- """
- Gets the editable filters for this user.
- """
-
- # get all the voting systems for this user
- admin_systems = self.getAdministratedSystems()
-
- # and all the other ones also
- other_systems = list(filter(lambda a: a not in admin_systems,
- VotingSystem.objects.all()))
-
- return (admin_systems, other_systems)
-
-
admin.site.register(Admin)
-admin.site.register(SuperAdmin)
-admin.site.register(UserProfile)
diff --git a/users/ojub_auth.py b/users/ojub_auth.py
index af7a211..c126e69 100644
--- a/users/ojub_auth.py
+++ b/users/ojub_auth.py
@@ -1,113 +1,37 @@
from django.conf import settings
-from django.contrib.auth.models import User
-from users.models import UserProfile
+from requests_oauthlib import OAuth2Session
+from oauthlib.oauth2 import BackendApplicationClient
-import requests
+OPENJUB_BASE = "http://localhost:9000/"
-OPENJUB_BASE = "https://api.jacobs.university/"
+def get_all():
+ client = BackendApplicationClient(client_id=settings.DREAMJUB_CLIENT_ID)
+ dreamjub = OAuth2Session(client=client)
+ dreamjub.fetch_token(
+ token_url=settings.DREAMJUB_CLIENT_URL + 'login/o/token/',
+ client_id=settings.DREAMJUB_CLIENT_ID,
+ client_secret=settings.DREAMJUB_CLIENT_SECRET)
-class OjubBackend(object):
- """
- Authenticates credentials against the OpenJUB database.
+ # iterate over the pages (while there is a next)
+ results = []
+ next = settings.DREAMJUB_CLIENT_URL + 'api/v1/users/'
- The URL for the server is configured by OPENJUB_BASE in the settings.
+ while next:
+ res = dreamjub.get(next)
+ if not res.ok:
+ raise Exception(
+ 'Unable to retrieve current list of students, '
+ 'please try again later. ')
- This class does not fill in user profiles, this has to be handled
- in other places
- """
+ res = res.json()
+ results += res['results']
+ next = res['next'] if 'next' in res else None
- def authenticate(self, username=None, password=None):
- r = requests.post(OPENJUB_BASE + "auth/signin",
- data={'username': username, 'password': password})
+ # replace http with https at most one
+ if next is not None and next.startswith('http://') \
+ and settings.DREAMJUB_CLIENT_URL.startswith('https://'):
+ next = next.replace('http://', 'https://', 1)
- if r.status_code != requests.codes.ok:
- return None
-
- resp = r.json()
-
- uname = resp['user']
- token = resp['token']
-
- details = requests.get(OPENJUB_BASE + "user/me",
- params={'token': token})
-
- if details.status_code != requests.codes.ok:
- print("Could not get user details")
- return None
-
- try:
- user = User.objects.get(username=uname)
- except User.DoesNotExist:
- user = User(username=uname)
-
- user.set_unusable_password()
-
- # TODO Don't hardcode this
- if user.username in ["lkuboschek", "twiesing", "jinzhang",
- "rdeliallis"]:
- user.is_staff = True
- user.is_superuser = True
-
- data = details.json()
-
- user.first_name = data['firstName']
- user.last_name = data['lastName']
- user.email = data['email']
-
- user.save()
-
- # Make a user profile if there isn't one already
- try:
- profile = UserProfile.objects.get(user=user)
- except UserProfile.DoesNotExist:
- profile = UserProfile(user=user)
-
- profile.details = details.text
- profile.save()
-
- return user
-
- def get_user(self, user_id):
- try:
- return User.objects.get(pk=user_id)
- except User.DoesNotExist:
- return None
-
-
-def get_all(username, password):
- r = requests.post(OPENJUB_BASE + "auth/signin",
- data={'username': username, 'password': password})
-
- if r.status_code != requests.codes.ok:
- return None
-
- resp = r.json()
-
- uname = resp['user']
- token = resp['token']
-
- users = []
-
- TIMEOUT = 60
-
- request = requests.get(OPENJUB_BASE + "query",
- params={'token': token, 'limit': 20000},
- timeout=TIMEOUT)
-
- while True:
- if request.status_code != requests.codes.ok:
- return None
- else:
- # read json
- resjson = request.json()
-
- # load all the users
- users += resjson["data"]
-
- # if there was no data or no next field, continue
- if len(resjson["data"]) == 0 or not resjson["next"]:
- return users
- else:
- request = requests.get(resjson["next"], timeout=TIMEOUT)
+ return results
diff --git a/votes/models.py b/votes/models.py
index 07c5af9..c4a2af1 100644
--- a/votes/models.py
+++ b/votes/models.py
@@ -1,5 +1,3 @@
-import datetime
-
from django.utils import timezone
from django.db import models, transaction
@@ -44,18 +42,16 @@ def clean(self):
is_restricted_word('machine_name', self.machine_name)
def canEdit(self, user):
- """
- Checks if a user can edit this vote.
- """
- return user.isAdminFor(
- self.system) and self.status.stage != Status.PUBLIC
+ """ Checks if a user can edit this vote. """
+
+ return self.system.isAdmin(user) \
+ and self.status.stage != Status.PUBLIC
def canDelete(self, user):
- """
- Check if a user can delete this vote.
- """
- return user.isAdminFor(
- self.system) and self.status.stage == Status.INIT
+ """ Checks if a user can delete this vote. """
+
+ return self.system.isAdmin(user) \
+ and self.status.stage == Status.INIT
def canBeModified(self):
"""
@@ -63,27 +59,24 @@ def canBeModified(self):
"""
return self.status.stage == Status.INIT
- def update_eligibility(self, username, password):
+ def update_eligibility(self):
+
+ # TODO: Retrieve the API key things
PassiveVote.objects.get_or_create(vote=self, defaults={
'num_voters': 0,
'num_eligible': 0})
- if self.filter is not None:
+ if self.filter is None:
raise Exception("Missing filter. ")
# this will take really long
- everyone = get_all(username, password)
+ everyone = get_all()
if not everyone:
raise Exception("Invalid password or something went wrong. ")
- check = self.filter.map_matches(everyone)
- c = 0
-
- for b in check:
- if b:
- c += 1
+ c = self.filter.count_matches(everyone)
# get or create the passive vote object
(pv, _) = PassiveVote.objects.get_or_create(vote=self, defaults={
diff --git a/votes/views.py b/votes/views.py
index fb8971e..9503357 100644
--- a/votes/views.py
+++ b/votes/views.py
@@ -26,9 +26,10 @@
from django.contrib.auth.models import User
+from jay import utils
from votes.forms import EditVoteForm, EditVoteFilterForm, \
- EditVoteOptionsForm, GetVoteOptionForm, EditVoteOptionForm, PasswordForm, \
- EditScheduleForm, AdminSelectForm
+ EditVoteOptionsForm, GetVoteOptionForm, EditVoteOptionForm, \
+ PasswordForm, EditScheduleForm, AdminSelectForm
VOTE_ERROR_TEMPLATE = "vote/vote_msg.html"
VOTE_RESULT_TEMPLATE = "vote/vote_result.html"
@@ -52,7 +53,7 @@ def system_home(request, system_name):
all_votes = Vote.objects.filter(system=vs)
- if request.user.is_authenticated() and vs.isAdmin(request.user.profile):
+ if request.user.is_authenticated() and vs.isAdmin(request.user):
ctx['votes'] = all_votes
ctx['results'] = Vote.objects.filter(system=vs,
status__stage__in=[Status.PUBLIC,
@@ -81,7 +82,7 @@ def admin(request, system_name, alert_type=None, alert_head=None,
vs = get_object_or_404(VotingSystem, machine_name=system_name)
# raise an error if the user trying to access is not an admin
- if not vs.isAdmin(request.user.profile):
+ if not vs.isAdmin(request.user):
raise PermissionDenied
ctx['vs'] = vs
@@ -112,7 +113,7 @@ def admin_add(request, system_name):
vs = get_object_or_404(VotingSystem, machine_name=system_name)
# raise an error if the user trying to access is not an admin
- if not vs.isAdmin(request.user.profile):
+ if not vs.isAdmin(request.user):
raise PermissionDenied
try:
@@ -151,7 +152,7 @@ def admin_remove(request, system_name):
vs = get_object_or_404(VotingSystem, machine_name=system_name)
# raise an error if the user trying to access is not an admin
- if not vs.isAdmin(request.user.profile):
+ if not request.user.isAdmin(request.user):
raise PermissionDenied
try:
@@ -228,6 +229,7 @@ def get_vote_props(ctx, vote):
def vote_edit_context(request, system_name, vote_name):
+ from jay import utils
"""
Returns context and basic parameters for vote editing.
"""
@@ -237,14 +239,14 @@ def vote_edit_context(request, system_name, vote_name):
vote.touch()
# raise an error if the user trying to access is not an admin
- if not system.isAdmin(request.user.profile):
+ if not system.isAdmin(request.user):
raise PermissionDenied
# make a context
ctx = {}
# get all the systems this user can edit
- (admin_systems, other_systems) = request.user.profile.getSystems()
+ (admin_systems, other_systems) = VotingSystem.splitSystemsFor(request.user)
# add the vote to the system
ctx['vote'] = vote
@@ -281,7 +283,7 @@ def vote_add(request, system_name):
vs = get_object_or_404(VotingSystem, machine_name=system_name)
# raise an error if the user trying to access is not an admin
- if not vs.isAdmin(request.user.profile):
+ if not vs.isAdmin(request.user):
raise PermissionDenied
v = Vote()
@@ -311,7 +313,7 @@ def vote_add(request, system_name):
def vote_delete(request, system_name, vote_name):
(system, vote, ctx) = vote_edit_context(request, system_name, vote_name)
- if vote.canDelete(request.user.profile):
+ if vote.canDelete(request.user):
vote.delete()
return redirect('votes:system', system_name=system_name)
@@ -440,18 +442,18 @@ def vote_stage(request, system_name, vote_name):
if not form.is_valid():
raise Exception
- # read username + password
- username = request.user.username
- password = form.cleaned_data['password']
+ # make sure that the name of the vote has been submitted
+ if form.cleaned_data['password'] != vote_name:
+ raise Exception
except:
- ctx['alert_head'] = 'Saving failed'
+ ctx['alert_head'] = 'Staging vote failed'
ctx['alert_text'] = 'Invalid data submitted'
return render(request, VOTE_EDIT_TEMPLATE, ctx)
# set the vote status to public
try:
- vote.update_eligibility(username, password)
+ vote.update_eligibility()
vote.status.stage = Status.STAGED
vote.status.save()
@@ -499,7 +501,6 @@ def vote_time(request, system_name, vote_name):
public_time = form.cleaned_data["public_time"]
except Exception as e:
- print(e, form.errors)
ctx['alert_head'] = 'Saving failed'
ctx['alert_text'] = 'Invalid data submitted'
return render(request, VOTE_EDIT_TEMPLATE, ctx)
@@ -547,18 +548,18 @@ def vote_update(request, system_name, vote_name):
if not form.is_valid():
raise Exception
- # read username + password
- username = request.user.username
- password = form.cleaned_data['password']
+ # make sure that the name of the vote has been submitted
+ if form.cleaned_data['password'] != vote_name:
+ raise Exception
except:
ctx['alert_head'] = 'Saving failed'
ctx['alert_text'] = 'Invalid data submitted'
return render(request, VOTE_EDIT_TEMPLATE, ctx)
- # set the vote status to public
+ # re-count if eligible
try:
- vote.update_eligibility(username, password)
+ vote.update_eligibility()
except Exception as e:
ctx['alert_head'] = 'Updating eligibility failed. '
ctx['alert_text'] = str(e)
@@ -1013,7 +1014,7 @@ def results(request, system_name, vote_name):
if vote.status.stage != Status.PUBLIC:
if vote.status.stage == Status.CLOSE and \
request.user.is_authenticated():
- if vote.system.isAdmin(request.user.profile):
+ if vote.system.isAdmin(request.user):
ctx['alert_type'] = 'info'
ctx['alert_head'] = 'Non-public'
ctx['alert_text'] = 'The results are not public yet. You ' \
@@ -1060,7 +1061,7 @@ def get(self, request, system_name, vote_name):
# TODO Check status of vote
try:
- user_details = json.loads(request.user.profile.details)
+ user_details = utils.get_user_details(request.user)
if not filter:
ctx['alert_head'] = "No filter given."
@@ -1157,7 +1158,7 @@ def post(self, request, system_name, vote_name):
return self.render_error_response(ctx)
try:
- user_details = json.loads(request.user.profile.details)
+ user_details = utils.get_user_details(request.user)
if not filter:
ctx['alert_head'] = "No filter given."