diff --git a/auth/auth_systems/facebook.py b/auth/auth_systems/facebook.py index 7ace5cb0900150a47a40f99362ec0a6784483932..7951197f051fbabf6900653c6f42204fdc6f2f91 100644 --- a/auth/auth_systems/facebook.py +++ b/auth/auth_systems/facebook.py @@ -85,7 +85,7 @@ def get_user_groups(user): def check_constraint(constraint, user): # get the groups for the user - groups = [group['id'] for group in get_user_groups(user.token)] + groups = [group['id'] for group in get_user_groups(user)] # check if one of them is the group in the constraint try: diff --git a/helios/fixtures/users.json b/helios/fixtures/users.json index e66e46d1db2b33cdf3ca21b0db6a00e4fde07b26..62f2a32e72d41064841bb3cf221e154bb820e873 100644 --- a/helios/fixtures/users.json +++ b/helios/fixtures/users.json @@ -1 +1 @@ -[{"pk": 1, "model": "auth.user", "fields": {"info": "{}", "user_id": "ben@adida.net", "name": "Ben Adida", "user_type": "google", "token": null, "admin_p": false}}] \ No newline at end of file +[{"pk": 1, "model": "auth.user", "fields": {"info": "{}", "user_id": "ben@adida.net", "name": "Ben Adida", "user_type": "google", "token": null, "admin_p": false}},{"pk": 2, "model": "auth.user", "fields": {"info": "{}", "user_id": "12345", "name": "Ben Adida", "user_type": "facebook", "token": {"access_token":"1234"}, "admin_p": false}}] \ No newline at end of file diff --git a/helios/models.py b/helios/models.py index f0ca2468eebae6411b159cc0b929a0a8f9e43313..9841a773e566981d01fda3222ff2cb4713646535 100644 --- a/helios/models.py +++ b/helios/models.py @@ -255,7 +255,7 @@ class Election(HeliosModel): if not self.eligibility: return "Everyone can vote." else: - return_val = "Only the following users can vote:<ul>" + return_val = "<ul>" for constraint in self.eligibility: for one_constraint in constraint['constraint']: diff --git a/helios/templates/election_view.html b/helios/templates/election_view.html index f0d856e060dfefad2050b3e57130e6a08e2c8805..78beb63402a03d3725a46858636a9b9ee80a8c5a 100644 --- a/helios/templates/election_view.html +++ b/helios/templates/election_view.html @@ -229,27 +229,24 @@ Your voter alias is {{voter.alias}}. {% else %} {% if election.openreg %} {% if eligible_p %} -{% if election.voting_has_started %} -This {{election.election_type}} is open to anyone. -{% else %} -You are <em>not</em> registered to vote in this {{election.election_type}}.<br /> -<form method="post" action="{% url helios.views.one_election_register election.uuid %}"> -<input type="hidden" name="csrf_token" value="{{csrf_token}}" /> -<input type="submit" value="register!" /> -</form> -{% endif %} +You are eligible to vote in this election. {% else %} -Registration for this {{election.election_type}} is open, but You are <em>not eligible</em>. +You are <em>not eligible</em> to vote in this {{election.election_type}}. {% endif %} {% else %} -You are <em>not eligible</em> to vote in this {{election.election_type}}, because registration is closed and you are not registered.<br /> +You are <em>not eligible</em> to vote in this {{election.election_type}}. +<br /> {% endif %} {% endif %} {% endif %} {% else %} {% if election.openreg %} -Anyone can register for this election. <a href="{{settings.SECURE_URL_HOST}}{% url auth.views.index %}?return_url={{CURRENT_URL}}">Log in</a> and register! +{% if election.eligibility %} +This election is open to: {{election.pretty_eligibility|safe}}. <a href="{{settings.SECURE_URL_HOST}}{% url auth.views.index %}?return_url={{CURRENT_URL}}">Log in</a> to check your eligibility. +{% else %} +Anyone can vote in this election. +{% endif %} {% endif %} {% endif %} diff --git a/helios/templates/voters_list.html b/helios/templates/voters_list.html index 6bdd14fa7f259a6033d260a46edc49e172c68e3c..fba557f6ebcbd2ed72f76627ab6aa31b0dcd09ba 100644 --- a/helios/templates/voters_list.html +++ b/helios/templates/voters_list.html @@ -5,30 +5,36 @@ <h2 class="title">{{election.name}} — Voters and Ballot Tracking Center <span style="font-size:0.7em;">[<a href="{% url helios.views.one_election_view election.uuid %}">back to election</a>]</span></h2> <p> -<u>Registration</u> is {% if not election.frozen_at %}currently{% endif %} <b>{{ election.registration_status_pretty }}</b>. -{% if admin_p and not election.frozen_at %} +<b>Who can vote?</b> {% if election.openreg %} -[<a href="{% url helios.views.one_election_set_reg election.uuid %}?open_p=0">switch to closed</a>] - -{% if can_set_eligibility %} -<p> -<em>{{election.pretty_eligibility|safe}}</em> -<br /> -You can <a href="{% url helios.views.voters_eligibility election.uuid %}">limit the eligibility</a> of voters based on their {{user.user_type}} credentials. -</p> +{{election.pretty_eligibility|safe}} +{% else %} +<em>Only the voters listed here</em>. {% endif %} +</p> - -{% else %} +{% if admin_p and not election.frozen_at %} {% if election.private_p %} -<br /> -Your election is marked private: registration can be opened to the public only for public elections. +<em>Your election is marked private, which means you cannot open registration up more widely</em>.<br /> {% else %} -[<a href="{% url helios.views.one_election_set_reg election.uuid %}?open_p=1">switch to open</a>] +You can change this setting: +<form method="post" action="{% url helios.views.voters_eligibility election.uuid %}"> +<input type="hidden" name="csrf_token" value="{{csrf_token}}" /> +<input type="radio" name="eligibility" value="openreg" {% if election.openreg and not election.eligibility %}CHECKED{% endif %} /> anyone can vote<br /> +<input type="radio" name="eligibility" value="closedreg" {% if not election.openreg %}CHECKED{% endif %} /> only voters listed explicitly below can vote<br /> +{% if categories %} +<input type="radio" name="eligibility" value="limitedreg" {% if election.eligibility %}CHECKED{% endif %} /> only voters who are members of +<select name="category_id"> +{% for category in categories %} +<option value="{{category.id}}"> {{category.name}}</option> +{% endfor %} +</select> +<br /> {% endif %} +<input type="submit" value="update" /> +</form> {% endif %} {% endif %} -</p> {% if email_voters and election.frozen_at and admin_p %} <p><a href="{% url helios.views.voters_email election.uuid %}">email voters</a></p> @@ -46,7 +52,7 @@ Your election is marked private: registration can be opened to the public only f {% if admin_p %} <!-- Add a Voter: WORK HERE--> -{% if upload_p %} +{% if upload_p and not election.openreg %} <p> <a href="{% url helios.views.voters_upload election_uuid=election.uuid %}">bulk upload voters</a> </p> @@ -125,6 +131,7 @@ Voters {{voters_page.start_index}} - {{voters_page.end_index}} (of {{total_voter </table> {% else %} +<br /><br /> <em>no voters.</em> {% endif %} diff --git a/helios/tests.py b/helios/tests.py index 91a414f29ec7b76dcff8835ce607f3e6e7dac24d..61ccfa6debd9ebd05d23b2a6de819e4c5e6da86f 100644 --- a/helios/tests.py +++ b/helios/tests.py @@ -49,6 +49,7 @@ class ElectionModelTests(TestCase): def setUp(self): self.user = auth_models.User.objects.get(user_id='ben@adida.net', user_type='google') + self.fb_user = auth_models.User.objects.get(user_type='facebook') self.election, self.created_p = self.create_election() def test_create_election(self): @@ -147,6 +148,24 @@ class ElectionModelTests(TestCase): # without openreg, and now true self.assertTrue(self.election.user_eligible_p(self.user)) + def test_facebook_eligibility(self): + self.election.eligibility = [{'auth_system': 'facebook', 'constraint':[{'group': {'id': '123', 'name':'Fake Group'}}]}] + + # without openreg, this should be false + self.assertFalse(self.election.user_eligible_p(self.fb_user)) + + self.election.openreg = True + + # fake out the facebook constraint checking, since + # our access_token is obviously wrong + from auth.auth_systems import facebook + + def fake_check_constraint(constraint, user): + return constraint == {'group': {'id': '123', 'name':'Fake Group'}} and user == self.fb_user + facebook.check_constraint = fake_check_constraint + + self.assertTrue(self.election.user_eligible_p(self.fb_user)) + def test_freeze(self): # freezing without trustees and questions, no good def try_freeze(): @@ -670,6 +689,36 @@ class ElectionBlackboxTests(WebTest): self._cast_ballot(election_id, username, password, need_login = False) self._do_tally(election_id) + def test_election_voters_eligibility(self): + # create the election + self.client.get("/") + self.setup_login() + response = self.app.post("/helios/elections/new", { + "short_name" : "test-eligibility", + "name" : "Test Eligibility", + "description" : "An election test for voter eligibility", + "election_type" : "election", + "use_voter_aliases": "0", + "use_advanced_audit_features": "1", + "private_p" : "0"}) + + election_id = re.match("(.*)/elections/(.*)/view", response.location).group(2) + + # get the eligibility page + eligibility_page = self.app.get("/helios/elections/%s/voters/list" % election_id) + + elig_form = eligibility_page.form + elig_form['eligibility'] = 'openreg' + elig_page = elig_form.submit().follow() + + self.assertContains(elig_page, "Everyone can vote") + + elig_form = elig_page.form + elig_form['eligibility'] = 'closedreg' + elig_page = elig_form.submit().follow() + + self.assertContains(elig_page, "Only the voters listed here") + def test_do_complete_election_with_trustees(self): """ FIXME: do the this test diff --git a/helios/views.py b/helios/views.py index 2a82eae8de22d6dcd982774d8d2280b6134a7bd6..169d9c43d46012ee798d4d5eca2c1e3ae4657b32 100644 --- a/helios/views.py +++ b/helios/views.py @@ -1114,10 +1114,9 @@ def voters_list_pretty(request, election): user = get_user(request) admin_p = security.user_can_admin_election(user, election) - if admin_p and election.openreg: - can_set_eligibility = can_list_categories(user.user_type) - else: - can_set_eligibility = False + categories = None + if admin_p and can_list_categories(user.user_type): + categories = AUTH_SYSTEMS[user.user_type].list_categories(user) # files being processed voter_files = election.voterfile_set.all() @@ -1144,34 +1143,43 @@ def voters_list_pretty(request, election): 'limit': limit, 'total_voters': total_voters, 'upload_p': helios.VOTERS_UPLOAD, 'q' : q, 'voter_files': voter_files, - 'can_set_eligibility': can_set_eligibility}) + 'categories': categories}) @election_admin() def voters_eligibility(request, election): + """ + set eligibility for voters + """ user = get_user(request) - if not can_list_categories(user.user_type): + if request.method == "GET": + # this shouldn't happen, only POSTs + return HttpResponseRedirect("/") + + # for now, private elections cannot change eligibility + if election.private_p: return HttpResponseRedirect(reverse(voters_list_pretty, args=[election.uuid])) - if request.method == "GET": - categories = AUTH_SYSTEMS[user.user_type].list_categories(user) + # eligibility + eligibility = request.POST['eligibility'] + + if eligibility in ['openreg', 'limitedreg']: + election.openreg= True - return render_template(request, 'voters_eligibility', - {'categories' : categories, 'election': election}) + if eligibility == 'closedreg': + election.openreg= False - # now process the constraint - category_id = request.POST['category_id'] - if category_id == "": - category_id = None + if eligibility == 'limitedreg': + # now process the constraint + category_id = request.POST['category_id'] - if category_id: constraint = AUTH_SYSTEMS[user.user_type].generate_constraint(category_id, user) election.eligibility = [{'auth_system': user.user_type, 'constraint': [constraint]}] else: election.eligibility = None - + election.save() - return HttpResponseRedirect(reverse(voters_eligibility, args=[election.uuid])) + return HttpResponseRedirect(reverse(voters_list_pretty, args=[election.uuid])) @election_admin() def voters_upload(request, election):