diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index dab2dfb85..8fc269e52 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -1,7 +1,7 @@ from datetime import datetime from django.contrib.auth.models import AnonymousUser -from django.contrib.contenttypes import generic +from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse @@ -95,9 +95,8 @@ class Item(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, MPTTModel): """ Field for generic relation to a related object. Id of the object. """ - # TODO: rename it to object_pk - content_object = generic.GenericForeignKey() + content_object = GenericForeignKey() """ Field for generic relation to a related object. General field to the related object. """ diff --git a/openslides/assignment/forms.py b/openslides/assignment/forms.py index 5bd16c14a..97ffcd268 100644 --- a/openslides/assignment/forms.py +++ b/openslides/assignment/forms.py @@ -8,12 +8,12 @@ from .models import Assignment class AssignmentForm(CssClassMixin, forms.ModelForm): - posts = forms.IntegerField( + open_posts = forms.IntegerField( min_value=1, initial=1, label=ugettext_lazy("Number of available posts")) class Meta: model = Assignment - exclude = ('status', 'elected') + fields = ('title', 'description', 'open_posts', 'poll_description_default') class AssignmentRunForm(CssClassMixin, forms.Form): diff --git a/openslides/assignment/main_menu.py b/openslides/assignment/main_menu.py index 2049cfb3c..8e18dc0ef 100644 --- a/openslides/assignment/main_menu.py +++ b/openslides/assignment/main_menu.py @@ -8,7 +8,7 @@ class AssignmentMainMenuEntry(MainMenuEntry): Main menu entry for the assignment app. """ verbose_name = ugettext_lazy('Elections') - required_permission = 'assignment.can_see_assignment' + required_permission = 'assignment.can_see_assignments' default_weight = 40 pattern_name = 'assignment_list' icon_css_class = 'icon-assignment' diff --git a/openslides/assignment/models.py b/openslides/assignment/models.py index b9e038b0d..87465f2fa 100644 --- a/openslides/assignment/models.py +++ b/openslides/assignment/models.py @@ -1,4 +1,4 @@ -from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes.fields import GenericRelation from django.core.urlresolvers import reverse from django.db import models from django.utils.datastructures import SortedDict @@ -15,24 +15,36 @@ from openslides.projector.models import SlideMixin from openslides.utils.exceptions import OpenSlidesError from openslides.utils.models import AbsoluteUrlMixin from openslides.utils.rest_api import RESTModelMixin -from openslides.utils.utils import html_strong from openslides.users.models import User -class AssignmentCandidate(RESTModelMixin, models.Model): +class AssignmentRelatedUser(RESTModelMixin, models.Model): """ - Many2Many table between an assignment and the candidates. + Many to Many table between an assignment and user. """ - assignment = models.ForeignKey("Assignment") - person = models.ForeignKey(User, db_index=True) - elected = models.BooleanField(default=False) - blocked = models.BooleanField(default=False) + 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', + db_index=True, + related_name='assignment_related_users') + user = models.ForeignKey(User, db_index=True) + status = models.IntegerField( + choices=STATUSES, + default=STATUS_CANDIDATE) class Meta: - unique_together = ("assignment", "person") + unique_together = ('assignment', 'user') def __str__(self): - return str(self.person) + return "%s <-> %s" % (self.assignment, self.user) def get_root_rest_element(self): """ @@ -44,35 +56,87 @@ class AssignmentCandidate(RESTModelMixin, models.Model): class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model): slide_callback_name = 'assignment' - STATUS = ( - ('sea', ugettext_lazy('Searching for candidates')), - ('vot', ugettext_lazy('Voting')), - ('fin', ugettext_lazy('Finished')), + PHASE_SEARCH = 1 + PHASE_VOTING = 2 + PHASE_FINISHED = 3 + + PHASES = ( + (PHASE_SEARCH, ugettext_lazy('Searching for candidates')), + (PHASE_VOTING, ugettext_lazy('Voting')), + (PHASE_FINISHED, ugettext_lazy('Finished')), ) - name = models.CharField(max_length=100, verbose_name=ugettext_lazy("Name")) - description = models.TextField(null=True, blank=True, verbose_name=ugettext_lazy("Description")) - posts = models.PositiveSmallIntegerField(verbose_name=ugettext_lazy("Number of available posts")) + title = models.CharField( + max_length=100, + verbose_name=ugettext_lazy("Title")) + """ + Title of the assignment. + """ + + description = models.TextField( + blank=True, + verbose_name=ugettext_lazy("Description")) + """ + Text to describe the assignment. + """ + + open_posts = models.PositiveSmallIntegerField( + verbose_name=ugettext_lazy("Number of members to be elected")) + """ + The number of members to be elected. + """ + poll_description_default = models.CharField( - max_length=79, null=True, blank=True, + max_length=79, + blank=True, verbose_name=ugettext_lazy("Default comment on the ballot paper")) - status = models.CharField(max_length=3, choices=STATUS, default='sea') + """ + Default text for the poll description. + """ + + phase = models.IntegerField( + choices=PHASES, + default=PHASE_SEARCH) + """ + Phase in which the assignment is. + """ + + related_users = models.ManyToManyField( + User, + through='AssignmentRelatedUser') + """ + Users that a candidates, elected or blocked as candidate. + + See AssignmentRelatedUser for more infos. + """ + tags = models.ManyToManyField(Tag, blank=True) + """ + Tags for the assignment. + """ + + items = GenericRelation(Item) + """ + Agenda items for this assignment. + """ class Meta: permissions = ( - ('can_see_assignment', ugettext_noop('Can see elections')), # TODO: Add plural s to the codestring - ('can_nominate_other', ugettext_noop('Can nominate another person')), + ('can_see_assignments', ugettext_noop('Can see elections')), + ('can_nominate_other', ugettext_noop('Can nominate another participant')), ('can_nominate_self', ugettext_noop('Can nominate oneself')), - ('can_manage_assignment', ugettext_noop('Can manage elections')), # TODO: Add plural s also to the codestring + ('can_manage_assignments', ugettext_noop('Can manage elections')), ) - ordering = ('name',) + ordering = ('title', ) verbose_name = ugettext_noop('Election') def __str__(self): - return self.name + return self.title def get_absolute_url(self, link='detail'): + """ + Returns absolute url to the assignment instance. + """ if link == 'detail': url = reverse('assignment_detail', args=[str(self.pk)]) elif link == 'update': @@ -80,125 +144,115 @@ class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model): elif link == 'delete': url = reverse('assignment_delete', args=[str(self.pk)]) else: - url = super(Assignment, self).get_absolute_url(link) + url = super().get_absolute_url(link) return url def get_slide_context(self, **context): - context.update({ - 'polls': self.poll_set.filter(published=True), - 'vote_results': self.vote_results(only_published=True)}) - return super(Assignment, self).get_slide_context(**context) - - def set_status(self, status): - status_dict = dict(self.STATUS) - if status not in status_dict: - raise ValueError(_('%s is not a valid status.') % html_strong(status)) - if self.status == status: - raise ValueError( - _('The election status is already %s.') % html_strong(status_dict[status])) - self.status = status - self.save() - - def run(self, candidate, person=None): """ - run for a vote - candidate: The user who will be a candidate - person: The user who chooses the candidate + Retuns the context to generate the assignment slide. """ - # TODO: don't make any permission checks here. - # Use other Exceptions - if self.is_candidate(candidate): - raise NameError(_('%s is already a candidate.') % candidate) - if not person.has_perm("assignment.can_manage_assignment") and self.status != 'sea': - raise NameError(_('The candidate list is already closed.')) - candidature = self.assignment_candidates.filter(person=candidate) - if candidature and candidate != person and \ - not person.has_perm("assignment.can_manage_assignment"): - # if the candidature is blocked and anotherone tries to run the - # candidate - raise NameError( - _('%s does not want to be a candidate.') % candidate) - elif candidature: - candidature[0].blocked = False - candidature[0].save() - else: - AssignmentCandidate(assignment=self, person=candidate).save() - - def delrun(self, candidate, blocked=True): - """ - stop running for a vote - """ - try: - candidature = self.assignment_candidates.get(person=candidate) - except AssignmentCandidate.DoesNotExist: - raise Exception(_('%s is no candidate') % candidate) - - if not candidature.blocked: - if blocked: - candidature.blocked = True - candidature.save() - else: - candidature.delete() - else: - candidature.delete() - - def is_candidate(self, person): - """ - return True, if person is a candidate. - """ - try: - return self.assignment_candidates.filter(person=person).exclude(blocked=True).exists() - except AttributeError: - return False - - def is_blocked(self, person): - """ - return True, if the person is blockt for candidature. - """ - return self.assignment_candidates.filter(person=person).filter(blocked=True).exists() - - @property - def assignment_candidates(self): - return AssignmentCandidate.objects.filter(assignment=self) + return super().get_slide_context( + polls=self.polls.filter(published=True), + vote_results=self.vote_results(only_published=True), + **context) @property def candidates(self): - return self.get_participants(only_candidate=True) + """ + Queryset that represents the candidates for the assignment. + """ + return self.related_users.filter( + assignmentrelateduser__status=AssignmentRelatedUser.STATUS_CANDIDATE) @property def elected(self): - return self.get_participants(only_elected=True) + """ + Queryset that represents all elected users for the assignment. + """ + return self.related_users.filter( + assignmentrelateduser__status=AssignmentRelatedUser.STATUS_ELECTED) - def get_participants(self, only_elected=False, only_candidate=False): - candidates = self.assignment_candidates.exclude(blocked=True) + @property + def blocked(self): + """ + Queryset that represents all blocked users for the assignment. + """ + return self.related_users.filter( + assignmentrelateduser__status=AssignmentRelatedUser.STATUS_BLOCKED) - assert not (only_elected and only_candidate) + def is_candidate(self, user): + """ + Returns True if user is a candidate. - if only_elected: - candidates = candidates.filter(elected=True) + Costs one database query. + """ + return self.candidates.filter(pk=user.pk).exists() - if only_candidate: - candidates = candidates.filter(elected=False) + def is_elected(self, user): + """ + Returns True if the user is elected for this assignment. - # TODO: rewrite this with a queryset - participants = [] - for candidate in candidates.all(): - participants.append(candidate.person) - return participants + Costs one database query. + """ + return self.elected.filter(pk=user.pk).exists() - def set_elected(self, person, value=True): - candidate = self.assignment_candidates.get(person=person) - candidate.elected = value - candidate.save() + def is_blocked(self, user): + """ + Returns True if the user is blockt for candidature. - def is_elected(self, person): - return person in self.elected + Costs one database query. + """ + return self.blocked.filter(pk=user.pk).exists() - def gen_poll(self): + def set_candidate(self, user): + """ + Adds the user as candidate. + """ + related_user, __ = self.assignment_related_users.update_or_create( + user=user, + defaults={'status': AssignmentRelatedUser.STATUS_CANDIDATE}) + + def set_elected(self, user): + """ + Makes user an elected user for this assignment. + """ + related_user, __ = self.assignment_related_users.update_or_create( + user=user, + defaults={'status': AssignmentRelatedUser.STATUS_ELECTED}) + + 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): + """ + Delete the connection from the assignment to the user. + """ + self.assignment_related_users.filter(user=user).delete() + + def set_phase(self, phase): + """ + Sets the phase attribute of the assignment. + + Raises a ValueError if the phase is not valide. + """ + if phase not in dict(self.PHASES): + raise ValueError("Invalid phase %s" % phase) + + self.phase = phase + + def create_poll(self): """ Creates an new poll for the assignment and adds all candidates to all lists of speakers of related agenda items. """ + candidates = self.candidates.all() + + # Find out the method of the election if config['assignment_poll_vote_values'] == 'votes': yesnoabstain = False elif config['assignment_poll_vote_values'] == 'yesnoabstain': @@ -206,19 +260,20 @@ class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model): else: # config['assignment_poll_vote_values'] == 'auto' # candidates <= available posts -> yes/no/abstain - if len(self.candidates) <= (self.posts - len(self.elected)): + if len(candidates) <= (self.open_posts - self.elected.count()): yesnoabstain = True else: yesnoabstain = False - poll = AssignmentPoll.objects.create( - assignment=self, + # Create the poll with the candidates. + poll = self.polls.create( description=self.poll_description_default, yesnoabstain=yesnoabstain) - poll.set_options([{'candidate': person} for person in self.candidates]) + poll.set_options({'candidate': user} for user in candidates) - items = Item.objects.filter(content_type=ContentType.objects.get_for_model(Assignment), object_id=self.pk) - for item in items: + # Add all candidates to all agenda items for this assignment + # TODO: Try to do this in a bulk create + for item in self.items.all(): for candidate in self.candidates: try: Speaker.objects.add(candidate, item) @@ -231,14 +286,15 @@ class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model): def vote_results(self, only_published): """ - returns a table represented as a list with all candidates from all + Returns a table represented as a list with all candidates from all related polls and their vote results. """ vote_results_dict = SortedDict() - # All polls related to this assigment - polls = self.poll_set.all() + + polls = self.polls.all() if only_published: polls = polls.filter(published=True) + # All PollOption-Objects related to this assignment options = [] for poll in polls: @@ -263,7 +319,7 @@ class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model): return vote_results_dict def get_agenda_title(self): - return self.name + return str(self) def get_agenda_title_supplement(self): return '(%s)' % _('Assignment') @@ -296,15 +352,14 @@ class AssignmentOption(RESTModelMixin, BaseOption): class AssignmentPoll(RESTModelMixin, SlideMixin, CollectDefaultVotesMixin, PublishPollMixin, AbsoluteUrlMixin, BasePoll): - slide_callback_name = 'assignmentpoll' - """Name of the callback for the slide system.""" - option_class = AssignmentOption - assignment = models.ForeignKey(Assignment, related_name='poll_set') + + assignment = models.ForeignKey(Assignment, related_name='polls') yesnoabstain = models.BooleanField(default=False) description = models.CharField( - max_length=79, null=True, blank=True, + max_length=79, + blank=True, verbose_name=ugettext_lazy("Comment on the ballot paper")) def __str__(self): @@ -321,7 +376,7 @@ class AssignmentPoll(RESTModelMixin, SlideMixin, CollectDefaultVotesMixin, elif link == 'delete': url = reverse('assignmentpoll_delete', args=[str(self.pk)]) else: - url = super(AssignmentPoll, self).get_absolute_url(link) + url = super().get_absolute_url(link) return url def get_assignment(self): @@ -334,17 +389,17 @@ class AssignmentPoll(RESTModelMixin, SlideMixin, CollectDefaultVotesMixin, return [ugettext_noop('Votes')] def get_ballot(self): - return self.assignment.poll_set.filter(id__lte=self.id).count() + return self.assignment.polls.filter(id__lte=self.pk).count() def get_percent_base_choice(self): return config['assignment_poll_100_percent_base'] def append_pollform_fields(self, fields): fields.append('description') - super(AssignmentPoll, self).append_pollform_fields(fields) + super().append_pollform_fields(fields) def get_slide_context(self, **context): - return super(AssignmentPoll, self).get_slide_context(poll=self) + return super().get_slide_context(poll=self) def get_root_rest_element(self): """ diff --git a/openslides/assignment/personal_info.py b/openslides/assignment/personal_info.py index 1ba394469..c9630466a 100644 --- a/openslides/assignment/personal_info.py +++ b/openslides/assignment/personal_info.py @@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy from openslides.utils.personal_info import PersonalInfo -from .models import Assignment +from .models import Assignment, AssignmentRelatedUser class AssignmentPersonalInfo(PersonalInfo): @@ -13,6 +13,5 @@ class AssignmentPersonalInfo(PersonalInfo): default_weight = 40 def get_queryset(self): - return Assignment.objects.filter( - assignmentcandidate__person=self.request.user, - assignmentcandidate__blocked=False) + return (Assignment.objects.filter(assignment_related_users__user=self.request.user) + .exclude(assignment_related_users__status=AssignmentRelatedUser.STATUS_BLOCKED)) diff --git a/openslides/assignment/serializers.py b/openslides/assignment/serializers.py index 34825898a..61d836131 100644 --- a/openslides/assignment/serializers.py +++ b/openslides/assignment/serializers.py @@ -3,23 +3,22 @@ from openslides.utils.rest_api import serializers from .models import ( models, Assignment, - AssignmentCandidate, + AssignmentRelatedUser, AssignmentOption, AssignmentPoll, AssignmentVote) -class AssignmentCandidateSerializer(serializers.ModelSerializer): +class AssignmentRelatedUserSerializer(serializers.ModelSerializer): """ - Serializer for assignment.models.AssignmentCandidate objects. + Serializer for assignment.models.AssignmentRelatedUser objects. """ class Meta: - model = AssignmentCandidate + model = AssignmentRelatedUser fields = ( 'id', - 'person', - 'elected', - 'blocked',) + 'user', + 'status') class AssignmentVoteSerializer(serializers.ModelSerializer): @@ -103,8 +102,8 @@ class AssignmentFullSerializer(serializers.ModelSerializer): """ Serializer for assignment.models.Assignment objects. With all polls. """ - assignmentcandidate_set = AssignmentCandidateSerializer(many=True, read_only=True) - poll_set = AssignmentAllPollSerializer(many=True, read_only=True) + related_users = AssignmentRelatedUserSerializer(many=True, read_only=True) + polls = AssignmentAllPollSerializer(many=True, read_only=True) class Meta: model = Assignment @@ -114,9 +113,9 @@ class AssignmentFullSerializer(serializers.ModelSerializer): 'description', 'posts', 'status', - 'assignmentcandidate_set', + 'related_users', 'poll_description_default', - 'poll_set', + 'polls', 'tags',) @@ -124,7 +123,8 @@ class AssignmentShortSerializer(AssignmentFullSerializer): """ Serializer for assignment.models.Assignment objects. Without unpublished poll. """ - poll_set = AssignmentShortPollSerializer(many=True, read_only=True) + related_users = AssignmentRelatedUserSerializer(many=True, read_only=True) + polls = AssignmentShortPollSerializer(many=True, read_only=True) class Meta: model = Assignment @@ -134,7 +134,7 @@ class AssignmentShortSerializer(AssignmentFullSerializer): 'description', 'posts', 'status', - 'assignmentcandidate_set', + 'related_users', 'poll_description_default', - 'poll_set', + 'polls', 'tags',) diff --git a/openslides/assignment/templates/assignment/assignment_detail.html b/openslides/assignment/templates/assignment/assignment_detail.html index 51fff465e..7699caab6 100644 --- a/openslides/assignment/templates/assignment/assignment_detail.html +++ b/openslides/assignment/templates/assignment/assignment_detail.html @@ -35,13 +35,13 @@ {% endif %} - {% if perms.assignment.can_manage_assignment or perms.agenda.can_manage_agenda %} + {% if perms.assignment.can_manage_assignments or perms.agenda.can_manage_agenda %}
{% trans 'More actions' %}
{% endblock %} diff --git a/openslides/assignment/templates/assignment/assignment_list.html b/openslides/assignment/templates/assignment/assignment_list.html index 2a1547d2b..2a96e1ee4 100644 --- a/openslides/assignment/templates/assignment/assignment_list.html +++ b/openslides/assignment/templates/assignment/assignment_list.html @@ -9,7 +9,7 @@ {% block content %}

{% trans "Elections" %} - {% if perms.assignment.can_manage_assignment %} + {% if perms.assignment.can_manage_assignments %} @@ -23,7 +23,7 @@ {% trans 'Tags' %} {% endif %} - {% if perms.assignment.can_see_assignment %} + {% if perms.assignment.can_see_assignments %} @@ -38,8 +38,8 @@ {% trans "Election" %} {% trans "Candidates" %} - {% trans "Status" %} - {% if perms.assignment.can_manage_assignment or perms.core.can_manage_projector %} + {% trans "Phase" %} + {% if perms.assignment.can_manage_assignments or perms.core.can_manage_projector %} {% trans "Actions" %} {% endif %} @@ -54,16 +54,16 @@ {% trans "Posts" context "Number of searched candidates for an election" %}: - {{ object.posts }} + {{ object.open_posts }} - {% if object.status != 'fin' %} - | {% trans "Candidates" %}: {{ object.get_participants|length }} + {% if object.phase != object.PHASE_FINISHED %} + | {% trans "Candidates" %}: {{ object.candidates.count }} {% endif %} - | {% trans "Elected" %}: {{ object.elected|length }} + | {% trans "Elected" %}: {{ object.elected.count }} - {{ object.get_status_display }} - {% if perms.assignment.can_manage_assignment or perms.core.can_manage_projector %} + {{ object.get_phase_display }} + {% if perms.assignment.can_manage_assignments or perms.core.can_manage_projector %} {% if perms.core.can_manage_projector %} @@ -73,7 +73,7 @@ {% endif %} - {% if perms.assignment.can_manage_assignment %} + {% if perms.assignment.can_manage_assignments %} diff --git a/openslides/assignment/templates/assignment/widget_assignment.html b/openslides/assignment/templates/assignment/widget_assignment.html index 7033343ae..0c3162c30 100644 --- a/openslides/assignment/templates/assignment/widget_assignment.html +++ b/openslides/assignment/templates/assignment/widget_assignment.html @@ -11,7 +11,7 @@ rel="tooltip" data-original-title="{% trans 'Show' %}">   - {% if perms.assignment.can_manage_assignment %} + {% if perms.assignment.can_manage_assignments %} diff --git a/openslides/assignment/templates/search/assignment-results.html b/openslides/assignment/templates/search/assignment-results.html index 7ea3ef147..381bac760 100644 --- a/openslides/assignment/templates/search/assignment-results.html +++ b/openslides/assignment/templates/search/assignment-results.html @@ -1,7 +1,7 @@ {% load i18n %} {% load highlight %} -{% if perms.assignment.can_see_assignment %} +{% if perms.assignment.can_see_assignments %}
  • {{ result.object }}
    {% trans "Election" %}
    diff --git a/openslides/assignment/templates/search/indexes/assignment/assignment_text.txt b/openslides/assignment/templates/search/indexes/assignment/assignment_text.txt index 3ea7b5085..de6268129 100644 --- a/openslides/assignment/templates/search/indexes/assignment/assignment_text.txt +++ b/openslides/assignment/templates/search/indexes/assignment/assignment_text.txt @@ -1,4 +1,4 @@ -{{ object.name }} +{{ object.title }} {{ object.description }} {{ object.candidates }} {{ object.tags.all }} diff --git a/openslides/assignment/urls.py b/openslides/assignment/urls.py index efb46177d..b2a31e2ed 100644 --- a/openslides/assignment/urls.py +++ b/openslides/assignment/urls.py @@ -24,21 +24,21 @@ urlpatterns = patterns( views.AssignmentDeleteView.as_view(), name='assignment_delete'), - url(r'^(?P\d+)/setstatus/(?P[a-z]{3})/$', - views.AssignmentSetStatusView.as_view(), - name='assignment_set_status'), + url(r'^(?P\d+)/set_phase/(?P\d+)/$', + views.AssignmentSetPhaseView.as_view(), + name='assignment_set_phase'), - url(r'^(?P\d+)/run/$', - views.AssignmentRunView.as_view(), - name='assignment_run'), + url(r'^(?P\d+)/candidate/$', + views.AssignmentCandidateView.as_view(), + name='assignment_candidate'), - url(r'^(?P\d+)/delrun/$', - views.AssignmentRunDeleteView.as_view(), - name='assignment_delrun'), + url(r'^(?P\d+)/delete_candidate/$', + views.AssignmentDeleteCandidateshipView.as_view(), + name='assignment_del_candidate'), - url(r'^(?P\d+)/delother/(?P[^/]+)/$', - views.AssignmentRunOtherDeleteView.as_view(), - name='assignment_delother'), + url(r'^(?P\d+)/delother/(?P[^/]+)/$', + views.AssignmentDeleteCandidateshipOtherView.as_view(), + name='assignment_del_candidate_other'), url(r'^(?P\d+)/agenda/$', views.CreateRelatedAgendaItemView.as_view(), @@ -52,7 +52,7 @@ urlpatterns = patterns( views.AssignmentPDF.as_view(), name='assignment_pdf'), - url(r'^(?P\d+)/gen_poll/$', + url(r'^(?P\d+)/create_poll/$', views.PollCreateView.as_view(), name='assignmentpoll_create'), @@ -64,22 +64,26 @@ urlpatterns = patterns( views.AssignmentPollDeleteView.as_view(), name='assignmentpoll_delete'), - url(r'^poll/(?P\d+)/print/$', + url(r'^poll/(?P\d+)/print/$', views.AssignmentPollPDF.as_view(), name='assignmentpoll_pdf'), - # TODO: use seperate urls to publish and unpublish the poll - # see assignment_user_elected url(r'^poll/(?P\d+)/pub/$', - views.SetPublishStatusView.as_view(), - name='assignmentpoll_publish_status'), + views.SetPublishPollView.as_view(), + {'publish': True}, + name='assignmentpoll_publish_poll'), - url(r'^(?P\d+)/elected/(?P[^/]+)/$', + url(r'^poll/(?P\d+)/unpub/$', + views.SetPublishPollView.as_view(), + {'publish': False}, + name='assignmentpoll_unpublish_poll'), + + url(r'^(?P\d+)/elected/(?P[^/]+)/$', views.SetElectedView.as_view(), {'elected': True}, name='assignment_user_elected'), - url(r'^(?P\d+)/notelected/(?P[^/]+)/$', + url(r'^(?P\d+)/notelected/(?P[^/]+)/$', views.SetElectedView.as_view(), {'elected': False}, name='assignment_user_not_elected') diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py index 8d5070a07..ed3e98480 100644 --- a/openslides/assignment/views.py +++ b/openslides/assignment/views.py @@ -2,7 +2,6 @@ from cgi import escape from django.contrib import messages from django.core.urlresolvers import reverse -from django.shortcuts import redirect from django.utils.translation import ugettext as _ from django.utils.translation import ungettext from reportlab.lib import colors @@ -18,9 +17,9 @@ from openslides.utils.pdf import stylesheet from openslides.utils.rest_api import viewsets from openslides.utils.utils import html_strong from openslides.utils.views import (CreateView, DeleteView, DetailView, - ListView, PDFView, PermissionMixin, + ListView, PDFView, QuestionView, RedirectView, - SingleObjectMixin, UpdateView, View) + SingleObjectMixin, UpdateView) from .forms import AssignmentForm, AssignmentRunForm from .models import Assignment, AssignmentPoll @@ -28,150 +27,183 @@ from .serializers import AssignmentFullSerializer, AssignmentShortSerializer class AssignmentListView(ListView): - """ListView for all Assignments""" - required_permission = 'assignment.can_see_assignment' + """ + Lists all assignments. + """ + required_permission = 'assignment.can_see_assignments' model = Assignment class AssignmentDetail(DetailView): - required_permission = 'assignment.can_see_assignment' + """ + Shows one assignment. + """ + # TODO: use another view as 'run form' when updating this to angular + required_permission = 'assignment.can_see_assignments' model = Assignment form_class = AssignmentRunForm def get_context_data(self, *args, **kwargs): - context = super(AssignmentDetail, self).get_context_data(*args, **kwargs) + context = super().get_context_data(*args, **kwargs) + assignment = self.get_object() if self.request.method == 'POST': context['form'] = self.form_class(self.request.POST) else: context['form'] = self.form_class() - polls = self.get_object().poll_set.all() - if not self.request.user.has_perm('assignment.can_manage_assignment'): - polls = self.get_object().poll_set.filter(published=True) - vote_results = self.get_object().vote_results(only_published=True) - else: - polls = self.get_object().poll_set.all() - vote_results = self.get_object().vote_results(only_published=False) - blocked_candidates = [ - candidate.person for candidate in - self.get_object().assignment_candidates.filter(blocked=True)] + polls = assignment.polls.all() + if not self.request.user.has_perm('assignment.can_manage_assignments'): + polls = polls.filter(published=True) + vote_results = assignment.vote_results(only_published=True) + else: + polls = self.get_object().polls.all() + vote_results = assignment.vote_results(only_published=False) + context['polls'] = polls context['vote_results'] = vote_results - context['blocked_candidates'] = blocked_candidates - context['user_is_candidate'] = self.get_object().is_candidate(self.request.user) + context['blocked_candidates'] = assignment.blocked + context['user_is_candidate'] = assignment.is_candidate(self.request.user) return context def post(self, *args, **kwargs): if self.request.user.has_perm('assignment.can_nominate_other'): + assignment = self.get_object() form = self.form_class(self.request.POST) if form.is_valid(): user = form.cleaned_data['candidate'] - try: - self.get_object().run(user, self.request.user) - except NameError as e: - messages.error(self.request, e) + if (assignment.phase == assignment.PHASE_SEARCH or + self.request.user.has_perm('assignment.can_manage_assignments')): + if (assignment.is_blocked(user) and + not self.request.user.has_perm('assignment.can_manage_assignments')): + messages.error( + self.request, + _("User %s does not want to be an candidate") % user) + elif assignment.is_elected(user): + messages.error( + self.request, + _("User %s is already elected") % html_strong(user)) + elif assignment.is_candidate(user): + messages.error( + self.request, + _("User %s is already an candidate") % html_strong(user)) + else: + assignment.set_candidate(user) + messages.success( + self.request, + _("User %s was nominated successfully.") % html_strong(user)) else: - messages.success(self.request, _( - "Candidate %s was nominated successfully.") - % html_strong(user)) + messages.error( + self.request, + _("You can not add candidates to this assignment")) return super(AssignmentDetail, self).get(*args, **kwargs) class AssignmentCreateView(CreateView): + required_permission = 'assignment.can_manage_assignments' model = Assignment form_class = AssignmentForm - required_permission = 'assignment.can_manage_assignment' class AssignmentUpdateView(UpdateView): + required_permission = 'assignment.can_manage_assignments' model = Assignment form_class = AssignmentForm - required_permission = 'assignment.can_manage_assignment' class AssignmentDeleteView(DeleteView): - required_permission = 'assignment.can_manage_assignment' + required_permission = 'assignment.can_manage_assignments' model = Assignment success_url_name = 'assignment_list' -class AssignmentSetStatusView(SingleObjectMixin, RedirectView): +class AssignmentSetPhaseView(SingleObjectMixin, RedirectView): + required_permission = 'assignment.can_manage_assignments' model = Assignment - required_permission = 'assignment.can_manage_assignment' url_name = 'assignment_detail' def pre_redirect(self, *args, **kwargs): - status = kwargs.get('status') - if status is not None: - try: - self.get_object().set_status(status) - except ValueError as e: - messages.error(self.request, e) - else: - messages.success( - self.request, - _('Election status was set to: %s.') % - html_strong(self.get_object().get_status_display()) - ) - - -class AssignmentRunView(SingleObjectMixin, PermissionMixin, View): - model = Assignment - required_permission = 'assignment.can_nominate_self' - - def get(self, *args, **kwargs): + phase = int(kwargs.get('phase')) assignment = self.get_object() try: - assignment.run(self.request.user, self.request.user) - except NameError as e: + assignment.set_phase(phase) + except ValueError as e: messages.error(self.request, e) else: + assignment.save() messages.success( - self.request, _('You have set your candidature successfully.')) - return redirect(reverse('assignment_detail', args=[assignment.pk])) + self.request, + _('Election status was set to: %s.') % + html_strong(assignment.get_phase_display())) -class AssignmentRunDeleteView(SingleObjectMixin, RedirectView): +class AssignmentCandidateView(SingleObjectMixin, RedirectView): + required_permission = 'assignment.can_nominate_self' model = Assignment url_name = 'assignment_detail' def pre_redirect(self, *args, **kwargs): - if self.get_object().status == 'sea' or self.request.user.has_perm( - "assignment.can_manage_assignment"): - try: - self.get_object().delrun(self.request.user, blocked=True) - except Exception as e: - # TODO: only catch relevant exception - messages.error(self.request, e) + assignment = self.get_object() + if (assignment.phase == assignment.PHASE_SEARCH or + self.request.user.has_perm('assignment.can_manage_assignments')): + user = self.request.user + if assignment.is_elected(user): + messages.error( + self.request, + _("You are already elected")) + elif assignment.is_candidate(user): + messages.error( + self.request, + _("You are already an candidate")) else: - messages.success(self.request, _( - 'You have withdrawn your candidature successfully. ' - 'You can not be nominated by other participants anymore.')) + assignment.set_candidate(user) + messages.success( + self.request, + _("You were nominated successfully.")) + else: + messages.error( + self.request, + _("You can not candidate to this assignment")) + + +class AssignmentDeleteCandidateshipView(SingleObjectMixin, RedirectView): + required_permission = None # Any user can withdraw his candidature + model = Assignment + url_name = 'assignment_detail' + + def pre_redirect(self, *args, **kwargs): + assignment = self.get_object() + if (assignment.phase == assignment.PHASE_SEARCH or + self.request.user.has_perm('assignment.can_manage_assignments')): + user = self.request.user + assignment.set_blocked(user) + messages.success(self.request, _( + 'You have withdrawn your candidature successfully. ' + 'You can not be nominated by other participants anymore.')) else: messages.error(self.request, _('The candidate list is already closed.')) -class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionView): +class AssignmentDeleteCandidateshipOtherView(SingleObjectMixin, QuestionView): + required_permission = 'assignment.can_manage_assignments' model = Assignment - required_permission = 'assignment.can_manage_assignment' def get_question_message(self): - self._get_person_information() - if not self.is_blocked: - question = _("Do you really want to withdraw %s from the election?") % html_strong(self.person) + self.user = User.objects.get(pk=self.kwargs.get('user_pk')) + assignment = self.get_object() + if assignment.is_blocked: + question = _("Do you really want to unblock %s for the election?") % html_strong(self.user) else: - question = _("Do you really want to unblock %s for the election?") % html_strong(self.person) + question = _("Do you really want to withdraw %s from the election?") % html_strong(self.user) return question def on_clicked_yes(self): - self._get_person_information() - try: - self.get_object().delrun(self.person, blocked=False) - except Exception as e: - # TODO: only catch relevant exception - self.error = e - else: + self.user = User.objects.get(pk=self.kwargs.get('user_pk')) + assignment = self.get_object() + if not assignment.is_elected(self.user): + assignment.delete_related_user(self.user) self.error = False + else: + self.error = _("User %s is already elected") % html_strong(self.user) def create_final_message(self): if self.error: @@ -180,14 +212,7 @@ class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionView): messages.success(self.request, self.get_final_message()) def get_final_message(self): - message = _("Candidate %s was withdrawn successfully.") % html_strong(self.person) - if self.is_blocked: - message = _("%s was unblocked successfully.") % html_strong(self.person) - return message - - def _get_person_information(self): - self.person = User.objects.get(pk=self.kwargs.get('user_id')) - self.is_blocked = self.get_object().is_blocked(self.person) + return _("Candidate %s was withdrawn successfully.") % html_strong(self.user) class AssignmentViewSet(viewsets.ModelViewSet): @@ -203,16 +228,16 @@ class AssignmentViewSet(viewsets.ModelViewSet): permission to see assignments and in case of create, update or destroy requests the permission to manage assignments. """ - if (not request.user.has_perm('assignment.can_see_assignment') or + if (not request.user.has_perm('assignment.can_see_assignments') or (self.action in ('create', 'update', 'destroy') and not - request.user.has_perm('assignment.can_manage_assignment'))): + request.user.has_perm('assignment.can_manage_assignments'))): self.permission_denied(request) def get_serializer_class(self): """ Returns different serializer classes with respect to users permissions. """ - if self.request.user.has_perm('assignment.can_manage_assignment'): + if self.request.user.has_perm('assignment.can_manage_assignments'): serializer_class = AssignmentFullSerializer else: serializer_class = AssignmentShortSerializer @@ -220,16 +245,17 @@ class AssignmentViewSet(viewsets.ModelViewSet): class PollCreateView(SingleObjectMixin, RedirectView): + required_permission = 'assignment.can_manage_assignments' model = Assignment - required_permission = 'assignment.can_manage_assignment' url_name = 'assignment_detail' def pre_redirect(self, *args, **kwargs): - self.get_object().gen_poll() + self.get_object().create_poll() messages.success(self.request, _("New ballot was successfully created.")) class PollUpdateView(PollFormView): + required_permission = 'assignment.can_manage_assignments' poll_class = AssignmentPoll template_name = 'assignment/assignmentpoll_form.html' @@ -238,49 +264,46 @@ class PollUpdateView(PollFormView): self.assignment = self.poll.get_assignment() context['assignment'] = self.assignment context['poll'] = self.poll - context['polls'] = self.assignment.poll_set.all() + context['polls'] = self.assignment.polls.all() context['ballotnumber'] = self.poll.get_ballot() return context def get_success_url(self): - return_url = '' if 'apply' not in self.request.POST: return_url = reverse('assignment_detail', args=[self.poll.assignment.id]) + else: + return_url = '' return return_url -class SetPublishStatusView(SingleObjectMixin, RedirectView): +class SetPublishPollView(SingleObjectMixin, RedirectView): + required_permission = 'assignment.can_manage_assignments' model = AssignmentPoll - required_permission = 'assignment.can_manage_assignment' url_name = 'assignment_detail' allow_ajax = True + publish = False - def get_ajax_context(self, **kwargs): - return {'published': self.object.published} + def get_ajax_context(self, **context): + return super().get_ajax_context( + published=self.object.published, + **context) def pre_redirect(self, *args, **kwargs): - try: - poll = self.get_object() - except self.model.DoesNotExist: - messages.error(self.request, _('Ballot ID %d does not exist.') % - int(kwargs['poll_id'])) - else: - if poll.published: - poll.set_published(False) - else: - poll.set_published(True) + poll = self.get_object() + poll.set_published(kwargs['publish']) class SetElectedView(SingleObjectMixin, RedirectView): + required_permission = 'assignment.can_manage_assignments' model = Assignment - required_permission = 'assignment.can_manage_assignment' url_name = 'assignment_detail' allow_ajax = True def pre_redirect(self, *args, **kwargs): self.person = User.objects.get(pk=kwargs['user_id']) self.elected = kwargs['elected'] - self.get_object().set_elected(self.person, self.elected) + # TODO: un-elect users if self.elected is False + self.get_object().set_elected(self.person) def get_ajax_context(self, **kwargs): if self.elected: @@ -298,16 +321,16 @@ class AssignmentPollDeleteView(DeleteView): """ Delete an assignment poll object. """ - required_permission = 'assignment.can_manage_assignment' + required_permission = 'assignment.can_manage_assignments' model = AssignmentPoll def pre_redirect(self, request, *args, **kwargs): self.set_assignment() - super(AssignmentPollDeleteView, self).pre_redirect(request, *args, **kwargs) + super().pre_redirect(request, *args, **kwargs) def pre_post_redirect(self, request, *args, **kwargs): self.set_assignment() - super(AssignmentPollDeleteView, self).pre_post_redirect(request, *args, **kwargs) + super().pre_post_redirect(request, *args, **kwargs) def set_assignment(self): self.assignment = self.get_object().assignment @@ -320,26 +343,26 @@ class AssignmentPollDeleteView(DeleteView): class AssignmentPDF(PDFView): - required_permission = 'assignment.can_see_assignment' + required_permission = 'assignment.can_see_assignments' top_space = 0 def get_filename(self): try: - assignment_id = self.kwargs['pk'] - assignment = Assignment.objects.get(id=assignment_id) + assignment = Assignment.objects.get(pk=self.kwargs['pk']) filename = u'%s-%s' % ( _("Assignment"), - assignment.name.replace(' ', '_')) + assignment.title.replace(' ', '_')) except: filename = _("Elections") return filename def append_to_pdf(self, story): try: - assignment_id = self.kwargs['pk'] + assignment_pk = self.kwargs['pk'] except KeyError: - assignment_id = None - if assignment_id is None: # print all assignments + assignment_pk = None + + if assignment_pk is None: # print all assignments title = escape(config["assignment_pdf_title"]) story.append(Paragraph(title, stylesheet['Heading1'])) preamble = escape(config["assignment_pdf_preamble"]) @@ -356,31 +379,31 @@ class AssignmentPDF(PDFView): # List of assignments for assignment in assignments: story.append(Paragraph( - escape(assignment.name), stylesheet['Heading3'])) + escape(assignment.title), stylesheet['Heading3'])) # Assignment details (each assignment on single page) for assignment in assignments: story.append(PageBreak()) # append the assignment to the story-object self.get_assignment(assignment, story) else: # print selected assignment - assignment = Assignment.objects.get(id=assignment_id) + assignment = Assignment.objects.get(pk=assignment_pk) # append the assignment to the story-object self.get_assignment(assignment, story) def get_assignment(self, assignment, story): # title story.append(Paragraph( - _("Election: %s") % escape(assignment.name), stylesheet['Heading1'])) + _("Election: %s") % escape(assignment.title), stylesheet['Heading1'])) story.append(Spacer(0, 0.5 * cm)) # Filling table rows... data = [] - polls = assignment.poll_set.filter(published=True) + polls = assignment.polls.filter(published=True) # 1. posts data.append([ Paragraph("%s:" % - _("Number of available posts"), stylesheet['Bold']), - Paragraph(str(assignment.posts), stylesheet['Paragraph'])]) + _("Number of members to be elected"), stylesheet['Bold']), + Paragraph(str(assignment.open_posts), stylesheet['Paragraph'])]) # 2a. if no polls available print candidates if not polls: @@ -393,7 +416,7 @@ class AssignmentPDF(PDFView): [], Paragraph(".  %s" % candidate, stylesheet['Signaturefield'])]) - if assignment.status == "sea": + if assignment.phase == assignment.PHASE_SEARCH: for x in range(0, 7): data.append([ [], @@ -517,16 +540,16 @@ class CreateRelatedAgendaItemView(_CreateRelatedAgendaItemView): class AssignmentPollPDF(PDFView): - required_permission = 'assignment.can_manage_assignment' + required_permission = 'assignment.can_manage_assignments' top_space = 0 def get(self, request, *args, **kwargs): - self.poll = AssignmentPoll.objects.get(id=self.kwargs['poll_id']) + self.poll = AssignmentPoll.objects.get(pk=self.kwargs['poll_pk']) return super().get(request, *args, **kwargs) def get_filename(self): filename = u'%s-%s_%s' % ( - _("Election"), self.poll.assignment.name.replace(' ', '_'), + _("Election"), self.poll.assignment.title.replace(' ', '_'), self.poll.get_ballot()) return filename @@ -543,7 +566,7 @@ class AssignmentPollPDF(PDFView): cell = [] cell.append(Spacer(0, 0.8 * cm)) cell.append(Paragraph( - _("Election") + ": " + self.poll.assignment.name, + _("Election") + ": " + self.poll.assignment.title, stylesheet['Ballot_title'])) cell.append(Paragraph( self.poll.description or '', @@ -555,7 +578,7 @@ class AssignmentPollPDF(PDFView): "%d candidate", "%d candidates", len(options)) % len(options) available_posts_string = ungettext( "%d available post", "%d available posts", - self.poll.assignment.posts) % self.poll.assignment.posts + self.poll.assignment.open_posts) % self.poll.assignment.open_posts cell.append(Paragraph( "%s, %s, %s" % (ballot_string, candidate_string, available_posts_string), stylesheet['Ballot_description'])) diff --git a/openslides/users/api.py b/openslides/users/api.py index ac299b692..8d29151ca 100644 --- a/openslides/users/api.py +++ b/openslides/users/api.py @@ -76,7 +76,7 @@ def create_builtin_groups_and_admin(): perm_15 = Permission.objects.get(content_type=ct_motion, codename='can_see_motion') ct_assignment = ContentType.objects.get(app_label='assignment', model='assignment') - perm_16 = Permission.objects.get(content_type=ct_assignment, codename='can_see_assignment') + perm_16 = Permission.objects.get(content_type=ct_assignment, codename='can_see_assignments') ct_users = ContentType.objects.get(app_label='users', model='user') perm_users_can_see_name = Permission.objects.get(content_type=ct_users, codename='can_see_name') @@ -114,7 +114,7 @@ def create_builtin_groups_and_admin(): # Staff (pk 4) perm_41 = Permission.objects.get(content_type=ct_agenda, codename='can_manage_agenda') perm_42 = Permission.objects.get(content_type=ct_motion, codename='can_manage_motion') - perm_43 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignment') + perm_43 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignments') perm_44 = Permission.objects.get(content_type=ct_users, codename='can_manage') perm_45 = Permission.objects.get(content_type=ct_core, codename='can_manage_projector') perm_46 = Permission.objects.get(content_type=ct_core, codename='can_use_chat') diff --git a/tests/old/account/test_widgets.py b/tests/old/account/test_widgets.py index c1851c1a7..12c9de704 100644 --- a/tests/old/account/test_widgets.py +++ b/tests/old/account/test_widgets.py @@ -91,8 +91,8 @@ class PersonalInfoWidget(TestCase): def test_candidate_list(self): assignment = self.import_assignment() if assignment: - assignment_1 = assignment.models.Assignment.objects.create(name='Hausmeister ooKoh7roApoo3phe', posts=1) - assignment_1.run(candidate=self.user, person=self.user) + assignment_1 = assignment.models.Assignment.objects.create(title='Hausmeister ooKoh7roApoo3phe', open_posts=1) + assignment_1.set_candidate(self.user) response = self.client.get('/dashboard/') self.assertContains(response, 'I am candidate for the following elections:', status_code=200) self.assertContains(response, 'Hausmeister ooKoh7roApoo3phe', status_code=200) diff --git a/tests/old/assignment/test_models.py b/tests/old/assignment/test_models.py deleted file mode 100644 index abc112038..000000000 --- a/tests/old/assignment/test_models.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.test.client import Client - -from openslides.agenda.models import Item, Speaker -from openslides.assignment.models import Assignment -from openslides.users.models import User -from openslides.utils.test import TestCase - - -class AssignmentModelTest(TestCase): - def setUp(self): - # Admin - self.admin = User.objects.get(pk=1) - self.admin_client = Client() - self.admin_client.login(username='admin', password='admin') - - def test_delete_with_related_item(self): - assignment = Assignment.objects.create(name='assignment_name_fgdhensbch34zfu1284ds', posts=1) - response = self.admin_client.get('/assignment/1/agenda/') - self.assertRedirects(response, '/agenda/') - self.assertEqual(Item.objects.get(pk=1).get_title(), 'assignment_name_fgdhensbch34zfu1284ds') - assignment.delete() - self.assertTrue(Item.objects.filter(pk=1).exists()) - - def test_begin_speach(self): - assignment = Assignment.objects.create(name='test_assignment_gjbnchs4620sdfhjfsksj1', posts=1) - item = Item.objects.create(content_object=assignment) - person_1 = User.objects.create(username='user_1_bnhdjgd8747djcbjd8fg') - person_2 = User.objects.create(username='user_2_qmlkohid6qvx5q0fbmh9') - person_3 = User.objects.create(username='user_3_nbjf74jf9bjag219ou96') - assignment.run(person_1, person_1) - assignment.run(person_2, person_2) - assignment.run(person_3, person_3) - Speaker.objects.add(person_1, item) - self.assertEqual(item.speaker_set.count(), 1) - - assignment.gen_poll() - self.assertTrue(item.speaker_set.filter(user=person_1).exists()) - self.assertTrue(item.speaker_set.filter(user=person_2).exists()) - self.assertTrue(item.speaker_set.filter(user=person_3).exists()) diff --git a/tests/old/assignment/test_pdf.py b/tests/old/assignment/test_pdf.py index 9312600e3..03ea82f0e 100644 --- a/tests/old/assignment/test_pdf.py +++ b/tests/old/assignment/test_pdf.py @@ -16,11 +16,11 @@ class AssignmentPDFTest(TestCase): self.admin_client.login(username='admin', password='admin') def test_render_pdf(self): - Assignment.objects.create(name='assignment_name_ith8qua1Eiferoqu5ju2', description="test", posts=1) + Assignment.objects.create(title='assignment_name_ith8qua1Eiferoqu5ju2', description="test", open_posts=1) response = self.admin_client.get('/assignment/print/') self.assertEqual(response.status_code, 200) def test_render_many_posts(self): - Assignment.objects.create(name='assignment_name_cohZ9shaipee3Phaing4', description="test", posts=20) + Assignment.objects.create(title='assignment_name_cohZ9shaipee3Phaing4', description="test", open_posts=20) response = self.admin_client.get('/assignment/print/') self.assertEqual(response.status_code, 200) diff --git a/tests/old/assignment/test_views.py b/tests/old/assignment/test_views.py index eeee670ea..9c5c17e6c 100644 --- a/tests/old/assignment/test_views.py +++ b/tests/old/assignment/test_views.py @@ -34,7 +34,7 @@ class AssignmentViewTestCase(TestCase): self.registered_client = Client() self.registered_client.login(username='registered', password='registered') - self.assignment1 = Assignment.objects.create(name='test', posts=2) + self.assignment1 = Assignment.objects.create(title='test', open_posts=2) def check_url(self, url, test_client, response_cose): response = test_client.get(url) @@ -45,7 +45,7 @@ class AssignmentViewTestCase(TestCase): class TestAssignmentPollDelete(AssignmentViewTestCase): def setUp(self): super(TestAssignmentPollDelete, self).setUp() - self.assignment1.gen_poll() + self.assignment1.create_poll() def test_get(self): response = self.check_url('/assignment/poll/1/del/', self.admin_client, 302) @@ -65,7 +65,7 @@ class TestAssignmentDetailView(AssignmentViewTestCase): self.assertContains(response, 'No candidates available.') self.assertNotContains(response, 'Blocked Candidates') - response = self.delegate_client.get('/assignment/1/run/') + response = self.delegate_client.get('/assignment/1/candidate/') self.assertTrue(self.assignment1.is_candidate(self.delegate)) self.assertFalse(self.assignment1.is_blocked(self.delegate)) @@ -73,7 +73,7 @@ class TestAssignmentDetailView(AssignmentViewTestCase): self.assertNotContains(response, 'No candidates available.') self.assertNotContains(response, 'Blocked Candidates') - response = self.delegate_client.get('/assignment/1/delrun/') + response = self.delegate_client.get('/assignment/1/delete_candidate/') self.assertFalse(self.assignment1.is_candidate(self.delegate)) self.assertTrue(self.assignment1.is_blocked(self.delegate)) @@ -89,19 +89,19 @@ class TestAssignmentPollCreateView(TestCase): def test_assignment_add_candidate(self): admin = User.objects.get(pk=1) self.assignment = Assignment.objects.create( - name='test_assignment_oiL2heerookiegeirai0', - posts=1) - self.assignment.run(admin, admin) + title='test_assignment_oiL2heerookiegeirai0', + open_posts=1) + self.assignment.set_candidate(admin) self.assertEqual(len(Assignment.objects.get(pk=self.assignment.pk).candidates), 1) def test_assignment_poll_creation(self): self.test_assignment_add_candidate() - self.assignment.set_status('vot') + self.assignment.set_phase(self.assignment.PHASE_VOTING) admin_client = Client() admin_client.login(username='admin', password='admin') self.assertFalse(AssignmentPoll.objects.exists()) self.assertEqual(config['assignment_poll_vote_values'], 'auto') - response = admin_client.get('/assignment/1/gen_poll/') + response = admin_client.get('/assignment/1/create_poll/') self.assertRedirects(response, '/assignment/1/') poll = AssignmentPoll.objects.get() self.assertEqual(poll.assignment, self.assignment) @@ -117,10 +117,10 @@ class TestAssignmentPollPdfView(TestCase): def test_assignment_create_poll_pdf(self): # Create a assignment with a poll admin = User.objects.get(pk=1) - assignment = Assignment.objects.create(name='assignment1', posts=1) - assignment.run(admin, admin) - assignment.set_status('vot') - assignment.gen_poll() + assignment = Assignment.objects.create(title='assignment1', open_posts=1) + assignment.set_candidate(admin) + assignment.set_phase(assignment.PHASE_VOTING) + assignment.create_poll() client = Client() client.login(username='admin', password='admin') @@ -140,7 +140,7 @@ class TestPollUpdateView(TestCase): """ Tests that a 404 is returned, when a non existing poll is requested. """ - Assignment.objects.create(name='test assignment', posts=1) + Assignment.objects.create(title='test assignment', open_posts=1) url = '/assignment/poll/1/edit/' response = self.admin_client.get(url)