def add_or_update(request, election=None): user = request.admin institution = user.institution if request.method == "GET": election_form = ElectionForm(user, institution, instance=election, lang=request.LANGUAGE_CODE) else: election_form = ElectionForm(user, institution, request.POST, instance=election) if election_form.is_valid(): creating = election is None with transaction.atomic(): election = election_form.save() if not election.admins.filter(pk=user.pk).count(): election.admins.add(user) if election_form.creating: election.logger.info("Election created") msg = "New election created" subject = "New Zeus election" election.notify_admins(msg=msg, subject=subject) if not election.has_helios_trustee(): election.generate_trustee() if election.polls.count() == 0: url = election_reverse(election, 'polls_add') else: url = election_reverse(election, 'index') if election.voting_extended_until: subject = "Voting extension" msg = "Voting end date extended" election.notify_admins(msg=msg, subject=subject) election.zeus.compute_election_public() election.logger.info("Public key updated") hook_url = None if creating: hook_url = election.get_module().run_hook('post_create') else: hook_url = election.get_module().run_hook('post_update') return HttpResponseRedirect(hook_url or url) context = {'election_form': election_form, 'election': election} set_menu('election_edit', context) tpl = "election_new" if election and election.pk: tpl = "election_edit" return render_template(request, tpl, context)
def add_edit(request, election, poll=None): if not poll and not election.feature_can_add_poll: raise PermissionDenied if poll and not poll.feature_can_edit: raise PermissionDenied if election.linked_polls and 'batch_file' in request.FILES: return _add_batch(request, election) if poll: oldname = poll.name if request.method == "POST": form = PollForm(request.POST, instance=poll, election=election) if form.is_valid(): new_poll = form.save() if form.has_changed(): new_poll.logger.info("Poll updated %r" % form.changed_data) message = _("Poll updated successfully") messages.success(request, message) newname = new_poll.name # log poll edit/creation if poll: if oldname != newname: poll.logger.info("Renamed from %s to %s", oldname, newname) else: new_poll.logger.info("Poll created") url = election_reverse(election, 'polls_list') return redirect(url) if request.method == "GET": form = PollForm(instance=poll, election=election) context = {'election': election, 'poll': poll, 'form': form} set_menu('polls', context) if poll: set_menu('edit_poll', context) tpl = "election_poll_add_or_edit" return render_template(request, tpl, context)
def login(request, election, trustee_email, trustee_secret): trustee = get_object_or_404(Trustee, election=election, email=trustee_email) if not trustee: raise PermissionDenied("Invalid election") if trustee_secret == trustee.secret: user = auth.ZeusUser(trustee) if request.zeususer.is_authenticated() and ( not request.zeususer.is_trustee or request.zeususer._user.pk != trustee.pk): messages.error( request, _("You need to logout from your current account " "to access this view.")) return HttpResponseRedirect(reverse('error', kwargs={'code': 403})) user.authenticate(request) election.logger.info("Trustee %r logged in", trustee.email) return HttpResponseRedirect( reverse('election_trustee_home', args=[election.uuid])) else: url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def home(request, election, trustee): context = {'election': election, 'trustee': trustee} if not trustee.public_key: url = election_reverse(election, 'trustee_keygen') return HttpResponseRedirect(url) set_menu('trustee', context) return render_template(request, 'election_trustee_home', context)
def endnow(request, election): if election.voting_extended_until: election.voting_extended_until = datetime.datetime.now() else: election.voting_ends_at = datetime.datetime.now() election.save() election.logger.info("Changed election dates to be able to close voting") url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def trustee_delete(request, election, trustee_uuid): election.zeus.invalidate_election_public() trustee = election.trustees.get(uuid=trustee_uuid) trustee.delete() election.logger.info("Trustee %r deleted", trustee.email) election.zeus.compute_election_public() election.logger.info("Public key updated") url = election_reverse(election, 'trustees_list') return HttpResponseRedirect(url)
def _add_batch(request, election): batch_file = request.FILES['batch_file'] try: data = yaml.safe_load(batch_file) except Exception: messages.error(request, _("Invalid batch file contents")) url = election_reverse(election, 'polls_list') return HttpResponseRedirect(url) try: _handle_batch(election, data.get('polls'), data.get('vars', {}), data.get('auto_link', False)) except Exception as e: logging.exception(e) election.logger.exception(e) messages.error(request, str(e)) url = election_reverse(election, 'polls_list') return HttpResponseRedirect(url)
def results(request, election, poll): if not request.zeususer.is_admin and not poll.feature_public_results: raise PermissionDenied('41') if not poll.get_module().display_poll_results: url = election_reverse(election, 'index') return HttpResponseRedirect(url) context = {'poll': poll, 'election': election} set_menu('results', context) return render_template(request, 'election_poll_results', context)
def cancel(request, election): cancel_msg = request.POST.get('cancel_msg', '') cancel_date = datetime.datetime.now() election.canceled_at = cancel_date election.cancelation_reason = cancel_msg election.completed_at = cancel_date election.save() url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def freeze(request, election): election.logger.info("Starting to freeze") tasks.election_validate_create(election.id) # hacky delay. Hopefully validate create task will start running # before the election view redirect. if not settings.CELERY_TASK_ALWAYS_EAGER: import time time.sleep(getattr(settings, 'ZEUS_ELECTION_FREEZE_DELAY', 4)) url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def post_create(self, election): # create the two polls poll = election.polls.create(name=str(_("Electors: Group A")), oauth2_type='', oauth2_code_url='', oauth2_client_secret='', oauth2_client_type='', oauth2_confirmation_url='', oauth2_exchange_url='', oauth2_client_id='', jwt_public_key='') election.polls.create(name=str(_("Electors: Group B"))) return election_reverse(election, 'polls_list')
def close_mixing(request, election): election.logger.info("Closing remote mixes") election.remote_mixing_finished_at = datetime.datetime.now() election.save() tasks.election_validate_mixing(election.id) # hacky delay. Hopefully validate create task will start running # before the election view redirect. import time time.sleep(getattr(settings, 'ZEUS_ELECTION_FREEZE_DELAY', 4)) url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def recompute_results(request, election): election.compute_results_started_at = None election.compute_results_finished_at = None election.compute_results_status = 'waiting' election.completed_at = None election.save() for poll in election.polls.all(): poll.compute_results_started_at = None poll.compute_results_finished_at = None poll.compute_results_status = 'waiting' poll.save() transaction.on_commit(lambda: poll_compute_results.delay(poll.pk)) url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def post_create(self, election): # create the two polls poll = election.polls.create( name=unicode(_("Electors: Group A")), oauth2_type=u'', oauth2_code_url=u'', oauth2_client_secret=u'', oauth2_client_type=u'', oauth2_confirmation_url=u'', oauth2_exchange_url=u'', oauth2_client_id=u'', jwt_public_key=u'' ) election.polls.create(name=unicode(_("Electors: Group B"))) return election_reverse(election, 'polls_list')
def voters_email(request, election, poll=None, voter_uuid=None): user = request.admin TEMPLATES = [ ('vote', _('Time to Vote')), ('info', _('Additional Info')), ] default_template = 'vote' if not election.any_poll_feature_can_send_voter_mail: raise PermissionDenied('34') if not election.any_poll_feature_can_send_voter_booth_invitation: TEMPLATES.pop(0) default_template = 'info' polls = [poll] if not poll: polls = election.polls_by_link_id voter = None if voter_uuid: try: if poll: voter = get_object_or_404(Voter, uuid=voter_uuid, poll=poll) else: voter = get_object_or_404(Voter, uuid=voter_uuid, election=election) except Voter.DoesNotExist: raise PermissionDenied('35') if not voter: url = election_reverse(election, 'index') return HttpResponseRedirect(url) if voter.excluded_at: TEMPLATES.pop(0) default_template = 'info' if election.voting_extended_until and not election.voting_ended_at: if not voter or (voter and not voter.excluded_at): TEMPLATES.append(('extension', _('Voting end date extended'))) if request.method == 'POST': template = request.POST.get('template', default_template) else: template = request.GET.get('template', default_template) if template not in [t[0] for t in TEMPLATES]: raise Exception("bad template") election_url = election.get_absolute_url() default_subject = render_to_string('email/%s_subject.txt' % template, {'custom_subject': "<SUBJECT>"}) tpl_context = { 'election': election, 'election_url': election_url, 'custom_subject': default_subject, 'custom_message': '<BODY>', 'custom_message_sms': '<SMS_BODY>', 'SECURE_URL_HOST': settings.SECURE_URL_HOST, 'voter': { 'vote_hash': '<SMART_TRACKER>', 'name': '<VOTER_NAME>', 'voter_name': '<VOTER_NAME>', 'voter_surname': '<VOTER_SURNAME>', 'voter_login_id': '<VOTER_LOGIN_ID>', 'voter_password': '******', 'login_code': '<VOTER_LOGIN_CODE>', 'audit_passwords': '1', 'get_audit_passwords': ['pass1', 'pass2', '...'], 'get_quick_login_url': '<VOTER_LOGIN_URL>', 'poll': poll, 'election': election } } default_body = render_to_string('email/%s_body.txt' % template, tpl_context) default_sms_body = render_to_string('sms/%s_body.txt' % template, tpl_context) q_param = request.GET.get('q', None) filtered_voters = election.voters.filter() if poll: filtered_voters = poll.voters.filter() if not q_param: filtered_voters = filtered_voters.none() else: filtered_voters = election.get_module().filter_voters( filtered_voters, q_param, request) if not filtered_voters.count(): message = _("No voters were found.") messages.error(request, message) url = election_reverse(election, 'polls_list') return HttpResponseRedirect(url) if request.method == "GET": email_form = EmailVotersForm(election, template) email_form.fields['email_subject'].initial = dict(TEMPLATES)[template] if voter: email_form.fields['send_to'].widget = \ email_form.fields['send_to'].hidden_widget() else: email_form = EmailVotersForm(election, template, request.POST) if email_form.is_valid(): # the client knows to submit only once with a specific voter_id voter_constraints_include = None voter_constraints_exclude = None update_booth_invitation_date = False if template == 'vote': update_booth_invitation_date = True if voter: voter_constraints_include = {'uuid': voter.uuid} # exclude those who have not voted if email_form.cleaned_data['send_to'] == 'voted': voter_constraints_exclude = {'vote_hash': None} # include only those who have not voted if email_form.cleaned_data['send_to'] == 'not-voted': voter_constraints_include = {'vote_hash': None} for _poll in polls: if not _poll.feature_can_send_voter_mail: continue if template == 'vote' and not \ _poll.feature_can_send_voter_booth_invitation: continue subject_template = 'email/%s_subject.txt' % template body_template = 'email/%s_body.txt' % template body_template_sms = 'sms/%s_body.txt' % template contact_method = email_form.cleaned_data['contact_method'] extra_vars = { 'SECURE_URL_HOST': settings.SECURE_URL_HOST, 'custom_subject': email_form.cleaned_data['email_subject'], 'custom_message': email_form.cleaned_data['email_body'], 'custom_message_sms': email_form.cleaned_data['sms_body'], 'election_url': election_url, } task_kwargs = { 'contact_id': template, 'notify_once': email_form.cleaned_data.get('notify_once'), 'subject_template_email': subject_template, 'body_template_email': body_template, 'body_template_sms': body_template_sms, 'contact_methods': contact_method.split(":"), 'template_vars': extra_vars, 'voter_constraints_include': voter_constraints_include, 'voter_constraints_exclude': voter_constraints_exclude, 'update_date': True, 'update_booth_invitation_date': update_booth_invitation_date, 'q_param': q_param, } log_obj = election if poll: log_obj = poll if voter: log_obj.logger.info( "Notifying single voter %s, [template: %s, filter: %s]", voter.voter_login_id, template, q_param) else: log_obj.logger.info( "Notifying voters, [template: %s, filter: %r]", template, q_param) tasks.voters_email.delay(_poll.pk, **task_kwargs) filters = get_voters_filters_with_constraints( q_param, voter_constraints_include, voter_constraints_exclude) send_to = filtered_voters.filter(filters) if q_param and not send_to.filter(filters).count(): msg = "No voters matched your filters. No emails were sent." messages.error(request, _(msg)) else: messages.info(request, _("Email sending started")) url = election_reverse(election, 'polls_list') if poll: url = poll_reverse(poll, 'voters') if q_param: url += '?q=%s' % six.moves.urllib.parse.quote_plus(q_param) return HttpResponseRedirect(url) else: message = _("Something went wrong") messages.error(request, message) if election.sms_enabled and election.sms_data.left <= 0: messages.warning(request, _("No SMS deliveries left.")) context = { 'email_form': email_form, 'election': election, 'poll': poll, 'voter_o': voter, 'default_subject': default_subject, 'default_body': default_body, 'default_sms_body': default_sms_body, 'sms_enabled': election.sms_enabled, 'template': template, 'filtered_voters': filtered_voters, 'templates': TEMPLATES } set_menu('voters', context) if not poll: set_menu('polls', context) return render_template(request, "voters_email", context)
def remove(request, election, poll): poll.delete() poll.logger.info("Poll deleted") return HttpResponseRedirect(election_reverse(election, 'polls_list'))
def close(request, election): election.close_voting() tasks.election_validate_voting(election.pk) url = election_reverse(election, 'index') return HttpResponseRedirect(url)
def trustee_send_url(request, election, trustee_uuid): trustee = election.trustees.get(uuid=trustee_uuid) trustee.send_url_via_mail() url = election_reverse(election, 'trustees_list') messages.success(request, _("Trustee login url sent")) return HttpResponseRedirect(url)
def start_mixing(request, election): tasks.start_mixing.delay(election_id=election.id) url = election_reverse(election, 'index') return HttpResponseRedirect(url)