diff --git a/core/views.py b/core/views.py index ebfcf6a..83625dc 100644 --- a/core/views.py +++ b/core/views.py @@ -7,6 +7,7 @@ from filters.models import UserFilter from users.models import UserProfile + # Create your views here. def home(request): ctx = {} @@ -15,8 +16,14 @@ def home(request): systems = VotingSystem.objects.all() if request.user.is_authenticated(): - details = json.loads(request.user.profile.details) - votes_shown = [v for v in votes if v.filter.matches(details)] + try: + details = request.user.socialaccount_set.get( + provider='dreamjub').extra_data + except request.user.DoesNotExist: + details = {} + + votes_shown = [v for v in votes if v.filter.matches(json.loads( + details))] ctx["vote_list_title"] = "Your votes" diff --git a/filters/models.py b/filters/models.py index a5931a9..5cd9ed1 100644 --- a/filters/models.py +++ b/filters/models.py @@ -9,56 +9,56 @@ from settings.models import VotingSystem import filters.forest as forest +from jay import utils # Create your models here. class UserFilter(models.Model): - system = models.ForeignKey(VotingSystem) - name = models.CharField(max_length=255) - value = models.CharField(max_length=255) - tree = models.TextField(blank=True) - - def __str__(self): - return u'%s: %s' % (self.system.machine_name, self.name) - - def clean(self): - try: - self.tree = json.dumps(forest.parse_and_simplify(self.value)) - except Exception as e: - self.tree = None - - if self.tree == None: - raise ValidationError({ - 'value': ValidationError('Value for \'value\' invalid: Can not parse into a valid logical tree. ', code='invalid') - }) - - def matches(self, obj): - """ - Checks if this filter matches an object. - """ - - try: - return forest.matches(json.loads(self.tree), obj) - except Exception as e: - import sys - sys.stderr.write(e) - return False - - def map_matches(self, objs): - - try: - return forest.map_match(json.loads(self.tree), objs) - except Exception as e: - return False - - def canEdit(self, user): - """ - Checks if a user can edit this UserFilter. - """ - - return self.system.isAdmin(user) - - def get_absolute_url(self): - from django.core.urlresolvers import reverse - return reverse('filters:edit', kwargs={'filter_id':self.id}) + system = models.ForeignKey(VotingSystem) + name = models.CharField(max_length=255) + value = models.CharField(max_length=255) + tree = models.TextField(blank=True) + + def __str__(self): + return u'%s: %s' % (self.system.machine_name, self.name) + + def clean(self): + try: + self.tree = json.dumps(forest.parse_and_simplify(self.value)) + except Exception as e: + self.tree = None + + if self.tree == None: + raise ValidationError({ + 'value': ValidationError('Value for \'value\' invalid: Can not parse into a valid logical tree. ', code='invalid') + }) + + def matches(self, obj): + """ + Checks if this filter matches an object. + """ + + try: + return forest.matches(json.loads(self.tree), obj) + except Exception as e: + import sys + sys.stderr.write(e) + return False + + def map_matches(self, objs): + + try: + return forest.map_match(json.loads(self.tree), objs) + except Exception as e: + return False + + def canEdit(self, user): + """ + Checks if a user can edit this UserFilter. + """ + return utils.is_admin_for(user, self.system) + + def get_absolute_url(self): + from django.core.urlresolvers import reverse + return reverse('filters:edit', kwargs={'filter_id':self.id}) admin.site.register(UserFilter) diff --git a/filters/views.py b/filters/views.py index 9671185..ce22070 100644 --- a/filters/views.py +++ b/filters/views.py @@ -12,12 +12,12 @@ from filters.forms import NewFilterForm, EditFilterForm, FilterTestForm, FilterTestUserForm import filters.forest as forest -import json - from votes.models import VotingSystem -from jay.utils import priviliged +from jay.utils import priviliged, is_elevated, get_all_systems, is_admin_for, get_user_details + +import json FILTER_FOREST_TEMPLATE = "filters/filter_forest.html" FILTER_EDIT_TEMPLATE = "filters/filter_edit.html" @@ -28,7 +28,7 @@ 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 +40,7 @@ def Forest(request, alert_type=None, alert_head=None, alert_text=None): bc.append({'url':reverse('filters:forest'), 'text':'Filters', 'active':True}) ctx['breadcrumbs'] = bc - (admin_systems, other_systems) = request.user.profile.getSystems() + (admin_systems, other_systems) = get_all_systems(request.user) # give those to the view ctx['admin_systems'] = admin_systems @@ -77,7 +77,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 is_admin_for(request.user, system): return Forest(request, alert_head="Creation failed", alert_text="Nice try. You are not allowed to edit this VotingSystem. ") # create a new filter @@ -136,7 +136,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 @@ -244,7 +244,7 @@ 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 60aacbe..aa4bb87 100644 --- a/jay/settings.py +++ b/jay/settings.py @@ -26,7 +26,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', @@ -66,8 +74,10 @@ 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', +) # Default after login redirect # These are named URL routes @@ -93,3 +103,6 @@ ) STATIC_URL = '/static/' +SITE_ID = 1 + +ACCOUNT_EMAIL_VERIFICATION = "none" \ No newline at end of file diff --git a/jay/urls.py b/jay/urls.py index 37c9f9a..058ecd2 100644 --- a/jay/urls.py +++ b/jay/urls.py @@ -42,7 +42,7 @@ url(r'^help/filters/$', TemplateView.as_view(template_name="filters/filter_help.html"), 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"), # Sub-projects diff --git a/jay/utils.py b/jay/utils.py index 68c59d0..59c3d81 100644 --- a/jay/utils.py +++ b/jay/utils.py @@ -1,34 +1,94 @@ from django.core.exceptions import PermissionDenied + def memoize(f): memo = {} + def helper(*x): key = str(x) if key not in memo: memo[key] = f(*x) return memo[key] + return helper + def superadmin(handler): """ - Checks if a user is a super admin. + Checks if a user is a super admin. """ - + def helper(request, *args, **kwargs): - if not request.user.profile.isSuperAdmin(): + if not request.user.is_superuser: raise PermissionDenied return handler(request, *args, **kwargs) - + return helper + +def is_elevated(user): + if not user.is_superuser: + if not user.admin_set.count() > 0: + return False + return True + + def priviliged(handler): """ - Checks that a user has elevated priviliges. + Checks that a user has elevated priviliges. """ + 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 \ No newline at end of file + + return helper + + +def get_user_details(user): + import json + + try: + data = user.socialaccount_set.get(provider="dreamjub").extra_data + return data + except: + return {} + + +def is_admin_for(user, system): + """ + Checks if this user can administer a certain voting system. + """ + return system in get_administrated_systems(user) + + +def get_administrated_systems(user): + from settings.models import VotingSystem, Admin + """ + Returns all voting systems this user can administer. + """ + # if we are a superadmin we can manage all systems + if user.is_superuser: + 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=user))) + + +def get_all_systems(user): + from settings.models import VotingSystem + """ + Gets the editable filters for this user. + """ + + # get all the voting systems for this user + admin_systems = get_administrated_systems(user) + + # and all the other ones also + other_systems = list(filter(lambda a: not a in admin_systems, VotingSystem.objects.all())) + + return admin_systems, other_systems diff --git a/requirements.txt b/requirements.txt index 2ea77cd..55ff99b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,5 +10,9 @@ Markdown==2.6.5 # For filters PyExecJS==1.1.0 -# For OpenJUB auth backend -requests==2.6.0 +# For reaching out to OpenJUB +requests==2.12.3 + +# For authing against dreamjub +django-allauth==0.29.0 +django-allauth-dreamjub==0.1.3 diff --git a/settings/models.py b/settings/models.py index 473565b..c17947c 100644 --- a/settings/models.py +++ b/settings/models.py @@ -3,28 +3,29 @@ from django.contrib import admin from jay.restricted import is_restricted_word +from users.models import Admin class VotingSystem(models.Model): - machine_name = models.SlugField(max_length = 50, unique = True) - simple_name = models.CharField(max_length = 80) - - def __str__(self): - return u'[%s] %s' % (self.machine_name, self.simple_name) - - 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() - - def isAdmin(self, user): - """ - Checks if a user is an administrator for this voting system. - """ - return user.isAdminFor(self) + machine_name = models.SlugField(max_length = 50, unique = True) + simple_name = models.CharField(max_length = 80) + + def __str__(self): + return u'[%s] %s' % (self.machine_name, self.simple_name) + + 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() + + def isAdmin(self, user): + """ + Checks if a user is an administrator for this voting system. + """ + return Admin.objects.filter(system=self, user=user).exists() admin.site.register(VotingSystem) diff --git a/settings/urls.py b/settings/urls.py index 8259cc4..c6ced47 100644 --- a/settings/urls.py +++ b/settings/urls.py @@ -1,14 +1,14 @@ 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/templates/base/base.html b/templates/base/base.html index 74bf1a4..c7778cd 100644 --- a/templates/base/base.html +++ b/templates/base/base.html @@ -43,11 +43,11 @@ {{ user.username }} {% else %} - Login + Login {% endif %} 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/users/models.py b/users/models.py index 2497790..1a989aa 100644 --- a/users/models.py +++ b/users/models.py @@ -5,95 +5,42 @@ 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) - - class Meta(): - unique_together = (("system", "user")) - - def __str__(self): - return u'[%s] %s' % (self.system.machine_name, self.user) + user = models.ForeignKey(User) + system = models.ForeignKey("settings.VotingSystem") + class Meta(): + unique_together = (("system", "user")) + 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: not a in admin_systems, VotingSystem.objects.all())) - - return (admin_systems, other_systems) + 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.is_superuser 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 15fcf61..9dd21bd 100644 --- a/users/ojub_auth.py +++ b/users/ojub_auth.py @@ -1,77 +1,7 @@ -from django.conf import settings -from django.contrib.auth.models import User - -from users.models import UserProfile - import requests OPENJUB_BASE = "https://api.jacobs.university/" -class OjubBackend(object): - """ - Authenticates credentials against the OpenJUB database. - - The URL for the server is configured by OPENJUB_BASE in the settings. - - This class does not fill in user profiles, this has to be handled - in other places - """ - def authenticate(self, username=None, password=None): - 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'] - - 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}) diff --git a/votes/models.py b/votes/models.py index d507534..06fcb95 100644 --- a/votes/models.py +++ b/votes/models.py @@ -13,313 +13,314 @@ from users.ojub_auth import get_all from jay.restricted import is_restricted_word +from jay import utils # Create your models here. class Vote(models.Model): - system = models.ForeignKey(VotingSystem) + system = models.ForeignKey(VotingSystem) - name = models.CharField(max_length = 64) - machine_name = models.SlugField(max_length = 64) + name = models.CharField(max_length = 64) + machine_name = models.SlugField(max_length = 64) - auto_open_options = models.BooleanField(default = False) + auto_open_options = models.BooleanField(default = False) - filter = models.ForeignKey(UserFilter, null = True) - status = models.OneToOneField('Status') + filter = models.ForeignKey(UserFilter, null = True) + status = models.OneToOneField('Status') - description = models.TextField(blank = True) + description = models.TextField(blank = True) - creator = models.ForeignKey(User) + creator = models.ForeignKey(User) - min_votes = models.IntegerField() - max_votes = models.IntegerField() + min_votes = models.IntegerField() + max_votes = models.IntegerField() - class Meta(): - unique_together = (("system", "machine_name")) + class Meta(): + unique_together = (("system", "machine_name")) - def __str__(self): - return u'[%s] %s' % (self.machine_name, self.name) + def __str__(self): + return u'[%s] %s' % (self.machine_name, self.name) - def clean(self): - is_restricted_word('machine_name', self.machine_name) + 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 + def canEdit(self, user): + """ + Checks if a user can edit this vote. + """ + return utils.is_admin_for(user, self.system) 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 + def canDelete(self, user): + """ + Check if a user can delete this vote. + """ + return utils.is_admin_for(user, self.system) and self.status.stage == Status.INIT - def canBeModified(self): - """ - Checks if this vote can still be modified. - """ - return self.status.stage == Status.INIT + def canBeModified(self): + """ + Checks if this vote can still be modified. + """ + return self.status.stage == Status.INIT - def update_eligibility(self, username, password): + def update_eligibility(self, username, password): - PassiveVote.objects.get_or_create(vote=self, defaults={'num_voters': 0, 'num_eligible': 0}) + PassiveVote.objects.get_or_create(vote=self, defaults={'num_voters': 0, 'num_eligible': 0}) - if self.filter == None: - raise Exception("Missing filter. ") + if self.filter == None: + raise Exception("Missing filter. ") - # this will take really long - everyone = get_all(username, password) + # this will take really long + everyone = get_all(username, password) - if not everyone: - raise Exception("Invalid password or something went wrong. ") + if not everyone: + raise Exception("Invalid password or something went wrong. ") - check = self.filter.map_matches(everyone) - c = 0 + check = self.filter.map_matches(everyone) + c = 0 - for b in check: - if b: - c += 1 + for b in check: + if b: + c += 1 - # get or create the passive vote object - (pv, _) = PassiveVote.objects.get_or_create(vote=self, defaults={'num_voters': 0, 'num_eligible': 0}) + # get or create the passive vote object + (pv, _) = PassiveVote.objects.get_or_create(vote=self, defaults={'num_voters': 0, 'num_eligible': 0}) - # update the eligibility number - pv.num_eligible = c + # update the eligibility number + pv.num_eligible = c - # and save - pv.save() + # and save + pv.save() - # Touch yourself, we lack self-assurance - def touch(self): - status = self.status - stage = self.status.stage - now = timezone.now() + # Touch yourself, we lack self-assurance + def touch(self): + status = self.status + stage = self.status.stage + now = timezone.now() - if stage == Status.INIT: - return + if stage == Status.INIT: + return - if stage == Status.STAGED and status.open_time: - if status.open_time <= now: - self.status.stage = Status.OPEN + if stage == Status.STAGED and status.open_time: + if status.open_time <= now: + self.status.stage = Status.OPEN - if stage == Status.OPEN and status.close_time: - if status.close_time <= now: - self.status.stage = Status.CLOSE - self.close() + if stage == Status.OPEN and status.close_time: + if status.close_time <= now: + self.status.stage = Status.CLOSE + self.close() - if stage == Status.CLOSE and status.public_time: - if status.public_time <= now: - self.status.stage = Status.PUBLIC + if stage == Status.CLOSE and status.public_time: + if status.public_time <= now: + self.status.stage = Status.PUBLIC - self.status.save() + self.status.save() - """ + """ - Converts the ActiveVotes on this vote to a count on the PassiveVote of this Vote + Converts the ActiveVotes on this vote to a count on the PassiveVote of this Vote - """ - def close(self): - try: - pasv = self.passivevote - voters = self.activevote_set + """ + def close(self): + try: + pasv = self.passivevote + voters = self.activevote_set - pasv.num_voters = voters.count() - pasv.save() + pasv.num_voters = voters.count() + pasv.save() - voters.delete() + voters.delete() - except PassiveVote.DoesNotExist: - pass + except PassiveVote.DoesNotExist: + pass - @transaction.atomic - def renumberOptions(self): - """ - Renumbers the options in this vote. - """ + @transaction.atomic + def renumberOptions(self): + """ + Renumbers the options in this vote. + """ - # give all of them a sequential number. - for i, v in enumerate(self.option_set.order_by("number")): - v.number = i - v.save() + # give all of them a sequential number. + for i, v in enumerate(self.option_set.order_by("number")): + v.number = i + v.save() - @transaction.atomic - def deleteOption(self, option): - """ - Removes an option from this vote. - """ + @transaction.atomic + def deleteOption(self, option): + """ + Removes an option from this vote. + """ - # if the option is not in our options, something weird happened. - if not option.id in self.option_set.values_list('id', flat=True): - raise ValueError + # if the option is not in our options, something weird happened. + if not option.id in self.option_set.values_list('id', flat=True): + raise ValueError - # remove the option - option.delete() + # remove the option + option.delete() - # get the count - count = self.option_set.count() + # get the count + count = self.option_set.count() - # adn check if min_votes or max_votes are too big. - # then update accordingly. - if self.min_votes > count: - self.min_votes = count + # adn check if min_votes or max_votes are too big. + # then update accordingly. + if self.min_votes > count: + self.min_votes = count - if self.max_votes > count: - self.max_votes = count + if self.max_votes > count: + self.max_votes = count - # and save of course - self.save() + # and save of course + self.save() - # and renumber - self.renumberOptions() + # and renumber + self.renumberOptions() - @transaction.atomic - def addOption(self): - """ - Adds a new option. - """ + @transaction.atomic + def addOption(self): + """ + Adds a new option. + """ - # renumber the options to make sure we are in order - self.renumberOptions() + # renumber the options to make sure we are in order + self.renumberOptions() - # find a number for the new option - num = self.option_set.count() + # find a number for the new option + num = self.option_set.count() - # create a new option - opt = Option(vote=self, number = num, name = "Option #"+str(num + 1)) + # create a new option + opt = Option(vote=self, number = num, name = "Option #"+str(num + 1)) - # and save it - opt.save() + # and save it + opt.save() - @transaction.atomic - def moveDownOption(self, option): - """ - move an option down in the indexing. - """ + @transaction.atomic + def moveDownOption(self, option): + """ + move an option down in the indexing. + """ - # if the option is not in our options, something weird happened. - if not option.id in self.option_set.values_list('id', flat=True): - raise ValueError + # if the option is not in our options, something weird happened. + if not option.id in self.option_set.values_list('id', flat=True): + raise ValueError - # renumber options to make sure we are in a valid order - self.renumberOptions() + # renumber options to make sure we are in a valid order + self.renumberOptions() - # if we are already at the bottom there is nothing to do. - if option.number == 0: - return + # if we are already at the bottom there is nothing to do. + if option.number == 0: + return - # find the option right below our option - below = self.option_set.filter(number=option.number - 1)[0] + # find the option right below our option + below = self.option_set.filter(number=option.number - 1)[0] - # switch our two number - below.number = option.number - option.number = option.number - 1 + # switch our two number + below.number = option.number + option.number = option.number - 1 - # and save the options - below.save() - option.save() + # and save the options + below.save() + option.save() - @transaction.atomic - def moveUpOption(self, option): - """ - move an option up in the indexing. - """ + @transaction.atomic + def moveUpOption(self, option): + """ + move an option up in the indexing. + """ - # if the option is not in our options, something weird happened. - if not option.id in self.option_set.values_list('id', flat=True): - raise ValueError + # if the option is not in our options, something weird happened. + if not option.id in self.option_set.values_list('id', flat=True): + raise ValueError - # renumber options to make sure we are in a valid order - self.renumberOptions() + # renumber options to make sure we are in a valid order + self.renumberOptions() - # if we are already at the top there is nothing to do. - if option.number == self.option_set.count() - 1: - return + # if we are already at the top there is nothing to do. + if option.number == self.option_set.count() - 1: + return - # find the option right above our option - above = self.option_set.filter(number=option.number + 1)[0] + # find the option right above our option + above = self.option_set.filter(number=option.number + 1)[0] - # switch our two number - above.number = option.number - option.number = option.number + 1 + # switch our two number + above.number = option.number + option.number = option.number + 1 - # and save the options - above.save() - option.save() + # and save the options + above.save() + option.save() class Option(models.Model): - vote = models.ForeignKey(Vote) + vote = models.ForeignKey(Vote) - number = models.IntegerField() + number = models.IntegerField() - name = models.CharField(max_length = 64) - description = models.TextField(blank = True) + name = models.CharField(max_length = 64) + description = models.TextField(blank = True) - picture_url = models.URLField(blank = True) + picture_url = models.URLField(blank = True) - personal_link = models.URLField(blank = True) - link_name = models.CharField(blank = True, max_length = 16) + personal_link = models.URLField(blank = True) + link_name = models.CharField(blank = True, max_length = 16) - count = models.IntegerField(default = 0, blank = True) + count = models.IntegerField(default = 0, blank = True) - class Meta(): - unique_together = (("vote", "number")) + class Meta(): + unique_together = (("vote", "number")) - def __str__(self): - return u'[%s] %s' % (self.number, self.name) + def __str__(self): + return u'[%s] %s' % (self.number, self.name) - def canEdit(self, user): - """ - Checks if a user can edit this option. - """ - return self.vote.canEdit(user) + def canEdit(self, user): + """ + Checks if a user can edit this option. + """ + return self.vote.canEdit(user) class Status(models.Model): - INIT = 'I' - STAGED = 'S' - OPEN = 'O' - CLOSE = 'C' - PUBLIC = 'P' - - STAGES = ( - (INIT, 'Init'), - (STAGED, 'Staged'), - (OPEN, 'Open'), - (CLOSE, 'Close'), - (PUBLIC, 'Results public') - ) - - open_time = models.DateTimeField(blank = True, null = True) - close_time = models.DateTimeField(blank = True, null = True) - public_time = models.DateTimeField(blank = True, null = True) - stage = models.CharField(max_length = 1, choices = STAGES, default = INIT) - - def __str__(self): - return self.stage + INIT = 'I' + STAGED = 'S' + OPEN = 'O' + CLOSE = 'C' + PUBLIC = 'P' + + STAGES = ( + (INIT, 'Init'), + (STAGED, 'Staged'), + (OPEN, 'Open'), + (CLOSE, 'Close'), + (PUBLIC, 'Results public') + ) + + open_time = models.DateTimeField(blank = True, null = True) + close_time = models.DateTimeField(blank = True, null = True) + public_time = models.DateTimeField(blank = True, null = True) + stage = models.CharField(max_length = 1, choices = STAGES, default = INIT) + + def __str__(self): + return self.stage class ActiveVote(models.Model): - vote = models.ForeignKey(Vote) + vote = models.ForeignKey(Vote) - user = models.ForeignKey(User) + user = models.ForeignKey(User) - def __str__(self): - return u'%s voted for %s' % (self.user, self.vote) + def __str__(self): + return u'%s voted for %s' % (self.user, self.vote) class PassiveVote(models.Model): - vote = models.OneToOneField(Vote) + vote = models.OneToOneField(Vote) - num_voters = models.IntegerField() - num_eligible = models.IntegerField() + num_voters = models.IntegerField() + num_eligible = models.IntegerField() - def __str__(self): - return u'%s of %s voted' % (self.num_voters, self.num_eligible) + def __str__(self): + return u'%s of %s voted' % (self.num_voters, self.num_eligible) admin.site.register(Vote) admin.site.register(Option) diff --git a/votes/views.py b/votes/views.py index 695febe..b4dd289 100644 --- a/votes/views.py +++ b/votes/views.py @@ -49,7 +49,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, Status.CLOSE]) @@ -203,7 +203,9 @@ def get_vote_props(ctx, vote): return ctx + def vote_edit_context(request, system_name, vote_name): + from jay import utils """ Returns context and basic parameters for vote editing. """ @@ -213,14 +215,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) = utils.get_all_systems(request.user) # add the vote to the system ctx['vote'] = vote @@ -256,7 +258,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()