{"action":"created","comment":{"url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/comments/28583919","id":28583919,"diff_hunk":"@@ -242,6 +243,134 @@ def get_serializer_class(self):\n             serializer_class = AssignmentShortSerializer\n         return serializer_class\n \n+    @detail_route(methods=['post', 'delete'])\n+    def candidature_self(self, request, pk=None):\n+        \"\"\"\n+        View to nominate self as candidate (POST) or withdraw own candidature\n+        (DELETE).\n+        \"\"\"\n+        if not request.user.has_perm('assignments.can_nominate_self'):\n+            self.permission_denied(request)\n+        assignment = self.get_object()\n+        if assignment.is_elected(request.user):\n+            raise ValidationError({'detail': _('You are already elected.')})\n+        if request.method == 'POST':\n+            message = self.nominate_self(request, assignment)\n+        else:\n+            # request.method == 'DELETE'\n+            message = self.withdraw_self(request, assignment)\n+        return Response({'detail': message})\n+\n+    def nominate_self(self, request, assignment):\n+        if assignment.phase == assignment.PHASE_FINISHED:\n+            raise ValidationError({'detail': _('You can not candidate to this election because it is finished.')})\n+        if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'):\n+            # To nominate self during voting you have to be a manager.\n+            self.permission_denied(request)\n+        if assignment.is_candidate(request.user):\n+            raise ValidationError({'detail': _('You are already a candidate of this election.')})\n+        assignment.set_candidate(request.user)\n+        return _('You were nominated successfully.')\n+\n+    def withdraw_self(self, request, assignment):\n+        # Withdraw candidature and set self blocked.\n+        if assignment.phase == assignment.PHASE_FINISHED:\n+            raise ValidationError({'detail': _('You can not withdraw your candidature to this election because it is finished.')})\n+        if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'):\n+            # To withdraw self during voting you have to be a manager.\n+            self.permission_denied(request)\n+        if not assignment.is_candidate(request.user):\n+            raise ValidationError({'detail': _('You are not a candidate of this election.')})\n+        assignment.set_blocked(request.user)\n+        return _(\n+            'You have withdrawn your candidature successfully. '\n+            'You can not be nominated by other participants anymore.')\n+\n+    def get_other_user(self, request):\n+        \"\"\"\n+        Helper method to get a specific user from request data (not the\n+        request.user) so that the views self.candidature_other or\n+        self.mark_elected can play with him.\n+        \"\"\"\n+        if not isinstance(request.data, dict):\n+            raise ValidationError({'detail': _('Invalid data. Expected dictionary, got %s.') % type(request.data)})\n+        user_str = request.data.get('user', '')\n+        try:\n+            user_pk = int(user_str)\n+        except ValueError:\n+            raise ValidationError({'detail': _('Invalid data. Expected something like {\"user\": <id>}.')})\n+        try:\n+            user = User.objects.get(pk=user_pk)\n+        except User.DoesNotExist:\n+            raise ValidationError({'detail': _('Invalid data. User %d does not exist.') % user_pk})\n+        return user\n+\n+    @detail_route(methods=['post', 'delete'])\n+    def candidature_other(self, request, pk=None):\n+        \"\"\"\n+        View to nominate other users (POST) or delete their candidature\n+        status (DELETE). The client has to send {'user': <id>}.\n+        \"\"\"\n+        if not request.user.has_perm('assignments.can_nominate_other'):\n+            self.permission_denied(request)\n+        user = self.get_other_user(request)\n+        assignment = self.get_object()\n+        if assignment.is_elected(user):\n+            raise ValidationError({'detail': _('User %s is already elected.') % user})\n+        if request.method == 'POST':\n+            message = self.nominate_other(request, user, assignment)\n+        else:\n+            # request.method == 'DELETE'\n+            message = self.delete_other(request, user, assignment)\n+        return Response({'detail': message})\n+\n+    def nominate_other(self, request, user, assignment):\n+        if assignment.phase == assignment.PHASE_FINISHED:\n+            raise ValidationError({'detail': _('You can not nominate someone to this election because it is finished.')})","path":"openslides/assignments/views.py","position":106,"original_position":106,"commit_id":"e0973cb11061e8eb6cf10e182d1239db9157e301","original_commit_id":"e0973cb11061e8eb6cf10e182d1239db9157e301","user":{"login":"ostcar","id":977937,"avatar_url":"https://avatars.githubusercontent.com/u/977937?v=3","gravatar_id":"","url":"https://api.github.com/users/ostcar","html_url":"https://github.com/ostcar","followers_url":"https://api.github.com/users/ostcar/followers","following_url":"https://api.github.com/users/ostcar/following{/other_user}","gists_url":"https://api.github.com/users/ostcar/gists{/gist_id}","starred_url":"https://api.github.com/users/ostcar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ostcar/subscriptions","organizations_url":"https://api.github.com/users/ostcar/orgs","repos_url":"https://api.github.com/users/ostcar/repos","events_url":"https://api.github.com/users/ostcar/events{/privacy}","received_events_url":"https://api.github.com/users/ostcar/received_events","type":"User","site_admin":false},"body":"The same here","created_at":"2015-04-17T10:28:33Z","updated_at":"2015-04-17T10:28:33Z","html_url":"https://github.com/OpenSlides/OpenSlides/pull/1512#discussion_r28583919","pull_request_url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512","_links":{"self":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/comments/28583919"},"html":{"href":"https://github.com/OpenSlides/OpenSlides/pull/1512#discussion_r28583919"},"pull_request":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512"}}},"pull_request":{"url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512","id":32188313,"html_url":"https://github.com/OpenSlides/OpenSlides/pull/1512","diff_url":"https://github.com/OpenSlides/OpenSlides/pull/1512.diff","patch_url":"https://github.com/OpenSlides/OpenSlides/pull/1512.patch","issue_url":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/1512","number":1512,"state":"open","locked":false,"title":"Assignment REST API changes","user":{"login":"normanjaeckel","id":2073844,"avatar_url":"https://avatars.githubusercontent.com/u/2073844?v=3","gravatar_id":"","url":"https://api.github.com/users/normanjaeckel","html_url":"https://github.com/normanjaeckel","followers_url":"https://api.github.com/users/normanjaeckel/followers","following_url":"https://api.github.com/users/normanjaeckel/following{/other_user}","gists_url":"https://api.github.com/users/normanjaeckel/gists{/gist_id}","starred_url":"https://api.github.com/users/normanjaeckel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanjaeckel/subscriptions","organizations_url":"https://api.github.com/users/normanjaeckel/orgs","repos_url":"https://api.github.com/users/normanjaeckel/repos","events_url":"https://api.github.com/users/normanjaeckel/events{/privacy}","received_events_url":"https://api.github.com/users/normanjaeckel/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-03-29T21:22:31Z","updated_at":"2015-04-17T10:28:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c0882da4e3b274b4ada683e02436009df16eee80","assignee":{"login":"ostcar","id":977937,"avatar_url":"https://avatars.githubusercontent.com/u/977937?v=3","gravatar_id":"","url":"https://api.github.com/users/ostcar","html_url":"https://github.com/ostcar","followers_url":"https://api.github.com/users/ostcar/followers","following_url":"https://api.github.com/users/ostcar/following{/other_user}","gists_url":"https://api.github.com/users/ostcar/gists{/gist_id}","starred_url":"https://api.github.com/users/ostcar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ostcar/subscriptions","organizations_url":"https://api.github.com/users/ostcar/orgs","repos_url":"https://api.github.com/users/ostcar/repos","events_url":"https://api.github.com/users/ostcar/events{/privacy}","received_events_url":"https://api.github.com/users/ostcar/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/OpenSlides/OpenSlides/milestones/17","html_url":"https://github.com/OpenSlides/OpenSlides/milestones/2.0","labels_url":"https://api.github.com/repos/OpenSlides/OpenSlides/milestones/17/labels","id":720870,"number":17,"title":"2.0","description":"We think we are ready not before May 2015.","creator":{"login":"normanjaeckel","id":2073844,"avatar_url":"https://avatars.githubusercontent.com/u/2073844?v=3","gravatar_id":"","url":"https://api.github.com/users/normanjaeckel","html_url":"https://github.com/normanjaeckel","followers_url":"https://api.github.com/users/normanjaeckel/followers","following_url":"https://api.github.com/users/normanjaeckel/following{/other_user}","gists_url":"https://api.github.com/users/normanjaeckel/gists{/gist_id}","starred_url":"https://api.github.com/users/normanjaeckel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanjaeckel/subscriptions","organizations_url":"https://api.github.com/users/normanjaeckel/orgs","repos_url":"https://api.github.com/users/normanjaeckel/repos","events_url":"https://api.github.com/users/normanjaeckel/events{/privacy}","received_events_url":"https://api.github.com/users/normanjaeckel/received_events","type":"User","site_admin":false},"open_issues":61,"closed_issues":94,"state":"open","created_at":"2014-07-14T20:36:14Z","updated_at":"2015-04-15T21:47:01Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512/commits","review_comments_url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512/comments","review_comment_url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/comments{/number}","comments_url":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/1512/comments","statuses_url":"https://api.github.com/repos/OpenSlides/OpenSlides/statuses/e0973cb11061e8eb6cf10e182d1239db9157e301","head":{"label":"normanjaeckel:AssignmentRESTAPIChanges","ref":"AssignmentRESTAPIChanges","sha":"e0973cb11061e8eb6cf10e182d1239db9157e301","user":{"login":"normanjaeckel","id":2073844,"avatar_url":"https://avatars.githubusercontent.com/u/2073844?v=3","gravatar_id":"","url":"https://api.github.com/users/normanjaeckel","html_url":"https://github.com/normanjaeckel","followers_url":"https://api.github.com/users/normanjaeckel/followers","following_url":"https://api.github.com/users/normanjaeckel/following{/other_user}","gists_url":"https://api.github.com/users/normanjaeckel/gists{/gist_id}","starred_url":"https://api.github.com/users/normanjaeckel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanjaeckel/subscriptions","organizations_url":"https://api.github.com/users/normanjaeckel/orgs","repos_url":"https://api.github.com/users/normanjaeckel/repos","events_url":"https://api.github.com/users/normanjaeckel/events{/privacy}","received_events_url":"https://api.github.com/users/normanjaeckel/received_events","type":"User","site_admin":false},"repo":{"id":5361084,"name":"OpenSlides","full_name":"normanjaeckel/OpenSlides","owner":{"login":"normanjaeckel","id":2073844,"avatar_url":"https://avatars.githubusercontent.com/u/2073844?v=3","gravatar_id":"","url":"https://api.github.com/users/normanjaeckel","html_url":"https://github.com/normanjaeckel","followers_url":"https://api.github.com/users/normanjaeckel/followers","following_url":"https://api.github.com/users/normanjaeckel/following{/other_user}","gists_url":"https://api.github.com/users/normanjaeckel/gists{/gist_id}","starred_url":"https://api.github.com/users/normanjaeckel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanjaeckel/subscriptions","organizations_url":"https://api.github.com/users/normanjaeckel/orgs","repos_url":"https://api.github.com/users/normanjaeckel/repos","events_url":"https://api.github.com/users/normanjaeckel/events{/privacy}","received_events_url":"https://api.github.com/users/normanjaeckel/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/normanjaeckel/OpenSlides","description":"","fork":true,"url":"https://api.github.com/repos/normanjaeckel/OpenSlides","forks_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/forks","keys_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/keys{/key_id}","collaborators_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/teams","hooks_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/hooks","issue_events_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/issues/events{/number}","events_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/events","assignees_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/assignees{/user}","branches_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/branches{/branch}","tags_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/tags","blobs_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/git/refs{/sha}","trees_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/git/trees{/sha}","statuses_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/statuses/{sha}","languages_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/languages","stargazers_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/stargazers","contributors_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/contributors","subscribers_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/subscribers","subscription_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/subscription","commits_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/commits{/sha}","git_commits_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/git/commits{/sha}","comments_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/comments{/number}","issue_comment_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/issues/comments{/number}","contents_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/contents/{+path}","compare_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/compare/{base}...{head}","merges_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/merges","archive_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/downloads","issues_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/issues{/number}","pulls_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/pulls{/number}","milestones_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/milestones{/number}","notifications_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/labels{/name}","releases_url":"https://api.github.com/repos/normanjaeckel/OpenSlides/releases{/id}","created_at":"2012-08-09T20:52:48Z","updated_at":"2015-03-24T15:07:25Z","pushed_at":"2015-04-13T18:05:29Z","git_url":"git://github.com/normanjaeckel/OpenSlides.git","ssh_url":"git@github.com:normanjaeckel/OpenSlides.git","clone_url":"https://github.com/normanjaeckel/OpenSlides.git","svn_url":"https://github.com/normanjaeckel/OpenSlides","homepage":"http://openslides.org","size":37678,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"OpenSlides:master","ref":"master","sha":"1bc6aef205df573177cd1ff290a86eec2a56ca3b","user":{"login":"OpenSlides","id":2055730,"avatar_url":"https://avatars.githubusercontent.com/u/2055730?v=3","gravatar_id":"","url":"https://api.github.com/users/OpenSlides","html_url":"https://github.com/OpenSlides","followers_url":"https://api.github.com/users/OpenSlides/followers","following_url":"https://api.github.com/users/OpenSlides/following{/other_user}","gists_url":"https://api.github.com/users/OpenSlides/gists{/gist_id}","starred_url":"https://api.github.com/users/OpenSlides/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OpenSlides/subscriptions","organizations_url":"https://api.github.com/users/OpenSlides/orgs","repos_url":"https://api.github.com/users/OpenSlides/repos","events_url":"https://api.github.com/users/OpenSlides/events{/privacy}","received_events_url":"https://api.github.com/users/OpenSlides/received_events","type":"Organization","site_admin":false},"repo":{"id":5250779,"name":"OpenSlides","full_name":"OpenSlides/OpenSlides","owner":{"login":"OpenSlides","id":2055730,"avatar_url":"https://avatars.githubusercontent.com/u/2055730?v=3","gravatar_id":"","url":"https://api.github.com/users/OpenSlides","html_url":"https://github.com/OpenSlides","followers_url":"https://api.github.com/users/OpenSlides/followers","following_url":"https://api.github.com/users/OpenSlides/following{/other_user}","gists_url":"https://api.github.com/users/OpenSlides/gists{/gist_id}","starred_url":"https://api.github.com/users/OpenSlides/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OpenSlides/subscriptions","organizations_url":"https://api.github.com/users/OpenSlides/orgs","repos_url":"https://api.github.com/users/OpenSlides/repos","events_url":"https://api.github.com/users/OpenSlides/events{/privacy}","received_events_url":"https://api.github.com/users/OpenSlides/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OpenSlides/OpenSlides","description":"Presentation and assembly system","fork":false,"url":"https://api.github.com/repos/OpenSlides/OpenSlides","forks_url":"https://api.github.com/repos/OpenSlides/OpenSlides/forks","keys_url":"https://api.github.com/repos/OpenSlides/OpenSlides/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OpenSlides/OpenSlides/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OpenSlides/OpenSlides/teams","hooks_url":"https://api.github.com/repos/OpenSlides/OpenSlides/hooks","issue_events_url":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/events{/number}","events_url":"https://api.github.com/repos/OpenSlides/OpenSlides/events","assignees_url":"https://api.github.com/repos/OpenSlides/OpenSlides/assignees{/user}","branches_url":"https://api.github.com/repos/OpenSlides/OpenSlides/branches{/branch}","tags_url":"https://api.github.com/repos/OpenSlides/OpenSlides/tags","blobs_url":"https://api.github.com/repos/OpenSlides/OpenSlides/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OpenSlides/OpenSlides/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OpenSlides/OpenSlides/git/refs{/sha}","trees_url":"https://api.github.com/repos/OpenSlides/OpenSlides/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OpenSlides/OpenSlides/statuses/{sha}","languages_url":"https://api.github.com/repos/OpenSlides/OpenSlides/languages","stargazers_url":"https://api.github.com/repos/OpenSlides/OpenSlides/stargazers","contributors_url":"https://api.github.com/repos/OpenSlides/OpenSlides/contributors","subscribers_url":"https://api.github.com/repos/OpenSlides/OpenSlides/subscribers","subscription_url":"https://api.github.com/repos/OpenSlides/OpenSlides/subscription","commits_url":"https://api.github.com/repos/OpenSlides/OpenSlides/commits{/sha}","git_commits_url":"https://api.github.com/repos/OpenSlides/OpenSlides/git/commits{/sha}","comments_url":"https://api.github.com/repos/OpenSlides/OpenSlides/comments{/number}","issue_comment_url":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/comments{/number}","contents_url":"https://api.github.com/repos/OpenSlides/OpenSlides/contents/{+path}","compare_url":"https://api.github.com/repos/OpenSlides/OpenSlides/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OpenSlides/OpenSlides/merges","archive_url":"https://api.github.com/repos/OpenSlides/OpenSlides/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OpenSlides/OpenSlides/downloads","issues_url":"https://api.github.com/repos/OpenSlides/OpenSlides/issues{/number}","pulls_url":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls{/number}","milestones_url":"https://api.github.com/repos/OpenSlides/OpenSlides/milestones{/number}","notifications_url":"https://api.github.com/repos/OpenSlides/OpenSlides/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OpenSlides/OpenSlides/labels{/name}","releases_url":"https://api.github.com/repos/OpenSlides/OpenSlides/releases{/id}","created_at":"2012-07-31T20:04:39Z","updated_at":"2015-04-01T20:16:12Z","pushed_at":"2015-04-17T10:21:02Z","git_url":"git://github.com/OpenSlides/OpenSlides.git","ssh_url":"git@github.com:OpenSlides/OpenSlides.git","clone_url":"https://github.com/OpenSlides/OpenSlides.git","svn_url":"https://github.com/OpenSlides/OpenSlides","homepage":"http://openslides.org","size":39473,"stargazers_count":63,"watchers_count":63,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":31,"mirror_url":null,"open_issues_count":120,"forks":31,"open_issues":120,"watchers":63,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512"},"html":{"href":"https://github.com/OpenSlides/OpenSlides/pull/1512"},"issue":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/1512"},"comments":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/issues/1512/comments"},"review_comments":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512/comments"},"review_comment":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/pulls/1512/commits"},"statuses":{"href":"https://api.github.com/repos/OpenSlides/OpenSlides/statuses/e0973cb11061e8eb6cf10e182d1239db9157e301"}}}}