Removed possibility to block candidates. Fixes #1708.
This commit is contained in:
parent
193d318bc9
commit
2e104d07b7
@ -15,6 +15,7 @@ Agenda:
|
|||||||
- Removed mptt.
|
- Removed mptt.
|
||||||
Assignments:
|
Assignments:
|
||||||
- Renamed app from assignment to assignments.
|
- Renamed app from assignment to assignments.
|
||||||
|
- Removed possibility to block candidates.
|
||||||
- Massive refactoring and cleanup of the app.
|
- Massive refactoring and cleanup of the app.
|
||||||
Motions:
|
Motions:
|
||||||
- Renamed app from motion to motions.
|
- Renamed app from motion to motions.
|
||||||
|
23
openslides/assignments/migrations/0005_auto_20160109_1624.py
Normal file
23
openslides/assignments/migrations/0005_auto_20160109_1624.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assignments', '0004_auto_20160109_1329'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='assignmentrelateduser',
|
||||||
|
name='status',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignmentrelateduser',
|
||||||
|
name='elected',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
@ -24,15 +24,6 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
|
|||||||
"""
|
"""
|
||||||
Many to Many table between an assignment and user.
|
Many to Many table between an assignment and user.
|
||||||
"""
|
"""
|
||||||
STATUS_CANDIDATE = 1
|
|
||||||
STATUS_ELECTED = 2
|
|
||||||
STATUS_BLOCKED = 3
|
|
||||||
STATUSES = (
|
|
||||||
(STATUS_CANDIDATE, ugettext_lazy('candidate')),
|
|
||||||
(STATUS_ELECTED, ugettext_lazy('elected')),
|
|
||||||
(STATUS_BLOCKED, ugettext_lazy('blocked')),
|
|
||||||
)
|
|
||||||
|
|
||||||
assignment = models.ForeignKey(
|
assignment = models.ForeignKey(
|
||||||
'Assignment',
|
'Assignment',
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
@ -40,9 +31,7 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
|
|||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
status = models.IntegerField(
|
elected = models.BooleanField(default=False)
|
||||||
choices=STATUSES,
|
|
||||||
default=STATUS_CANDIDATE)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
default_permissions = ()
|
default_permissions = ()
|
||||||
@ -106,9 +95,9 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
through='AssignmentRelatedUser')
|
through='AssignmentRelatedUser')
|
||||||
"""
|
"""
|
||||||
Users that are candidates, elected or blocked as candidate.
|
Users that are candidates or elected.
|
||||||
|
|
||||||
See AssignmentRelatedUser for more infos.
|
See AssignmentRelatedUser for more information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tags = models.ManyToManyField(Tag, blank=True)
|
tags = models.ManyToManyField(Tag, blank=True)
|
||||||
@ -145,7 +134,7 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
Queryset that represents the candidates for the assignment.
|
Queryset that represents the candidates for the assignment.
|
||||||
"""
|
"""
|
||||||
return self.related_users.filter(
|
return self.related_users.filter(
|
||||||
assignmentrelateduser__status=AssignmentRelatedUser.STATUS_CANDIDATE)
|
assignmentrelateduser__elected=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def elected(self):
|
def elected(self):
|
||||||
@ -153,15 +142,7 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
Queryset that represents all elected users for the assignment.
|
Queryset that represents all elected users for the assignment.
|
||||||
"""
|
"""
|
||||||
return self.related_users.filter(
|
return self.related_users.filter(
|
||||||
assignmentrelateduser__status=AssignmentRelatedUser.STATUS_ELECTED)
|
assignmentrelateduser__elected=True)
|
||||||
|
|
||||||
@property
|
|
||||||
def blocked(self):
|
|
||||||
"""
|
|
||||||
Queryset that represents all blocked users for the assignment.
|
|
||||||
"""
|
|
||||||
return self.related_users.filter(
|
|
||||||
assignmentrelateduser__status=AssignmentRelatedUser.STATUS_BLOCKED)
|
|
||||||
|
|
||||||
def is_candidate(self, user):
|
def is_candidate(self, user):
|
||||||
"""
|
"""
|
||||||
@ -179,21 +160,13 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
"""
|
"""
|
||||||
return self.elected.filter(pk=user.pk).exists()
|
return self.elected.filter(pk=user.pk).exists()
|
||||||
|
|
||||||
def is_blocked(self, user):
|
|
||||||
"""
|
|
||||||
Returns True if the user is blocked for candidature.
|
|
||||||
|
|
||||||
Costs one database query.
|
|
||||||
"""
|
|
||||||
return self.blocked.filter(pk=user.pk).exists()
|
|
||||||
|
|
||||||
def set_candidate(self, user):
|
def set_candidate(self, user):
|
||||||
"""
|
"""
|
||||||
Adds the user as candidate.
|
Adds the user as candidate.
|
||||||
"""
|
"""
|
||||||
related_user, __ = self.assignment_related_users.update_or_create(
|
related_user, __ = self.assignment_related_users.update_or_create(
|
||||||
user=user,
|
user=user,
|
||||||
defaults={'status': AssignmentRelatedUser.STATUS_CANDIDATE})
|
defaults={'elected': False})
|
||||||
|
|
||||||
def set_elected(self, user):
|
def set_elected(self, user):
|
||||||
"""
|
"""
|
||||||
@ -201,15 +174,7 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
"""
|
"""
|
||||||
related_user, __ = self.assignment_related_users.update_or_create(
|
related_user, __ = self.assignment_related_users.update_or_create(
|
||||||
user=user,
|
user=user,
|
||||||
defaults={'status': AssignmentRelatedUser.STATUS_ELECTED})
|
defaults={'elected': True})
|
||||||
|
|
||||||
def set_blocked(self, user):
|
|
||||||
"""
|
|
||||||
Block user from this assignment, so he can not get an candidate.
|
|
||||||
"""
|
|
||||||
related_user, __ = self.assignment_related_users.update_or_create(
|
|
||||||
user=user,
|
|
||||||
defaults={'status': AssignmentRelatedUser.STATUS_BLOCKED})
|
|
||||||
|
|
||||||
def delete_related_user(self, user):
|
def delete_related_user(self, user):
|
||||||
"""
|
"""
|
||||||
|
@ -29,7 +29,7 @@ class AssignmentRelatedUserSerializer(ModelSerializer):
|
|||||||
fields = (
|
fields = (
|
||||||
'id',
|
'id',
|
||||||
'user',
|
'user',
|
||||||
'status',
|
'elected',
|
||||||
'assignment') # js-data needs the assignment-id in the nested object to define relations.
|
'assignment') # js-data needs the assignment-id in the nested object to define relations.
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
return _('You were nominated successfully.')
|
return _('You were nominated successfully.')
|
||||||
|
|
||||||
def withdraw_self(self, request, assignment):
|
def withdraw_self(self, request, assignment):
|
||||||
# Withdraw candidature and set self blocked.
|
# Withdraw candidature.
|
||||||
if assignment.phase == assignment.PHASE_FINISHED:
|
if assignment.phase == assignment.PHASE_FINISHED:
|
||||||
raise ValidationError({'detail': _('You can not withdraw your candidature to this election because it is finished.')})
|
raise ValidationError({'detail': _('You can not withdraw your candidature to this election because it is finished.')})
|
||||||
if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'):
|
if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'):
|
||||||
@ -115,16 +115,14 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
self.permission_denied(request)
|
self.permission_denied(request)
|
||||||
if not assignment.is_candidate(request.user):
|
if not assignment.is_candidate(request.user):
|
||||||
raise ValidationError({'detail': _('You are not a candidate of this election.')})
|
raise ValidationError({'detail': _('You are not a candidate of this election.')})
|
||||||
assignment.set_blocked(request.user)
|
assignment.delete_related_user(request.user)
|
||||||
return _(
|
return _('You have withdrawn your candidature successfully.')
|
||||||
'You have withdrawn your candidature successfully. '
|
|
||||||
'You can not be nominated by other participants anymore.')
|
|
||||||
|
|
||||||
def get_user_from_request_data(self, request):
|
def get_user_from_request_data(self, request):
|
||||||
"""
|
"""
|
||||||
Helper method to get a specific user from request data (not the
|
Helper method to get a specific user from request data (not the
|
||||||
request.user) so that the views self.candidature_other or
|
request.user) so that the views self.candidature_other or
|
||||||
self.mark_elected can play with him.
|
self.mark_elected can play with it.
|
||||||
"""
|
"""
|
||||||
if not isinstance(request.data, dict):
|
if not isinstance(request.data, dict):
|
||||||
detail = _('Invalid data. Expected dictionary, got %s.') % type(request.data)
|
detail = _('Invalid data. Expected dictionary, got %s.') % type(request.data)
|
||||||
@ -165,8 +163,6 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
# To nominate another user during voting you have to be a manager.
|
# To nominate another user during voting you have to be a manager.
|
||||||
self.permission_denied(request)
|
self.permission_denied(request)
|
||||||
if not request.user.has_perm('assignments.can_manage'):
|
if not request.user.has_perm('assignments.can_manage'):
|
||||||
if assignment.is_blocked(user):
|
|
||||||
raise ValidationError({'detail': _('User %s does not want to be a candidate. Only a manager can do this.') % user})
|
|
||||||
if assignment.is_elected(user):
|
if assignment.is_elected(user):
|
||||||
raise ValidationError({'detail': _('User %s is already elected.') % user})
|
raise ValidationError({'detail': _('User %s is already elected.') % user})
|
||||||
if assignment.is_candidate(user):
|
if assignment.is_candidate(user):
|
||||||
@ -181,10 +177,10 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
if assignment.phase == assignment.PHASE_FINISHED:
|
if assignment.phase == assignment.PHASE_FINISHED:
|
||||||
detail = _('You can not delete someones candidature to this election because it is finished.')
|
detail = _('You can not delete someones candidature to this election because it is finished.')
|
||||||
raise ValidationError({'detail': detail})
|
raise ValidationError({'detail': detail})
|
||||||
if not assignment.is_candidate(user) and not assignment.is_blocked(user):
|
if not assignment.is_candidate(user):
|
||||||
raise ValidationError({'detail': _('User %s has no status in this election.') % user})
|
raise ValidationError({'detail': _('User %s has no status in this election.') % user})
|
||||||
assignment.delete_related_user(user)
|
assignment.delete_related_user(user)
|
||||||
return _('Candidate %s was withdrawn/unblocked successfully.') % user
|
return _('Candidate %s was withdrawn successfully.') % user
|
||||||
|
|
||||||
@detail_route(methods=['post', 'delete'])
|
@detail_route(methods=['post', 'delete'])
|
||||||
def mark_elected(self, request, pk=None):
|
def mark_elected(self, request, pk=None):
|
||||||
|
@ -65,7 +65,6 @@ class CanidatureSelf(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertFalse(Assignment.objects.get(pk=self.assignment.pk).candidates.filter(username='admin').exists())
|
self.assertFalse(Assignment.objects.get(pk=self.assignment.pk).candidates.filter(username='admin').exists())
|
||||||
self.assertTrue(Assignment.objects.get(pk=self.assignment.pk).blocked.filter(username='admin').exists())
|
|
||||||
|
|
||||||
def test_withdraw_self_twice(self):
|
def test_withdraw_self_twice(self):
|
||||||
response = self.client.delete(reverse('assignment-candidature-self', args=[self.assignment.pk]))
|
response = self.client.delete(reverse('assignment-candidature-self', args=[self.assignment.pk]))
|
||||||
@ -90,7 +89,6 @@ class CanidatureSelf(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertFalse(Assignment.objects.get(pk=self.assignment.pk).candidates.exists())
|
self.assertFalse(Assignment.objects.get(pk=self.assignment.pk).candidates.exists())
|
||||||
self.assertTrue(Assignment.objects.get(pk=self.assignment.pk).blocked.filter(username='admin').exists())
|
|
||||||
|
|
||||||
def test_withdraw_self_during_voting_non_admin(self):
|
def test_withdraw_self_during_voting_non_admin(self):
|
||||||
self.assignment.set_candidate(get_user_model().objects.get(username='admin'))
|
self.assignment.set_candidate(get_user_model().objects.get(username='admin'))
|
||||||
|
Loading…
Reference in New Issue
Block a user