From 55a20a7426fc66c7d90e71957b61045383443e32 Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sat, 30 Mar 2024 18:08:14 +0200 Subject: [PATCH 1/6] fixed certain static issues and updated some lines to python 3 --- zeus/forms.py | 1243 +++++++++++++++++++++++++++---------------------- 1 file changed, 693 insertions(+), 550 deletions(-) diff --git a/zeus/forms.py b/zeus/forms.py index 33147e0f8..ba71768e8 100644 --- a/zeus/forms.py +++ b/zeus/forms.py @@ -3,7 +3,6 @@ Forms for Zeus """ import re -import uuid import copy import json import types @@ -12,28 +11,24 @@ from datetime import datetime, timedelta from django import forms -from django.core.urlresolvers import reverse from django.core.validators import URLValidator from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ -from django.contrib.admin import widgets -from django.db import transaction from django.conf import settings -from django.db.models import Q from django.utils.safestring import mark_safe from django.contrib.auth.hashers import check_password, make_password from django.forms.models import BaseModelFormSet -from django.forms.widgets import Select, MultiWidget, DateInput, TextInput,\ - HiddenInput +from django.forms.widgets import Select, MultiWidget, TextInput, HiddenInput from django.forms.formsets import BaseFormSet -from helios.models import Election, Poll, Trustee, Voter +from helios.models import Election, Poll, Voter from heliosauth.models import User -from zeus.utils import extract_trustees, election_trustees_to_text, resolve_terms_options +from zeus.utils import extract_trustees +from zeus.utils import election_trustees_to_text, resolve_terms_options from zeus.widgets import JqSplitDateTimeField, JqSplitDateTimeWidget from zeus import help_texts as help -from zeus.utils import undecalize, ordered_dict_prepend +from zeus.utils import ordered_dict_prepend from django.core.validators import validate_email from zeus.election_modules import ELECTION_MODULES_CHOICES @@ -49,22 +44,31 @@ "voting_extended_until", "description", "help_email", - "help_phone" + "help_phone", ] INVALID_CHAR_MSG = _("%s is not a valid character.") + def election_form_formfield_cb(f, **kwargs): - if f.name in ['voting_starts_at', 'voting_ends_at', - 'voting_extended_until', 'forum_starts_at', 'forum_ends_at', - 'forum_extended_until']: - widget = JqSplitDateTimeWidget(attrs={'date_class': 'datepicker', - 'time_class': 'timepicker'}) - return JqSplitDateTimeField(label=f.verbose_name, - initial=f.default, - widget=widget, - required=not f.blank, - help_text=f.help_text) + if f.name in [ + "voting_starts_at", + "voting_ends_at", + "voting_extended_until", + "forum_starts_at", + "forum_ends_at", + "forum_extended_until", + ]: + widget = JqSplitDateTimeWidget( + attrs={"date_class": "datepicker", "time_class": "timepicker"} + ) + return JqSplitDateTimeField( + label=f.verbose_name, + initial=f.default, + widget=widget, + required=not f.blank, + help_text=f.help_text, + ) return f.formfield() @@ -77,9 +81,8 @@ def setup_editable_fields(form, **value_overrides): FIELD_REQUIRED_FEATURES mapping which maps field names to model features. A field is editable only when all required model features resolve to True. """ - for name, features in form.FIELD_REQUIRED_FEATURES.iteritems(): - editable = all([form.instance.check_feature(f) for \ - f in features]) + for name, features in form.FIELD_REQUIRED_FEATURES.items(): + editable = all([form.instance.check_feature(f) for f in features]) field = form.fields.get(name) if not field: @@ -90,9 +93,9 @@ def setup_editable_fields(form, **value_overrides): def disable_field(field, name, form, value_overrides): widget = field.widget - widget.attrs['readonly'] = True - widget.attrs['disabled'] = True - field.disabled = True # Django 1.9 only + widget.attrs["readonly"] = True + widget.attrs["disabled"] = True + field.disabled = True # Django 1.9 only # creates a value_from_datadict which returns instance value instead # of form data one @@ -102,93 +105,114 @@ def readonly_value_from_datadict(self, *args, **kwargs): value = override(form) else: value = getattr(form.instance, name) - if hasattr(widget, 'decompress'): + if hasattr(widget, "decompress"): value = widget.decompress(value) return value - return types.MethodType(readonly_value_from_datadict, widget) - widget.__dict__['value_from_datadict'] = \ - _mk_readonly(widget, name, form, value_overrides.get(name, None)) + return types.MethodType(readonly_value_from_datadict, widget) + widget.__dict__["value_from_datadict"] = _mk_readonly( + widget, name, form, value_overrides.get(name, None) + ) def _mk_dummy_clean(form, name): def _dummy_clean(self, *args, **kwargs): return self.cleaned_data.get(name) + return types.MethodType(_dummy_clean, form) - form.__dict__['clean_%s' % name] = _mk_dummy_clean(form, name) + form.__dict__["clean_%s" % name] = _mk_dummy_clean(form, name) if isinstance(widget, forms.CheckboxInput): - widget.attrs['disabled'] = True + widget.attrs["disabled"] = True class ElectionForm(forms.ModelForm): formfield_callback = election_form_formfield_cb - trustees = forms.CharField(label=_('Trustees'), required=False, - widget=forms.Textarea, - help_text=help.trustees) - remote_mixes = forms.BooleanField(label=_('Multiple mixnets'), - required=False, - help_text=help.remote_mixes) - legal_representative = forms.CharField(label=_('Legal representative'), - required=True, - help_text=None) - terms_consent = forms.BooleanField(label=_('Terms consent'), - required=True, - help_text=None) + trustees = forms.CharField( + label=_("Trustees"), + required=False, + widget=forms.Textarea, + help_text=help.trustees, + ) + remote_mixes = forms.BooleanField( + label=_("Multiple mixnets"), required=False,help_text=help.remote_mixes + ) + legal_representative = forms.CharField( + label=_("Legal representative"), required=True, help_text=None + ) + terms_consent = forms.BooleanField( + label=_("Terms consent"), required=True, help_text=None + ) FIELD_REQUIRED_FEATURES = { - 'trustees': ['edit_trustees'], - 'name': ['edit_name'], - 'description': ['edit_description'], - 'election_module': ['edit_type'], - 'voting_starts_at': ['edit_voting_starts_at'], - 'voting_ends_at': ['edit_voting_ends_at'], - 'voting_extended_until': ['edit_voting_extended_until'], - 'remote_mixes': ['edit_remote_mixes'], - 'trial': ['edit_trial'], - 'departments': ['edit_departments'], - 'cast_consent_text': ['edit_cast_consent_text'], + "trustees": ["edit_trustees"], + "name": ["edit_name"], + "description": ["edit_description"], + "election_module": ["edit_type"], + "voting_starts_at": ["edit_voting_starts_at"], + "voting_ends_at": ["edit_voting_ends_at"], + "voting_extended_until": ["edit_voting_extended_until"], + "remote_mixes": ["edit_remote_mixes"], + "trial": ["edit_trial"], + "departments": ["edit_departments"], + "cast_consent_text": ["edit_cast_consent_text"], } class Meta: model = Election - fields = ('trial', 'election_module', 'name', 'description', - 'departments', 'voting_starts_at', 'voting_ends_at', - 'voting_extended_until', - 'trustees', 'help_email', 'help_phone', - 'communication_language', - 'sms_api_enabled', 'cast_consent_text') + fields = ( + "trial", + "election_module", + "name", + "description", + "departments", + "voting_starts_at", + "voting_ends_at", + "voting_extended_until", + "trustees", + "help_email", + "help_phone", + "communication_language", + "sms_api_enabled", + "cast_consent_text", + ) def __init__(self, owner, institution, *args, **kwargs): self.institution = institution self.owner = owner self.terms_text = None - if kwargs.get('lang'): - lang = kwargs.pop('lang') + if kwargs.get("lang"): + lang = kwargs.pop("lang") else: lang = None super(ElectionForm, self).__init__(*args, **kwargs) - choices = getattr(settings, 'LANGUAGES', []) - choices = map(lambda x: (x[0], _(x[1])), choices) + choices = getattr(settings, "LANGUAGES", []) + choices = [(x[0], _(x[1])) for x in choices] help_text = _("Set the language that will be used for email messages") - self.fields['communication_language'] = forms.ChoiceField(label= - _("Communication language"), - choices=choices, - initial=lang, - help_text = help_text) - #self.fields['linked_polls'].widget = forms.HiddenInput() + self.fields["communication_language"] = forms.ChoiceField( + label=_("Communication language"), + choices=choices, + initial=lang, + help_text=help_text, + ) + # self.fields['linked_polls'].widget = forms.HiddenInput() if owner.sms_data: - help_text = _("Notify voters using SMS (%d deliveries available for your account)") % owner.sms_data.left - self.fields['sms_api_enabled'] = forms.BooleanField( + help_text = ( + _("Notify voters using SMS (%d " + +"deliveries available for your account)") + % owner.sms_data.left + ) + self.fields["sms_api_enabled"] = forms.BooleanField( label=_("Mobile SMS notifications enabled"), initial=True, required=False, - help_text=help_text) + help_text=help_text, + ) else: - del self.fields['sms_api_enabled'] + del self.fields["sms_api_enabled"] self.creating = True self._initial_data = {} @@ -199,107 +223,123 @@ def __init__(self, owner, institution, *args, **kwargs): self._initial_data[field] = self.initial[field] self.creating = False election_owner = self.instance.admins.filter()[0] - # user-specific terms text terms_options = resolve_terms_options(election_owner) - self.terms_text = parse_markdown_unsafe(_(terms_options.get('terms_text'))) - self.fields['terms_consent'].help_text = self.terms_text + self.terms_text = parse_markdown_unsafe(_(terms_options.get("terms_text"))) + self.fields["terms_consent"].help_text = self.terms_text # terms consent is required and only available during election creation # otherwise, enforce value to True and disable the checkbox input if not self.creating: - self.fields['terms_consent'].widget.attrs['disabled'] = True - self.fields['terms_consent'].widget.attrs['checked'] = True - self.fields['terms_consent'].required = False - - if not terms_options.get('require_legal_representative'): - del self.fields['legal_representative'] + self.fields["terms_consent"].widget.attrs["disabled"] = True + self.fields["terms_consent"].widget.attrs["checked"] = True + self.fields["terms_consent"].required = False + + if not terms_options.get("require_legal_representative"): + del self.fields["legal_representative"] else: if not self.creating: - self.fields['legal_representative'].widget.attrs['disabled'] = True - self.fields['legal_representative'].required = False - self.fields['legal_representative'].initial = self.instance.legal_representative + self.fields["legal_representative"].widget.attrs["disabled"] = True + self.fields["legal_representative"].required = False + self.fields["legal_representative"].initial = ( + self.instance.legal_representative + ) eligible_types = owner.eligible_election_types if not self.creating and self.instance: eligible_types.add(self.instance.election_module) - eligible_types_choices = filter(lambda x: x[0] in eligible_types, - ELECTION_MODULES_CHOICES) + eligible_types_choices = [ + x for x in ELECTION_MODULES_CHOICES if x[0] in eligible_types + ] - self.fields['election_module'].choices = eligible_types_choices + self.fields["election_module"].choices = eligible_types_choices deps_labels = { - 'unicouncilsgr': unicode(_('Departments')), - 'stv': unicode(_('Constituencies')), + "unicouncilsgr": str(_("Departments")), + "stv": str(_("Constituencies")), } deps_help_texts = { - 'unicouncilsgr': unicode(_("University Schools. e.g." - "

School of Engineering
" - "School of Medicine
School of" - "Informatics
")), - 'stv': unicode(_("List of constituencies. e.g." - "

District A
" - "District B
District C" - "
")), + "unicouncilsgr": str( + _( + "University Schools. e.g." + "

School of Engineering
" + "School of Medicine
School of" + "Informatics
" + ) + ), + "stv": str( + _( + "List of constituencies. e.g." + "

District A
" + "District B
District C" + "
" + ) + ), } - self.fields['departments'].widget.attrs['data-labels'] = json.dumps(deps_labels) - self.fields['departments'].widget.attrs['data-help'] = json.dumps(deps_help_texts) - self.fields['departments'].required = False + self.fields["departments"].widget.attrs["data-labels"] = json.dumps(deps_labels) + self.fields["departments"].widget.attrs["data-help"] = json.dumps( + deps_help_texts + ) + self.fields["departments"].required = False - _module = self.data.get('election_module', None) + _module = self.data.get("election_module", None) _module = _module or (self.instance and self.instance.election_module) - if _module in ['unicouncilsgr']: - self.fields['departments'].required = True + if _module in ["unicouncilsgr"]: + self.fields["departments"].required = True if self.instance and self.instance.pk: - self.fields.get('trustees').initial = \ - election_trustees_to_text(self.instance) - self.fields.get('remote_mixes').initial = \ - bool(self.instance.mix_key) + self.fields.get("trustees").initial = election_trustees_to_text( + self.instance + ) + self.fields.get("remote_mixes").initial = bool(self.instance.mix_key) def _clean_trustees(form): return election_trustees_to_text(form.instance) + def _clean_remote_mixes(form): return bool(form.instance.mix_key) - value_overrides= { - 'trustees': _clean_trustees, - 'remote_mixes': _clean_remote_mixes + + value_overrides = { + "trustees": _clean_trustees, + "remote_mixes": _clean_remote_mixes, } setup_editable_fields(self, **value_overrides) if not self.instance.frozen_at: - self.fields.pop('voting_extended_until') + self.fields.pop("voting_extended_until") def clean(self): data = super(ElectionForm, self).clean() - self.clean_voting_dates(data.get('voting_starts_at'), - data.get('voting_ends_at'), - data.get('voting_extended_until')) + self.clean_voting_dates( + data.get("voting_starts_at"), + data.get("voting_ends_at"), + data.get("voting_extended_until"), + ) return data def clean_departments(self): - deps = self.cleaned_data.get('departments') - deps_arr = deps.split('\n') + deps = self.cleaned_data.get("departments") + deps_arr = deps.split("\n") cleaned_deps = [] for item in deps_arr: item = item.strip() item = item.lstrip() if item: cleaned_deps.append(item) - cleaned_deps = '\n'.join(cleaned_deps) + cleaned_deps = "\n".join(cleaned_deps) return cleaned_deps def clean_voting_dates(self, starts, ends, extension): # WARN: skip live validation here. warn user during freeze instead. - #final_ends = extension or ends - #if self.instance and self.instance.polls.count(): - #for poll in self.instance.polls.filter(): - #if not poll.forum_enabled: - #continue - #if starts and poll.forum_starts_at < starts: - #raise forms.ValidationError(_("Invalid voting start date. Check poll forum access dates.")) - #if final_ends and poll.forum_ends_at > final_ends: - #raise forms.ValidationError(_("Invalid voting end date. Check poll forum access dates.")) + # final_ends = extension or ends + # if self.instance and self.instance.polls.count(): + # for poll in self.instance.polls.filter(): + # if not poll.forum_enabled: + # continue + # if starts and poll.forum_starts_at < starts: + # raise forms.ValidationError(_("Invalid voting start date. Check poll forum access dates.")) + # if final_ends and poll.forum_ends_at > final_ends: + # raise forms.ValidationError(_("Invalid voting end date. Check poll forum access dates.")) if starts and ends: if ends < datetime.now() and self.instance.feature_edit_voting_ends_at: raise forms.ValidationError(_("Invalid voting end date")) @@ -309,7 +349,7 @@ def clean_voting_dates(self, starts, ends, extension): raise forms.ValidationError(_("Invalid voting extension date")) def clean_trustees(self): - trustees = self.cleaned_data.get('trustees') + trustees = self.cleaned_data.get("trustees") try: for tname, temail in extract_trustees(trustees): validate_email(temail) @@ -322,24 +362,26 @@ def log_changed_fields(self, instance): if field in self.changed_data: inital = self._initial_data[field] newvalue = self.cleaned_data[field] - instance.logger.info("Field '%s' changed from %r to %r", field, - inital, newvalue) - + instance.logger.info( + "Field '%s' changed from %r to %r", field, inital, newvalue + ) def save(self, *args, **kwargs): - remote_mixes = self.cleaned_data.get('remote_mixes') + remote_mixes = self.cleaned_data.get("remote_mixes") if remote_mixes: self.instance.generate_mix_key() else: self.instance.mix_key = None saved = super(ElectionForm, self).save(*args, **kwargs) - trustees = extract_trustees(self.cleaned_data.get('trustees')) + trustees = extract_trustees(self.cleaned_data.get("trustees")) saved.institution = self.institution if saved.sms_api_enabled: saved.sms_data = self.owner.sms_data if self.creating: - saved.legal_representative = self.cleaned_data.get('legal_representative', None) + saved.legal_representative = self.cleaned_data.get( + "legal_representative", None + ) saved.save() if saved.feature_edit_trustees: saved.update_trustees(trustees) @@ -353,7 +395,8 @@ class AnswerWidget(forms.TextInput): def render(self, *args, **kwargs): html = super(AnswerWidget, self).render(*args, **kwargs) - html = u""" + html = ( + """
%s @@ -363,52 +406,58 @@ def render(self, *args, **kwargs): class="remove_answer">X
- """ % html + """ + % html + ) return mark_safe(html) DEFAULT_ANSWERS_COUNT = 2 -MAX_QUESTIONS_LIMIT = getattr(settings, 'MAX_QUESTIONS_LIMIT', 1) +MAX_QUESTIONS_LIMIT = getattr(settings, "MAX_QUESTIONS_LIMIT", 1) class QuestionBaseForm(forms.Form): - choice_type = forms.ChoiceField(choices=( - ('choice', _('Choice')), - )) - question = forms.CharField(label=_("Question"), max_length=5000, - required=True, - widget=forms.Textarea(attrs={ - 'rows': 4, - 'class': 'textarea' - })) + choice_type = forms.ChoiceField(choices=(("choice", _("Choice")),)) + question = forms.CharField( + label=_("Question"), + max_length=5000, + required=True, + widget=forms.Textarea(attrs={"rows": 4, "class": "textarea"}), + ) def __init__(self, *args, **kwargs): super(QuestionBaseForm, self).__init__(*args, **kwargs) - if len(self.fields['choice_type'].choices) == 1: - self.fields['choice_type'].widget = forms.HiddenInput() - self.fields['choice_type'].initial = 'choice' + if len(self.fields["choice_type"].choices) == 1: + self.fields["choice_type"].widget = forms.HiddenInput() + self.fields["choice_type"].initial = "choice" - answers = len(filter(lambda k: k.startswith("%s-answer_" % - self.prefix), self.data)) + answers = len( + [k for k in self.data if k.startswith("%s-answer_" % self.prefix)] + ) if not answers: - answers = len(filter(lambda k: k.startswith("answer_") and not "indexes" in k, - self.initial.keys())) + answers = len( + [ + k + for k in list(self.initial.keys()) + if k.startswith("answer_") and not "indexes" in k + ] + ) if answers == 0: answers = DEFAULT_ANSWERS_COUNT for ans in range(answers): - field_key = 'answer_%d' % ans - self.fields[field_key] = forms.CharField(max_length=300, - required=True, - widget=AnswerWidget) - self.fields[field_key].widget.attrs = {'class': 'answer_input'} + field_key = "answer_%d" % ans + self.fields[field_key] = forms.CharField( + max_length=300, required=True, widget=AnswerWidget + ) + self.fields[field_key].widget.attrs = {"class": "answer_input"} self._answers = answers def clean_question(self): - q = self.cleaned_data.get('question', '') - if '%' in q: + q = self.cleaned_data.get("question", "") + if "%" in q: raise forms.ValidationError(INVALID_CHAR_MSG % "%") return q.replace(": ", ":\t") @@ -423,25 +472,24 @@ class QuestionForm(QuestionBaseForm): def __init__(self, *args, **kwargs): super(QuestionForm, self).__init__(*args, **kwargs) answers = self._answers - max_choices = map(lambda x: (x,x), range(1, self.max_limit or answers+1)) - min_choices = map(lambda x: (x,x), range(0, answers+1 if self.min_limit is None else self.min_limit)) - - self.fields['max_answers'].choices = max_choices - self.fields['max_answers'].initial = min(map(lambda x:x[1], max_choices)) - self.fields['min_answers'].choices = max_choices - self.fields['min_answers'].initial = 0 - + max_choices = [(x, x) for x in range(1, self.max_limit or answers + 1)] + + self.fields["max_answers"].choices = max_choices + self.fields["max_answers"].initial = min([x[1] for x in max_choices]) + self.fields["min_answers"].choices = max_choices + self.fields["min_answers"].initial = 0 def clean(self): - max_answers = int(self.cleaned_data.get('max_answers')) - min_answers = int(self.cleaned_data.get('min_answers')) + max_answers = int(self.cleaned_data.get("max_answers")) + min_answers = int(self.cleaned_data.get("min_answers")) if min_answers > max_answers: - raise forms.ValidationError(_("Max answers should be greater " - "or equal to min answers")) + raise forms.ValidationError( + _("Max answers should be greater " "or equal to min answers") + ) answer_list = [] for key in self.cleaned_data: - if key.startswith('answer_'): - if '%' in self.cleaned_data[key]: + if key.startswith("answer_"): + if "%" in self.cleaned_data[key]: raise forms.ValidationError(INVALID_CHAR_MSG % "%") answer_list.append(self.cleaned_data[key]) if len(answer_list) > len(set(answer_list)): @@ -450,24 +498,31 @@ def clean(self): class PartyForm(QuestionForm): - question = forms.CharField(label=_("Party name"), max_length=255, - required=True, widget=forms.Textarea(attrs={ - 'rows': 4, - 'class': 'textarea' - })) + question = forms.CharField( + label=_("Party name"), + max_length=255, + required=True, + widget=forms.Textarea(attrs={"rows": 4, "class": "textarea"}), + ) + SCORES_DEFAULT_LEN = 2 -SCORES_CHOICES = [(x,x) for x in range(1, 10)] +SCORES_CHOICES = [(x, x) for x in range(1, 10)] + + class ScoresForm(QuestionBaseForm): - scores = forms.MultipleChoiceField(required=True, - widget=forms.CheckboxSelectMultiple, - choices=SCORES_CHOICES, - label=_('Scores')) + scores = forms.MultipleChoiceField( + required=True, + widget=forms.CheckboxSelectMultiple, + choices=SCORES_CHOICES, + label=_("Scores"), + ) scores.initial = (1, 2) min_answers = forms.ChoiceField(label=_("Min answers"), required=True) max_answers = forms.ChoiceField(label=_("Max answers"), required=True) + def __init__(self, *args, **kwargs): super(ScoresForm, self).__init__(*args, **kwargs) if type(self.data) != dict: @@ -475,35 +530,35 @@ def __init__(self, *args, **kwargs): else: myDict = self.data - if 'form-0-scores' in myDict: - self._scores_len = len(myDict['form-0-scores']) - elif 'scores' in self.initial: - self._scores_len = len(self.initial['scores']) + if "form-0-scores" in myDict: + self._scores_len = len(myDict["form-0-scores"]) + elif "scores" in self.initial: + self._scores_len = len(self.initial["scores"]) else: self._scores_len = SCORES_DEFAULT_LEN - max_choices = map(lambda x: (x,x), range(1, self._scores_len + 1)) - self.fields['max_answers'].choices = max_choices - self.fields['max_answers'].initial = self._scores_len - self.fields['min_answers'].choices = max_choices - + max_choices = [(x, x) for x in range(1, self._scores_len + 1)] + self.fields["max_answers"].choices = max_choices + self.fields["max_answers"].initial = self._scores_len + self.fields["min_answers"].choices = max_choices def clean(self): super(ScoresForm, self).clean() - max_answers = int(self.cleaned_data.get('max_answers', 0)) - min_answers = int(self.cleaned_data.get('min_answers', 0)) + max_answers = int(self.cleaned_data.get("max_answers", 0)) + min_answers = int(self.cleaned_data.get("min_answers", 0)) if (min_answers and max_answers) and min_answers > max_answers: - raise forms.ValidationError(_("Max answers should be greater " - "or equal to min answers")) + raise forms.ValidationError( + _("Max answers should be greater " "or equal to min answers") + ) answer_list = [] for key in self.cleaned_data: - if key.startswith('answer_'): - if '%' in self.cleaned_data[key]: + if key.startswith("answer_"): + if "%" in self.cleaned_data[key]: raise forms.ValidationError(INVALID_CHAR_MSG % "%") answer_list.append(self.cleaned_data[key]) if len(answer_list) > len(set(answer_list)): raise forms.ValidationError(_("No duplicate choices allowed")) - if 'scores' in self.cleaned_data: - if (len(answer_list) < max_answers): + if "scores" in self.cleaned_data: + if len(answer_list) < max_answers: m = _("Number of answers must be equal or bigger than max answers") raise forms.ValidationError(m) return self.cleaned_data @@ -512,18 +567,18 @@ def clean(self): class RequiredFormset(BaseFormSet): def __init__(self, *args, **kwargs): - super(RequiredFormset, self).__init__(*args, **kwargs) - try: - self.forms[0].empty_permitted = False - except IndexError: - pass + super(RequiredFormset, self).__init__(*args, **kwargs) + try: + self.forms[0].empty_permitted = False + except IndexError: + pass + class CandidateWidget(MultiWidget): def __init__(self, *args, **kwargs): - departments = kwargs.pop('departments', []) - widgets = (TextInput(), - Select(choices=departments)) + departments = kwargs.pop("departments", []) + widgets = (TextInput(), Select(choices=departments)) super(CandidateWidget, self).__init__(widgets, *args, **kwargs) def decompress(self, value): @@ -547,12 +602,16 @@ def format_output(self, rendered_widgets): class="remove_answer">X - """ % (rendered_widgets[0], rendered_widgets[1]) + """ % ( + rendered_widgets[0], + rendered_widgets[1], + ) def value_from_datadict(self, data, files, name): datalist = [ - widget.value_from_datadict(data, files, name + '_%s' % i) - for i, widget in enumerate(self.widgets)] + widget.value_from_datadict(data, files, name + "_%s" % i) + for i, widget in enumerate(self.widgets) + ] return json.dumps(datalist) @@ -561,75 +620,81 @@ class StvForm(QuestionBaseForm): answer_widget_values_len = 2 def __init__(self, *args, **kwargs): - deps = kwargs['initial'].get('departments_data', '').split('\n') + deps = kwargs["initial"].get("departments_data", "").split("\n") DEPARTMENT_CHOICES = [] for dep in deps: - DEPARTMENT_CHOICES.append((dep.strip(),dep.strip())) + DEPARTMENT_CHOICES.append((dep.strip(), dep.strip())) super(StvForm, self).__init__(*args, **kwargs) - self.fields.pop('question') - answers = len( - filter( - lambda k: k.startswith("%s-answer_" % self.prefix), - self.data) - ) / self.answer_widget_values_len + self.fields.pop("question") + answers = ( + len([k for k in self.data if k.startswith("%s-answer_" % self.prefix)]) + / self.answer_widget_values_len + ) if not answers: - answers = len(filter(lambda k: k.startswith("answer_"), - self.initial)) + answers = len([k for k in self.initial if k.startswith("answer_")]) if answers == 0: answers = DEFAULT_ANSWERS_COUNT self.fields.clear() for ans in range(answers): - field_key = 'answer_%d' % ans - field_key1 = 'department_%d' % ans + field_key = "answer_%d" % ans + field_key1 = "department_%d" % ans _widget = self._make_candidate_widget(DEPARTMENT_CHOICES) - self.fields[field_key] = forms.CharField(max_length=600, - required=True, - widget=_widget, - label=('Candidate')) + self.fields[field_key] = forms.CharField( + max_length=600, required=True, widget=_widget, label=("Candidate") + ) elig_help_text = _("https://en.wikipedia.org/wiki/Droop_quota") label_text = _("Droop quota") - ordered_dict_prepend(self.fields, 'droop_quota', - forms.BooleanField( - required=False, - label=label_text, - initial=True, - help_text=elig_help_text)) - self.fields['droop_quota'].widget.attrs['readonly'] = True - self.fields['droop_quota'].widget.attrs['disabled'] = True - - widget=forms.TextInput(attrs={'hidden': 'True'}) + ordered_dict_prepend( + self.fields, + "droop_quota", + forms.BooleanField( + required=False, label=label_text, initial=True, help_text=elig_help_text + ), + ) + self.fields["droop_quota"].widget.attrs["readonly"] = True + self.fields["droop_quota"].widget.attrs["disabled"] = True + + widget = forms.TextInput(attrs={"hidden": "True"}) dep_lim_help_text = _("maximum number of elected from the same constituency") dep_lim_label = _("Constituency limit") - ordered_dict_prepend(self.fields, 'department_limit', - forms.CharField( - help_text=dep_lim_help_text, - label=dep_lim_label, - widget=widget, - required=False)) - - widget=forms.CheckboxInput() + ordered_dict_prepend( + self.fields, + "department_limit", + forms.CharField( + help_text=dep_lim_help_text, + label=dep_lim_label, + widget=widget, + required=False, + ), + ) + + widget = forms.CheckboxInput() limit_help_text = _("enable limiting the elections from the same constituency") limit_label = _("Limit elected per constituency") - ordered_dict_prepend(self.fields, 'has_department_limit', - forms.BooleanField( - widget=widget, - help_text=limit_help_text, - label = limit_label, - required=False)) + ordered_dict_prepend( + self.fields, + "has_department_limit", + forms.BooleanField( + widget=widget, + help_text=limit_help_text, + label=limit_label, + required=False, + ), + ) elig_help_text = _("set the eligibles count of the election") label_text = _("Eligibles count") - ordered_dict_prepend(self.fields, 'eligibles', - forms.CharField( - label=label_text, - help_text=elig_help_text)) - + ordered_dict_prepend( + self.fields, + "eligibles", + forms.CharField(label=label_text, help_text=elig_help_text), + ) min_answers = None max_answers = None @@ -639,28 +704,28 @@ def _make_candidate_widget(self, departments): def _clean_answer(self, answer): from django.forms.util import ErrorList + answer_lst = json.loads(answer) - if '%' in answer_lst[0]: + if "%" in answer_lst[0]: raise forms.ValidationError(INVALID_CHAR_MSG % "%") if not answer_lst[0]: message = _("This field is required.") - self._errors['answer_0'] = ErrorList([message]) + self._errors["answer_0"] = ErrorList([message]) return None, json.dumps([]) answer_lst[0] = answer_lst[0].strip() return answer_lst[0], json.dumps(answer_lst) def clean(self): - answers = len( - filter( - lambda k: k.startswith( - "%s-answer_" % self.prefix), self.data) - ) / self.answer_widget_values_len + answers = ( + len([k for k in self.data if k.startswith("%s-answer_" % self.prefix)]) + / self.answer_widget_values_len + ) - #list used for checking duplicate candidates + # list used for checking duplicate candidates candidates_list = [] for ans in range(answers): - field_key = 'answer_%d' % ans + field_key = "answer_%d" % ans answer = self.cleaned_data[field_key] key, cleaned = self._clean_answer(answer) candidates_list.append(key) @@ -669,25 +734,25 @@ def clean(self): if len(candidates_list) > len(set(candidates_list)): raise forms.ValidationError(_("No duplicate choices allowed")) - self.cleaned_data['droop_quota'] = True + self.cleaned_data["droop_quota"] = True return self.cleaned_data def clean_eligibles(self): message = _("Value must be a positve integer") - eligibles = self.cleaned_data.get('eligibles') + eligibles = self.cleaned_data.get("eligibles") try: eligibles = int(eligibles) if eligibles > 0: return eligibles else: raise forms.ValidationError(message) - except ValueError,TypeError: + except ValueError as TypeError: raise forms.ValidationError(message) def clean_department_limit(self): message = _("Value must be a positve integer") - dep_limit = self.cleaned_data.get('department_limit') - if self.cleaned_data.get('has_department_limit'): + dep_limit = self.cleaned_data.get("department_limit") + if self.cleaned_data.get("has_department_limit"): if not dep_limit: raise forms.ValidationError(message) else: @@ -706,23 +771,21 @@ class UniCouncilsGrForm(StvForm): def __init__(self, *args, **kwargs): super(UniCouncilsGrForm, self).__init__(*args, **kwargs) - has_limit_help_text = \ - _("enable limiting the elections from the same department") - has_limit_label = \ - _("Limit elected per department") - self.fields['has_department_limit'].label = has_limit_label - self.fields['has_department_limit'].help_text = has_limit_label - dep_lim_help_text = \ - _("maximum number of elected from the same department") - dep_lim_label = \ - _("Department limit") - self.fields['department_limit'].label = dep_lim_label - self.fields['department_limit'].help_text = dep_lim_help_text - del self.fields['droop_quota'] + has_limit_help_text = _( + "enable limiting the elections from the same department" + ) + has_limit_label = _("Limit elected per department") + self.fields["has_department_limit"].label = has_limit_label + self.fields["has_department_limit"].help_text = has_limit_label + dep_lim_help_text = _("maximum number of elected from the same department") + dep_lim_label = _("Department limit") + self.fields["department_limit"].label = dep_lim_label + self.fields["department_limit"].help_text = dep_lim_help_text + del self.fields["droop_quota"] def clean(self): super(UniCouncilsGrForm, self).clean() - self.cleaned_data['droop_quota'] = False + self.cleaned_data["droop_quota"] = False return self.cleaned_data @@ -732,31 +795,30 @@ class PreferencesForm(StvForm): def __init__(self, *args, **kwargs): super(PreferencesForm, self).__init__(*args, **kwargs) - del self.fields['department_limit'] - del self.fields['has_department_limit'] - del self.fields['eligibles'] - del self.fields['droop_quota'] + del self.fields["department_limit"] + del self.fields["has_department_limit"] + del self.fields["eligibles"] + del self.fields["droop_quota"] def _make_candidate_widget(self, departments): - return AnswerWidget(attrs={'class': 'answer_input'}) + return AnswerWidget(attrs={"class": "answer_input"}) def _clean_answer(self, answer): - if '%' in answer: + if "%" in answer: raise forms.ValidationError(INVALID_CHAR_MSG % "%") return answer, answer class LoginForm(forms.Form): - username = forms.CharField(label=_('Username'), - max_length=50) - password = forms.CharField(label=_('Password'), - widget=forms.PasswordInput(), - max_length=100) + username = forms.CharField(label=_("Username"), max_length=50) + password = forms.CharField( + label=_("Password"), widget=forms.PasswordInput(), max_length=100 + ) def clean(self): self._user_cache = None - username = self.cleaned_data.get('username') - password = self.cleaned_data.get('password') + username = self.cleaned_data.get("username") + password = self.cleaned_data.get("password") try: user = User.objects.get(user_id=username) except User.DoesNotExist: @@ -765,7 +827,7 @@ def clean(self): if user.is_disabled: raise forms.ValidationError(_("Your account is disabled")) - if check_password(password, user.info['password']): + if check_password(password, user.info["password"]): self._user_cache = user return self.cleaned_data else: @@ -775,143 +837,152 @@ def clean(self): class PollForm(forms.ModelForm): FIELD_REQUIRED_FEATURES = { - 'name': ['edit_name'], - 'forum_enabled': ['edit_forum'], - 'forum_ends_at': ['edit_forum'], - 'forum_description': ['edit_forum'], - 'forum_starts_at': ['edit_forum'], - 'forum_extended_until': ['edit_forum_extension'], - 'linked_ref': ['edit_linked_ref'], - 'taxisnet_auth': ['edit_taxisnet'] + "name": ["edit_name"], + "forum_enabled": ["edit_forum"], + "forum_ends_at": ["edit_forum"], + "forum_description": ["edit_forum"], + "forum_starts_at": ["edit_forum"], + "forum_extended_until": ["edit_forum_extension"], + "linked_ref": ["edit_linked_ref"], + "taxisnet_auth": ["edit_taxisnet"], } formfield_callback = election_form_formfield_cb - forum_enabled = forms.BooleanField(label=_('Poll forum enabled'), - required=False, - help_text=help.forum_enabled) - linked_ref = forms.ChoiceField(required=False, initial='', - label=_('Link voters list to another poll')) + forum_enabled = forms.BooleanField( + label=_("Poll forum enabled"), required=False, help_text=help.forum_enabled + ) + linked_ref = forms.ChoiceField( + required=False, initial="", label=_("Link voters list to another poll") + ) def __init__(self, *args, **kwargs): - self.election = kwargs.pop('election', None) - self.admin = kwargs.pop('admin', None) + self.election = kwargs.pop("election", None) + self.admin = kwargs.pop("admin", None) super(PollForm, self).__init__(*args, **kwargs) - if 'linked_ref' in self.initial and self.initial['linked_ref'] is None: - self.initial['linked_ref'] = '' + if "linked_ref" in self.initial and self.initial["linked_ref"] is None: + self.initial["linked_ref"] = "" CHOICES = ( - ('public', 'public'), - ('confidential', 'confidential'), - ) - - TYPES = ( - ('google', 'google'), - ('facebook', 'facfebook'), - ('other', 'other') + ("public", "public"), + ("confidential", "confidential"), ) + TYPES = (("google", "google"), ("facebook", "facfebook"), ("other", "other")) - ordered_dict_prepend(self.fields, 'jwt_file', - forms.FileField( - label="JWT public keyfile", - required=False)) + ordered_dict_prepend( + self.fields, + "jwt_file", + forms.FileField(label="JWT public keyfile", required=False), + ) if self.instance.is_linked_root: - del self.fields['linked_ref'] + del self.fields["linked_ref"] else: linked_choices = [["", ""]] for p in self.election.polls.filter().exclude(pk=self.instance.pk): if not p.is_linked_leaf: linked_choices.append((p.uuid, p.name)) - self.fields['linked_ref'].choices = linked_choices - - self.fields['jwt_file'].widget.attrs['accept'] = '.pem' - self.fields['jwt_public_key'] = forms.CharField(required=False, - widget=forms.Textarea) - self.fields['oauth2_type'] = forms.ChoiceField(required=False, - choices=TYPES) - self.fields['oauth2_client_type'] = forms.ChoiceField(required=False, - choices=CHOICES) - self.fields['google_code_url'] = forms.CharField( - widget=HiddenInput, - initial="https://accounts.google.com/o/oauth2/auth", - required=False) - self.fields['google_exchange_url'] = forms.CharField( - widget=HiddenInput, - initial="https://accounts.google.com/o/oauth2/token", - required=False) - self.fields['google_confirmation_url'] = forms.CharField( - widget=HiddenInput, - initial="https://www.googleapis.com/oauth2/v1/userinfo", - required=False) - self.fields['facebook_code_url'] = forms.CharField( - widget=HiddenInput, - initial="https://www.facebook.com/dialog/oauth", - required=False) - self.fields['facebook_exchange_url'] = forms.CharField( - widget=HiddenInput, - initial="https://graph.facebook.com/oauth/access_token", - required=False) - self.fields['facebook_confirmation_url'] = forms.CharField( - widget=HiddenInput, - initial="https://graph.facebook.com/v2.2/me", - required=False) - - self.fields['forum_starts_at'].help_text = None - self.fields['forum_ends_at'].help_text = _("Voting starts at %s") % self.election.voting_ends_at + self.fields["linked_ref"].choices = linked_choices + + self.fields["jwt_file"].widget.attrs["accept"] = ".pem" + self.fields["jwt_public_key"] = forms.CharField( + required=False, widget=forms.Textarea + ) + self.fields["oauth2_type"] = forms.ChoiceField(required=False, choices=TYPES) + self.fields["oauth2_client_type"] = forms.ChoiceField( + required=False, choices=CHOICES + ) + self.fields["google_code_url"] = forms.CharField( + widget=HiddenInput, + initial="https://accounts.google.com/o/oauth2/auth", + required=False, + ) + self.fields["google_exchange_url"] = forms.CharField( + widget=HiddenInput, + initial="https://accounts.google.com/o/oauth2/token", + required=False, + ) + self.fields["google_confirmation_url"] = forms.CharField( + widget=HiddenInput, + initial="https://www.googleapis.com/oauth2/v1/userinfo", + required=False, + ) + self.fields["facebook_code_url"] = forms.CharField( + widget=HiddenInput, + initial="https://www.facebook.com/dialog/oauth", + required=False, + ) + self.fields["facebook_exchange_url"] = forms.CharField( + widget=HiddenInput, + initial="https://graph.facebook.com/oauth/access_token", + required=False, + ) + self.fields["facebook_confirmation_url"] = forms.CharField( + widget=HiddenInput, + initial="https://graph.facebook.com/v2.2/me", + required=False, + ) + self.fields["forum_starts_at"].help_text = None + self.fields["forum_ends_at"].help_text = ( + _("Voting starts at %s") % self.election.voting_ends_at + ) shib_data = None if self.initial is not None: - shib_data = self.initial.get('shibboleth_constraints', None) - if isinstance(shib_data, basestring): + shib_data = self.initial.get("shibboleth_constraints", None) + if isinstance(shib_data, str): shib_data = json.loads(shib) if shib_data is not None and isinstance(shib_data, dict): - self.initial['shibboleth_constraints'] = json.dumps(shib_data) + self.initial["shibboleth_constraints"] = json.dumps(shib_data) if not self.instance or not self.instance.pk: - self.initial['forum_ends_at'] = self.election.voting_starts_at - self.initial['forum_starts_at'] = self.initial['forum_ends_at'] - timedelta(days=2) + self.initial["forum_ends_at"] = self.election.voting_starts_at + self.initial["forum_starts_at"] = self.initial[ + "forum_ends_at" + ] - timedelta(days=2) if self.election.feature_frozen: - self.fields['name'].widget.attrs['readonly'] = True + self.fields["name"].widget.attrs["readonly"] = True - auth_title = _('2-factor authentication') - auth_help = _('2-factor authentication help text') - self.fieldsets = {'auth': [auth_title, auth_help, []]} + auth_title = _("2-factor authentication") + auth_help = _("2-factor authentication help text") + self.fieldsets = {"auth": [auth_title, auth_help, []]} self.fieldset_fields = [] - profiles = getattr(settings, 'ZEUS_SHIBBOLETH_PROFILES', {}) + profiles = getattr(settings, "ZEUS_SHIBBOLETH_PROFILES", {}) self.shib_profiles = profiles extra_auth_fields = {} - auth_fields = ['jwt', 'google', 'facebook', 'shibboleth', 'oauth2'] - auth_checks = ['jwt_auth', 'oauth2_thirdparty', 'shibboleth_auth'] + auth_fields = ["jwt", "google", "facebook", "shibboleth", "oauth2"] + auth_checks = ["jwt_auth", "oauth2_thirdparty", "shibboleth_auth"] if taxisnet.is_enabled(self.admin) or self.instance.taxisnet_auth: - auth_fields.append('taxisnet') - auth_checks.append('taxisnet_auth') + auth_fields.append("taxisnet") + auth_checks.append("taxisnet_auth") else: - del self.fields['taxisnet_auth'] + del self.fields["taxisnet_auth"] if profiles: - for key, data in profiles.items(): - field_key = 'shibprofile{}'.format(key) - fields_key = '{}_auth'.format(field_key) - if shib_data and shib_data.get('profile', None) == key: - del self.initial['shibboleth_constraints'] - del self.initial['shibboleth_auth'] + for key, data in list(profiles.items()): + field_key = "shibprofile{}".format(key) + fields_key = "{}_auth".format(field_key) + if shib_data and shib_data.get("profile", None) == key: + del self.initial["shibboleth_constraints"] + del self.initial["shibboleth_auth"] self.initial[fields_key] = True widget = forms.CheckboxInput() - field = forms.BooleanField(widget=widget, - help_text=data.get('help_text', ' '), - label = data.get('label', ''), - required=False) + field = forms.BooleanField( + widget=widget, + help_text=data.get("help_text", " "), + label=data.get("label", ""), + required=False, + ) self.fields[fields_key] = field self.fieldset_fields.append(field) auth_checks.append(fields_key) auth_fields.append(field_key) - for name, field in self.fields.items(): + for name, field in list(self.fields.items()): parts = name.split("_") if not parts[0] in auth_fields: continue @@ -919,68 +990,82 @@ def __init__(self, *args, **kwargs): key = parts[0] if key in auth_fields: - self.fieldsets['auth'][2].append(name) + self.fieldsets["auth"][2].append(name) self.fieldset_fields.append(field) - setattr(field, 'field_attrs', '') + setattr(field, "field_attrs", "") attrs = "data-auth={}".format(key) if is_check: attrs += " data-auth-toggle=true" - field.widget.attrs['field_class'] = 'fieldset-auth' - field.help_text = field.help_text or '  ' + field.widget.attrs["field_class"] = "fieldset-auth" + field.help_text = field.help_text or "  " else: attrs += " data-auth-option={}".format(key) - field.widget.attrs['field_class'] = \ - 'auth-option-field {}'.format(key) + field.widget.attrs["field_class"] = "auth-option-field {}".format( + key + ) field.field_attrs = attrs - keyOrder = self.fieldsets['auth'][2] - fieldsKeys = self.fields.keys() + keyOrder = self.fieldsets["auth"][2] + fieldsKeys = list(self.fields.keys()) for field in auth_checks: prev_index = keyOrder.index(field) item = keyOrder.pop(prev_index) keyOrder.insert(0, item) - if field == 'jwt_auth': - self.fields[field].widget.attrs['field_class'] = 'clearfix last' + if field == "jwt_auth": + self.fields[field].widget.attrs["field_class"] = "clearfix last" if self.admin and not self.admin.can_enable_forum: if not self.instance.forum_enabled: - del self.fields['forum_enabled'] + del self.fields["forum_enabled"] self.instance.election = self.election setup_editable_fields(self) disable_auth = False for f in auth_checks: field = self.fields[f] - if getattr(field, 'disabled', False): + if getattr(field, "disabled", False): disable_auth = True if disable_auth: for f in auth_checks: field = self.fields[f] - if not getattr(field, 'disabled', False): + if not getattr(field, "disabled", False): disable_field(field, f, self, {}) - class Meta: model = Poll - fields = ('name', - 'jwt_auth', 'jwt_issuer', 'jwt_public_key', - 'oauth2_thirdparty', 'oauth2_type', - 'oauth2_client_type', 'oauth2_client_id', - 'oauth2_client_secret', 'oauth2_code_url', - 'oauth2_exchange_url', 'oauth2_confirmation_url', - 'shibboleth_auth', 'shibboleth_constraints', - 'forum_enabled', 'forum_description', 'forum_starts_at', - 'forum_ends_at', 'forum_extended_until', 'linked_ref', 'taxisnet_auth') + fields = ( + "name", + "jwt_auth", + "jwt_issuer", + "jwt_public_key", + "oauth2_thirdparty", + "oauth2_type", + "oauth2_client_type", + "oauth2_client_id", + "oauth2_client_secret", + "oauth2_code_url", + "oauth2_exchange_url", + "oauth2_confirmation_url", + "shibboleth_auth", + "shibboleth_constraints", + "forum_enabled", + "forum_description", + "forum_starts_at", + "forum_ends_at", + "forum_extended_until", + "linked_ref", + "taxisnet_auth", + ) def iter_fieldset(self, name): for field in self.fieldsets[name][2]: yield self[field] def clean_linked_ref(self): - ref = self.cleaned_data.get('linked_ref', None) + ref = self.cleaned_data.get("linked_ref", None) if not ref: ref = None if ref: - if not ref in self.election.polls.filter().values_list('uuid', flat=True): + if not ref in self.election.polls.filter().values_list("uuid", flat=True): raise forms.ValidationError(_("Invalid poll")) else: p = self.election.polls.get(uuid=ref) @@ -991,8 +1076,8 @@ def clean_linked_ref(self): def clean_forum_starts_at(self): # forum start date should be set on a date after current date. - enabled = self.cleaned_data.get('forum_enabled') - starts_at = self.cleaned_data.get('forum_starts_at') + enabled = self.cleaned_data.get("forum_enabled") + starts_at = self.cleaned_data.get("forum_starts_at") if enabled and not starts_at: raise forms.ValidationError(_("This field is required.")) voting_starts = self.election.voting_starts_at @@ -1003,9 +1088,9 @@ def clean_forum_starts_at(self): def clean_forum_ends_at(self): # forum end date should be set if forum is enabled and should be set to # a date after current date and after forum start date - enabled = self.cleaned_data.get('forum_enabled') - starts_at = self.cleaned_data.get('forum_starts_at') - ends_at = self.cleaned_data.get('forum_ends_at') + enabled = self.cleaned_data.get("forum_enabled") + starts_at = self.cleaned_data.get("forum_starts_at") + ends_at = self.cleaned_data.get("forum_ends_at") voting_starts = self.election.voting_starts_at if enabled and not ends_at: raise forms.ValidationError(_("This field is required.")) @@ -1017,8 +1102,8 @@ def clean_forum_ends_at(self): return ends_at def clean_forum_description(self): - desc = self.cleaned_data.get('forum_description') or '' - enabled = self.cleaned_data.get('forum_enabled') + desc = self.cleaned_data.get("forum_description") or "" + enabled = self.cleaned_data.get("forum_enabled") desc = desc.strip() if enabled and not desc: @@ -1026,8 +1111,8 @@ def clean_forum_description(self): return desc def clean_forum_extended_until(self): - date = self.cleaned_data.get('forum_extended_until') - enabled = self.cleaned_data.get('forum_enabled') + date = self.cleaned_data.get("forum_extended_until") + enabled = self.cleaned_data.get("forum_enabled") forum_ends_at = self.instance.forum_ends_at if enabled and date and (date <= forum_ends_at): @@ -1035,12 +1120,12 @@ def clean_forum_extended_until(self): return date def clean_shibboleth_constraints(self): - value = self.cleaned_data.get('shibboleth_constraints', None) + value = self.cleaned_data.get("shibboleth_constraints", None) if value == "None": return None try: value and json.loads(value) - except Exception, e: + except Exception as e: raise forms.ValidationError(_("Invalid shibboleth constraints.")) return value @@ -1051,70 +1136,84 @@ def clean(self): data = self.cleaned_data election_polls = self.election.polls.all() - enabled = self.cleaned_data.get('forum_enabled') - linked_ref = self.cleaned_data.get('linked_ref') + enabled = self.cleaned_data.get("forum_enabled") + linked_ref = self.cleaned_data.get("linked_ref") if enabled and linked_ref: msg = [_("Forum cannot be enabled for linked polls")] self._errors["forum_enabled"] = msg self._errors["linked_ref"] = msg for poll in election_polls: - if (data.get('name') == poll.name and - ((not self.instance.pk ) or - (self.instance.pk and self.instance.name!=data.get('name')))): + if data.get("name") == poll.name and ( + (not self.instance.pk) + or (self.instance.pk and self.instance.name != data.get("name")) + ): message = _("Duplicate poll names are not allowed") raise forms.ValidationError(message) - if self.election.feature_frozen and\ - (self.cleaned_data['name'] != self.instance.name): - raise forms.ValidationError(_("Poll name cannot be changed\ - after freeze")) - - oauth2_field_names = ['type', 'client_type', 'client_id', 'client_secret', - 'code_url', 'exchange_url', 'confirmation_url'] - oauth2_field_names = ['oauth2_' + x for x in oauth2_field_names] - jwt_field_names = ['jwt_issuer', 'jwt_public_key'] + if self.election.feature_frozen and ( + self.cleaned_data["name"] != self.instance.name + ): + raise forms.ValidationError( + _( + "Poll name cannot be changed\ + after freeze" + ) + ) + + oauth2_field_names = [ + "type", + "client_type", + "client_id", + "client_secret", + "code_url", + "exchange_url", + "confirmation_url", + ] + oauth2_field_names = ["oauth2_" + x for x in oauth2_field_names] + jwt_field_names = ["jwt_issuer", "jwt_public_key"] url_validate = URLValidator() - if data['oauth2_thirdparty']: + if data["oauth2_thirdparty"]: for field_name in oauth2_field_names: if not data[field_name]: - self._errors[field_name] = _('This field is required.'), - url_types = ['code', 'exchange', 'confirmation'] + self._errors[field_name] = (_("This field is required."),) + url_types = ["code", "exchange", "confirmation"] for url_type in url_types: try: - url_validate(data['oauth2_{}_url'.format(url_type)]) + url_validate(data["oauth2_{}_url".format(url_type)]) except ValidationError: - self._errors['oauth2_{}_url'.format(url_type)] =\ - ((_("This URL is invalid"),)) + self._errors["oauth2_{}_url".format(url_type)] = ( + _("This URL is invalid"), + ) else: for field_name in oauth2_field_names: - data[field_name] = '' + data[field_name] = "" shibboleth_field_names = [] - if data['shibboleth_auth']: + if data["shibboleth_auth"]: for field_name in shibboleth_field_names: if not data[field_name]: - self._errors[field_name] = _('This field is required.'), + self._errors[field_name] = (_("This field is required."),) - for _key, item in self.shib_profiles.items(): - key = 'shibprofile{}_auth'.format(_key) + for _key, item in list(self.shib_profiles.items()): + key = "shibprofile{}_auth".format(_key) if data[key]: - data['shibboleth_auth'] = True - data['shibboleth_constraints'] = item.get('data') - data['shibboleth_constraints']['profile'] = _key + data["shibboleth_auth"] = True + data["shibboleth_constraints"] = item.get("data") + data["shibboleth_constraints"]["profile"] = _key - if data['jwt_auth']: + if data["jwt_auth"]: for field_name in jwt_field_names: if not data[field_name]: - self._errors[field_name] = _('This field is required.'), + self._errors[field_name] = (_("This field is required."),) else: for field_name in jwt_field_names: - data[field_name] = '' + data[field_name] = "" return data def save(self, *args, **kwargs): - was_linked = self.initial.get('linked_ref', None) - commit = kwargs.pop('commit', True) + was_linked = self.initial.get("linked_ref", None) + commit = kwargs.pop("commit", True) instance = super(PollForm, self).save(commit=False, *args, **kwargs) instance.election = self.election is_new = instance.pk is None @@ -1129,21 +1228,21 @@ def save(self, *args, **kwargs): class PollFormSet(BaseModelFormSet): def __init__(self, *args, **kwargs): - self.election = kwargs.pop('election', None) - self.admin = kwargs.pop('admin', None) + self.election = kwargs.pop("election", None) + self.admin = kwargs.pop("admin", None) super(PollFormSet, self).__init__(*args, **kwargs) def _construct_form(self, i, **kwargs): - kwargs['election'] = kwargs.get('election', self.election) - kwargs['admin'] = kwargs.get('admin', self.admin) + kwargs["election"] = kwargs.get("election", self.election) + kwargs["admin"] = kwargs.get("admin", self.admin) return super(PollFormSet, self)._construct_form(i, **kwargs) def clean(self): forms_data = self.cleaned_data form_poll_names = [] for form_data in forms_data: - form_poll_names.append(form_data['name']) - poll_name = form_data['name'] + form_poll_names.append(form_data["name"]) + poll_name = form_data["name"] e = Election.objects.get(id=self.election.id) election_polls = e.polls.all() for poll in election_polls: @@ -1155,9 +1254,8 @@ def clean(self): raise forms.ValidationError(message) def save(self, election, *args, **kwargs): - commit = kwargs.pop('commit', True) - instances = super(PollFormSet, self).save(commit=False, *args, - **kwargs) + commit = kwargs.pop("commit", True) + instances = super(PollFormSet, self).save(commit=False, *args, **kwargs) if commit: for instance in instances: instance.election = election @@ -1167,29 +1265,43 @@ def save(self, election, *args, **kwargs): SEND_TO_CHOICES = [ - ('all', _('all selected voters')), - ('voted', _('selected voters who have cast a ballot')), - ('not-voted', _('selected voters who have not yet cast a ballot')) + ("all", _("all selected voters")), + ("voted", _("selected voters who have cast a ballot")), + ("not-voted", _("selected voters who have not yet cast a ballot")), ] CONTACT_CHOICES = [ - ('email', _('Email only')), - ('sms', _('SMS only')), - ('email:sms', _('Email and SMS')), + ("email", _("Email only")), + ("sms", _("SMS only")), + ("email:sms", _("Email and SMS")), ] + class EmailVotersForm(forms.Form): - email_subject = forms.CharField(label=_('Email subject'), max_length=80, - required=False) - email_body = forms.CharField(label=_('In place of BODY'), max_length=30000, - widget=forms.Textarea, required=False) - sms_body = forms.CharField(label=_('In place of SMS_BODY'), max_length=30000, - widget=forms.Textarea, required=False) - contact_method = forms.ChoiceField(label=_("Contact method"), initial="email:sms", - choices=CONTACT_CHOICES) - notify_once = forms.BooleanField(initial=True, label=_("Do not send sms if voter email is set"), required=False) - send_to = forms.ChoiceField(label=_("Send To"), initial="all", - choices=SEND_TO_CHOICES) + email_subject = forms.CharField( + label=_("Email subject"), max_length=80, required=False + ) + email_body = forms.CharField( + label=_("In place of BODY"), + max_length=30000, + widget=forms.Textarea, + required=False, + ) + sms_body = forms.CharField( + label=_("In place of SMS_BODY"), + max_length=30000, + widget=forms.Textarea, + required=False, + ) + contact_method = forms.ChoiceField( + label=_("Contact method"), initial="email:sms", choices=CONTACT_CHOICES + ) + notify_once = forms.BooleanField( + initial=True, label=_("Do not send sms if voter email is set"), required=False + ) + send_to = forms.ChoiceField( + label=_("Send To"), initial="all", choices=SEND_TO_CHOICES + ) def __init__(self, election, template, *args, **kwargs): super(EmailVotersForm, self).__init__(*args, **kwargs) @@ -1197,31 +1309,36 @@ def __init__(self, election, template, *args, **kwargs): self.template = template if not election.sms_enabled: - self.fields['sms_body'].widget = forms.HiddenInput() - self.fields['contact_method'].widget = forms.HiddenInput() - self.fields['contact_method'].choices = [('email', _('Email'))] - self.fields['contact_method'].initial = 'email' - self.fields['notify_once'].widget = forms.HiddenInput() - self.fields['notify_once'].initial = False + self.fields["sms_body"].widget = forms.HiddenInput() + self.fields["contact_method"].widget = forms.HiddenInput() + self.fields["contact_method"].choices = [("email", _("Email"))] + self.fields["contact_method"].initial = "email" + self.fields["notify_once"].widget = forms.HiddenInput() + self.fields["notify_once"].initial = False else: choices = copy.copy(CONTACT_CHOICES) choices[1] = list(choices[1]) - choices[1][1] = "%s (%s)" % (unicode(choices[1][1]), _("%d deliveries available") % election.sms_data.left) - self.fields['contact_method'].choices = choices + choices[1][1] = "%s (%s)" % ( + str(choices[1][1]), + _("%d deliveries available") % election.sms_data.left, + ) + self.fields["contact_method"].choices = choices def clean(self): super(EmailVotersForm, self).clean() data = self.cleaned_data - if 'sms' in data.get('contact_method', []) and self.template == 'info': - if data.get('sms_body').strip() == '': + if "sms" in data.get("contact_method", []) and self.template == "info": + if data.get("sms_body").strip() == "": raise ValidationError(_("Please provide SMS body")) return data class ChangePasswordForm(forms.Form): - password = forms.CharField(label=_('Current password'), widget=forms.PasswordInput) - new_password = forms.CharField(label=_('New password'), widget=forms.PasswordInput) - new_password_confirm = forms.CharField(label=_('New password confirm'), widget=forms.PasswordInput) + password = forms.CharField(label=_("Current password"), widget=forms.PasswordInput) + new_password = forms.CharField(label=_("New password"), widget=forms.PasswordInput) + new_password_confirm = forms.CharField( + label=_("New password confirm"), widget=forms.PasswordInput + ) def __init__(self, user, *args, **kwargs): self.user = user @@ -1229,24 +1346,25 @@ def __init__(self, user, *args, **kwargs): def save(self): user = self.user - pwd = make_password(self.cleaned_data['new_password'].strip()) - user.info['password'] = pwd + pwd = make_password(self.cleaned_data["new_password"].strip()) + user.info["password"] = pwd user.save() def clean(self): cl = super(ChangePasswordForm, self).clean() - pwd = self.cleaned_data['password'].strip() - if not check_password(pwd, self.user.info['password']): - raise forms.ValidationError(_('Invalid password')) - if not self.cleaned_data.get('new_password') == \ - self.cleaned_data.get('new_password_confirm'): - raise forms.ValidationError(_('Passwords don\'t match')) + pwd = self.cleaned_data["password"].strip() + if not check_password(pwd, self.user.info["password"]): + raise forms.ValidationError(_("Invalid password")) + if not self.cleaned_data.get("new_password") == self.cleaned_data.get( + "new_password_confirm" + ): + raise forms.ValidationError(_("Passwords don't match")) return cl class VoterLoginForm(forms.Form): - login_id = forms.CharField(label=_('Login password'), required=True) + login_id = forms.CharField(label=_("Login password"), required=True) validation = re.compile("[0-9]{1,10}-(?:[0-9]{4}-){3,}[0-9]{4}") validation_digits = re.compile("[0-9]{17,}") @@ -1257,17 +1375,17 @@ def __init__(self, *args, **kwargs): def clean(self): cleaned_data = super(VoterLoginForm, self).clean() - login_id = self.cleaned_data.get('login_id', '').strip() + login_id = self.cleaned_data.get("login_id", "").strip() invalid_login_id_error = _("Invalid login code") if not login_id: raise forms.ValidationError(invalid_login_id_error) - matches = filter(bool, self.validation.findall(login_id)) + matches = list(filter(bool, self.validation.findall(login_id))) if len(matches): login_id = matches[0] else: - matches = filter(bool, self.validation_digits.findall(login_id)) + matches = list(filter(bool, self.validation_digits.findall(login_id))) if len(matches): login_id = matches[0] @@ -1297,19 +1415,24 @@ class STVBallotForm(forms.Form): def __init__(self, *args, **kwargs): candidates = self.candidates super(STVBallotForm, self).__init__(*args, **kwargs) - choices = [('', '')] + choices = [("", "")] for i, c in enumerate(candidates): choices.append((str(i), c)) for i, c in enumerate(candidates): - self.fields['choice_%d' % (i + 1)] = forms.ChoiceField(choices=choices, initial='', required=False, label=_("Ballot choice %s") % str(i + 1)) + self.fields["choice_%d" % (i + 1)] = forms.ChoiceField( + choices=choices, + initial="", + required=False, + label=_("Ballot choice %s") % str(i + 1), + ) def get_choices(self, serial): - vote = {'votes': [], "ballotSerialNumber": serial} + vote = {"votes": [], "ballotSerialNumber": serial} for i, c in enumerate(self.candidates): - val = self.cleaned_data.get('choice_%d' % (i + 1), '') + val = self.cleaned_data.get("choice_%d" % (i + 1), "") if not val: break - vote['votes'].append({'rank': (i + 1), "candidateTmpId": val}) + vote["votes"].append({"rank": (i + 1), "candidateTmpId": val}) return vote def clean(self): @@ -1317,7 +1440,7 @@ def clean(self): empty = False choices = [] for i, c in enumerate(self.candidates): - val = self.cleaned_data.get('choice_%d' % (i + 1), '') + val = self.cleaned_data.get("choice_%d" % (i + 1), "") if val == "": empty = True if val and empty: @@ -1330,29 +1453,45 @@ def clean(self): return data -candidates_help_text = _("""Candidates list. e.g.,

+candidates_help_text = _( + """Candidates list. e.g.,

FirstName, LastName, FatherName, SchoolA
FirstName, LastName, FatherName, SchoolB
-""") +""" +) + +limit_choices = [(x, str(x)) for x in range(2)] +eligibles_choices = [(x, str(x)) for x in range(1, 20)] + -limit_choices = map(lambda x: (x, str(x)), range(2)) -eligibles_choices = map(lambda x: (x, str(x)), range(1, 20)) class STVElectionForm(forms.Form): name = forms.CharField(label=_("Election name"), required=True) - voting_starts = forms.CharField(label=_("Voting start date"), required=True, help_text=_("e.g. 25/01/2015 07:00")) - voting_ends = forms.CharField(label=_("Voting end date"), required=True, help_text=_("e.g. 25/01/2015 19:00")) + voting_starts = forms.CharField( + label=_("Voting start date"), + required=True, + help_text=_("e.g. 25/01/2015 07:00"), + ) + voting_ends = forms.CharField( + label=_("Voting end date"), required=True, help_text=_("e.g. 25/01/2015 19:00") + ) institution = forms.CharField(label=_("Institution name")) - candidates = forms.CharField(label=_("Candidates"), widget=forms.Textarea, help_text=candidates_help_text) - eligibles_count = forms.ChoiceField(label=_("Eligibles count"), choices=eligibles_choices) - elected_limit = forms.IntegerField(label=_("Maximum elected per department"), required=False) + candidates = forms.CharField( + label=_("Candidates"), widget=forms.Textarea, help_text=candidates_help_text + ) + eligibles_count = forms.ChoiceField( + label=_("Eligibles count"), choices=eligibles_choices + ) + elected_limit = forms.IntegerField( + label=_("Maximum elected per department"), required=False + ) ballots_count = forms.CharField(label=_("Ballots count")) def __init__(self, *args, **kwargs): - kwargs.pop('disabled', False) + kwargs.pop("disabled", False) super(STVElectionForm, self).__init__(*args, **kwargs) def clean_voting_starts(self): - d = self.cleaned_data.get('voting_starts') or '' + d = self.cleaned_data.get("voting_starts") or "" d = d.strip() try: datetime.strptime(d, "%d/%m/%Y %H:%M") @@ -1361,7 +1500,7 @@ def clean_voting_starts(self): return d def clean_voting_ends(self): - d = self.cleaned_data.get('voting_ends') or '' + d = self.cleaned_data.get("voting_ends") or "" d = d.strip() try: datetime.strptime(d, "%d/%m/%Y %H:%M") @@ -1370,8 +1509,8 @@ def clean_voting_ends(self): return d def clean_candidates(self): - candidates = self.cleaned_data.get('candidates').strip() - candidates = map(lambda x: x.strip(), candidates.split("\n")) + candidates = self.cleaned_data.get("candidates").strip() + candidates = [x.strip() for x in candidates.split("\n")] for c in candidates: if len(c.split(",")) != 4: raise ValidationError(_("Candidate %s is invalid") % c) @@ -1379,37 +1518,41 @@ def clean_candidates(self): return candidates def get_candidates(self): - if not hasattr(self, 'cleaned_data'): + if not hasattr(self, "cleaned_data"): return [] - cs = self.cleaned_data.get('candidates')[:] + cs = self.cleaned_data.get("candidates")[:] for i, c in enumerate(cs): - cs[i] = map(lambda x: x.strip().replace(" ", "-"), c.split(",")) - cs[i] = u"{} {} {}:{}".format(*cs[i]) + cs[i] = [x.strip().replace(" ", "-") for x in c.split(",")] + cs[i] = "{} {} {}:{}".format(*cs[i]) return cs def get_data(self): data = self.cleaned_data ret = {} - ret['elName'] = data.get('name') - ret['electedLimit'] = data.get('elected_limit') or 0 - ret["votingStarts"] = data.get('voting_starts') - ret["votingEnds"] = data.get('voting_ends') - ret["institution"] = data.get('institution') - ret["numOfEligibles"] = int(data.get('eligibles_count')) + ret["elName"] = data.get("name") + ret["electedLimit"] = data.get("elected_limit") or 0 + ret["votingStarts"] = data.get("voting_starts") + ret["votingEnds"] = data.get("voting_ends") + ret["institution"] = data.get("institution") + ret["numOfEligibles"] = int(data.get("eligibles_count")) cands = self.get_candidates() schools = defaultdict(lambda: []) for i, c in enumerate(cands): name, school = c.split(":") name, surname, fathername = name.split(" ") - entry = {'lastName': surname, 'fatherName': fathername, - 'candidateTmpId': i, 'firstName': name} + entry = { + "lastName": surname, + "fatherName": fathername, + "candidateTmpId": i, + "firstName": name, + } schools[school].append(entry) _schools = [] - for school, cands in schools.iteritems(): - _schools.append({'candidates': cands, 'Name': school}) + for school, cands in schools.items(): + _schools.append({"candidates": cands, "Name": school}) - ret['schools'] = _schools - ret['ballots'] = [] + ret["schools"] = _schools + ret["ballots"] = [] return ret From 63adf3068cf6920ba3890cbc768c78c4d73c9a6d Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sun, 31 Mar 2024 16:53:10 +0300 Subject: [PATCH 2/6] Updated from python 2 to python 3 and fixed static analysis issues --- zeus/auth.py | 55 +++++++++++++++------------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/zeus/auth.py b/zeus/auth.py index 92e148c69..4a76d689c 100644 --- a/zeus/auth.py +++ b/zeus/auth.py @@ -15,9 +15,7 @@ from helios.models import Election, Poll, Trustee, Voter from heliosauth.models import User -from zeus.log import init_election_logger, init_poll_logger, _locals, \ - _close_logger -from zeus.utils import resolve_ip +from zeus.log import init_election_logger, init_poll_logger, _locals import logging logger = logging.getLogger(__name__) @@ -25,6 +23,11 @@ AUTH_RE = re.compile('Basic (\w+[=]*)') +def get_ip(request): + ip = request.META.get('HTTP_X_FORWARDER_FOR', None) + if not ip: + ip = request.META.get('REMOTE_ADDR') + return ip def class_method(func): def wrapper(self, request, *args, **kwargs): @@ -52,31 +55,22 @@ def inner(request, *args, **kwargs): allow_manager = getattr(func, '_allow_manager', False) _check_access = check_access user = request.zeususer - user_id = None if user.is_authenticated(): try: - user_id = user.user_id - _locals.user_id = user_id + _locals.user_id = user.user_id except Exception: raise PermissionDenied("Election cannot be accessed by you") - ip = resolve_ip(request) - _locals.ip = ip + _locals.ip = get_ip(request) if allow_manager and user.is_manager: _check_access = False - logging_locals = { - 'user_id': user_id, - 'ip': ip - } - if 'election_uuid' in kwargs: uuid = kwargs.pop('election_uuid') election = get_object_or_404(Election, uuid=uuid) if not user.can_access_election(election) and _check_access: raise PermissionDenied("Election cannot be accessed by you") kwargs['election'] = election - setattr(election, '_logging_locals', logging_locals) if 'poll_uuid' in kwargs: uuid = kwargs.pop('poll_uuid') @@ -84,29 +78,12 @@ def inner(request, *args, **kwargs): if not user.can_access_poll(poll) and _check_access: raise PermissionDenied("Poll cannot be accessed by you") kwargs['poll'] = poll - setattr(poll, '_logging_locals', logging_locals) - - resp = func(request, *args, **kwargs) - if 'poll' in kwargs: - _close_logger(kwargs['poll']) - if 'election' in kwargs: - _close_logger(kwargs['election']) - return resp + return func(request, *args, **kwargs) return inner return wrapper -def poll_voter_or_admin_required(func): - @election_view() - @wraps(func) - def wrapper(request, *args, **kwargs): - if not request.zeususer.is_voter and not request.zeususer.is_admin: - raise PermissionDenied("Voter or admin can only access this view.") - return func(request, *args, **kwargs) - return wrapper - - def poll_voter_required(func): @election_view() @wraps(func) @@ -237,7 +214,7 @@ def from_request(self, request): user = None try: users = get_users_from_request(request) - user = filter(lambda x:bool(x), users)[0] + user = [x for x in users if bool(x)][0] except IndexError: pass return ZeusUser(user) @@ -260,7 +237,8 @@ def __init__(self, user_obj): self.is_trustee = True if isinstance(self._user, Voter): - self.is_voter = True + if not self._user.excluded_at: + self.is_voter = True @property def user_id(self): @@ -340,7 +318,7 @@ def get_users_from_request(request): user, admin, trustee, voter = None, None, None, None # identify user and admin - if session.has_key(USER_SESSION_KEY): + if USER_SESSION_KEY in session: user = request.session[USER_SESSION_KEY] try: user = User.objects.get(pk=user) @@ -350,7 +328,7 @@ def get_users_from_request(request): pass # idenitfy voter - if session.has_key(VOTER_SESSION_KEY): + if VOTER_SESSION_KEY in session: voter = request.session[VOTER_SESSION_KEY] try: @@ -400,7 +378,7 @@ def get_users_from_request(request): admin = None # cleanup duplicate logins - if len(filter(lambda x:bool(x), [voter, trustee, admin])) > 1: + if len([x for x in [voter, trustee, admin] if bool(x)]) > 1: if voter: if trustee: del session[TRUSTEE_SESSION_KEY] @@ -414,10 +392,9 @@ def get_users_from_request(request): def allow_manager_access(func): func._allow_manager = True - func.func_globals['foo'] = 'bar' + func.__globals__['foo'] = 'bar' return func - def make_shibboleth_login_url(endpoint): shibboleth_login = reverse('shibboleth_login', kwargs={'endpoint': endpoint}) url = '/'.join(s.strip('/') for s in filter(bool,[ From d15e54bdedb0d177815d1916008be0eb0f1f1701 Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sun, 31 Mar 2024 16:55:01 +0300 Subject: [PATCH 3/6] Fixed mistakes from translation --- zeus/locale/el/LC_MESSAGES/django.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zeus/locale/el/LC_MESSAGES/django.po b/zeus/locale/el/LC_MESSAGES/django.po index 15be63a0e..c55c7de2e 100755 --- a/zeus/locale/el/LC_MESSAGES/django.po +++ b/zeus/locale/el/LC_MESSAGES/django.po @@ -339,7 +339,7 @@ msgid "Email" msgstr "Email" #, python-format -msgid "%d deliveries available" +msgid "%d sms deliveries available" msgstr "%d αποστολές sms διαθέσιμες" msgid "Please provide SMS body" @@ -450,7 +450,7 @@ msgstr "" "Οι ψηφοφόροι θα μπορούν να επικοινωνούν σε αυτό το τηλέφωνο για υποστήριξη " "σε θέματα της ψηφοφορίας" -msgid "Whether or not to allow remote mixing" +msgid "Choose whether or not you want to allow remote mixing" msgstr "" "Επιλέξτε αν θέλετε να παρέχετε εξωτερικά στάδια μίξης μετά την ψηφοφορία -- " "αφήστε κενό εάν δεν είστε σίγουρος/η" @@ -460,7 +460,7 @@ msgstr "" "Οι ψηφοφόροι θα πρέπει να αποδεχθούν το παρακάτω κείμενο προκειμένου να " "μπορέσουν να καταθέσουν την ψήφο τους." -msgid "Whether or not to enable election forum" +msgid "Choose whether or not you want to enable election forum" msgstr "Επιλέξτε αν θέλετε να ενεργοποιήσετε τη δυνατότητα διαβούλευσης" msgid "Forum access starts at" @@ -484,7 +484,7 @@ msgid "Are you sure you want to freeze the election ?" msgstr "Επιβεβαιώστε την οριστικοποίηση της ψηφοφορίας" msgid "Are you sure you want to delete the selected poll ?" -msgstr "Επιβεβαιώστε τη διαγραφή της επιλεγμένης κάλπης" +msgstr "Είστε σίγουρος ότι θέλετε να διαγράψετε τηv επιλεγμένης κάλπης" msgid "Admin guide for" msgstr "Οδηγός διαχειριστή για" @@ -537,7 +537,7 @@ msgstr "Εξαιρεθέντες ψηφοφόροι" msgid "Poll name" msgstr "Όνομα κάλπης" -msgid "RESULTS" +msgid "GENERAL RESULTS" msgstr "ΑΠΟΤΕΛΕΣΜΑΤΑ ΓΕΝΙΚΑ" msgid "TOTAL VOTES" @@ -598,7 +598,7 @@ msgid "Eliminated" msgstr "Αποκλεισμός" msgid "Eliminated due to quota restriction" -msgstr "Αποκλεισμός λόγω περιορισμού" +msgstr "Αποκλεισμός λόγω περιορισμού ποσοστώσεων" msgid "Elected" msgstr "Εκλεγμένοι" @@ -624,7 +624,7 @@ msgstr "ΝΑΙ" msgid "RANKING" msgstr "ΒΑΘΜΟΛΟΓΙΚΗ ΚΑΤΑΤΑΞΗ" -msgid "SCORES" +msgid "DETAILED SCORES" msgstr "ΒΑΘΜΟΛΟΓΙΕΣ ΑΝΑΛΥΤΙΚΑ" msgid "SCORES:" From 6bff774b77991c993afedc17c3f0bfe6e5e9268b Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sun, 31 Mar 2024 16:55:59 +0300 Subject: [PATCH 4/6] Updated from python 2 to python 3 and fixed static analysis issues --- zeus/views/admin.py | 80 +++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/zeus/views/admin.py b/zeus/views/admin.py index e3caf1c1c..111613b4d 100644 --- a/zeus/views/admin.py +++ b/zeus/views/admin.py @@ -1,16 +1,15 @@ -import copy -import datetime -import cStringIO as StringIO +from datetime import datetime +import io as StringIO from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse from django.conf import settings -from django.contrib import messages + from django.views.generic import View from zeus.reports import ElectionsReportCSV, ElectionsReport -from zeus.utils import render_template, ELECTION_TABLE_HEADERS,\ - get_filters, ELECTION_SEARCH_FIELDS, ELECTION_BOOL_KEYS_MAP,\ +from zeus.utils import render_template, ELECTION_TABLE_HEADERS, \ + get_filters, ELECTION_SEARCH_FIELDS, ELECTION_BOOL_KEYS_MAP, \ REPORT_TABLE_HEADERS, REPORT_SEARCH_FIELDS, REPORT_BOOL_KEYS_MAP from zeus import auth @@ -19,22 +18,31 @@ class HomeView(View): + """ + View class for handling home page related requests. + """ + @auth.class_method @auth.election_admin_required - def get(request, *args, **kwargs): + def get(self, request, *args, **kwargs): + """ + Handle HTTP GET requests for displaying the home page. + """ page = int(request.GET.get('page', 1)) - limit = int(request.GET.get('limit', 10)) + q_param = request.GET.get('q', '') - default_elections_per_page = getattr(settings, 'ELECTIONS_PER_PAGE', 20) - elections_per_page = request.GET.get('limit', default_elections_per_page) + default_elections_per_page = getattr(settings, + 'ELECTIONS_PER_PAGE', 20) + elections_per_page = request.GET.get('limit', + default_elections_per_page) try: elections_per_page = int(elections_per_page) - except: + except ValueError: elections_per_page = default_elections_per_page - order_by=request.GET.get('order', 'created_at') + order_by = request.GET.get('order', 'created_at') order_type = request.GET.get('order_type', 'desc') - if not order_by in ELECTION_TABLE_HEADERS: + if order_by not in ELECTION_TABLE_HEADERS: order_by = 'name' elections = Election.objects.administered_by(request.admin) @@ -42,7 +50,8 @@ def get(request, *args, **kwargs): if nr_unfiltered_elections == 0: return HttpResponseRedirect(reverse('election_create')) - elections = elections.filter(get_filters(q_param, ELECTION_TABLE_HEADERS, + elections = elections.filter(get_filters(q_param, + ELECTION_TABLE_HEADERS, ELECTION_SEARCH_FIELDS, ELECTION_BOOL_KEYS_MAP)) elections = elections.order_by(order_by) @@ -52,7 +61,7 @@ def get(request, *args, **kwargs): context = { 'is_superadmin': request.admin.superadmin_p, 'elections_administered': elections, - 'election_table_headers': ELECTION_TABLE_HEADERS.iteritems(), + 'election_table_headers': iter(ELECTION_TABLE_HEADERS.items()), 'q': q_param, 'page': page, 'elections_per_page': elections_per_page, @@ -61,13 +70,16 @@ def get(request, *args, **kwargs): @auth.class_method @auth.manager_or_superadmin_required - def post(request, *args, **kwargs): + def post(self, request, *args, **kwargs): + """ + Handle HTTP POST requests to update the official status of elections. + """ official = request.POST.getlist('official', '') uuid = request.POST.getlist('uuid', None) - for status, id in zip(official, uuid): + for status, election_uuid in zip(official, uuid): try: - election = Election.objects.get(uuid=id) + election = Election.objects.get(uuid=election_uuid) if status == '': status = None else: @@ -75,12 +87,18 @@ def post(request, *args, **kwargs): election.official = status election.save() - except: + except Election.DoesNotExist: + pass + except ValueError: pass return HttpResponseRedirect(reverse('admin_home')) + def find_elections(request): + """ + Find elections based on various filters provided in the request parameters. + """ order_by = request.GET.get('order', 'completed_at') order_type = request.GET.get('order_type', 'desc') start_date = request.GET.get('start_date', None) @@ -88,7 +106,7 @@ def find_elections(request): q = request.GET.get('q', '') # basic filters - filter = { + basic_filter = { 'trial': False, 'completed_at__isnull': False, } @@ -101,10 +119,12 @@ def find_elections(request): # filter by date if start_date: - filter['voting_starts_at__gte'] = datetime.strptime(start_date, "%d %b %Y") + basic_filter['voting_starts_at__gte'] = datetime.strptime(start_date, + "%d %b %Y") if end_date: - filter['voting_starts_at__lte'] = datetime.strptime(end_date, "%d %b %Y") + basic_filter['voting_starts_at__lte'] = datetime.strptime(end_date, + "%d %b %Y") # filter by query q_filters = get_filters( @@ -114,10 +134,10 @@ def find_elections(request): REPORT_BOOL_KEYS_MAP ) - if not order_by in ELECTION_TABLE_HEADERS: + if order_by not in ELECTION_TABLE_HEADERS: order_by = 'completed_at' - elections = Election.objects.filter(**filter).order_by(order_by) + elections = Election.objects.filter(**basic_filter).order_by(order_by) elections = elections.filter(q_filters) if order_type == 'desc': @@ -125,6 +145,7 @@ def find_elections(request): return elections + @auth.manager_or_superadmin_required def elections_report_csv(request): """ @@ -146,9 +167,10 @@ def elections_report_csv(request): fd.seek(0) response = HttpResponse(fd, content_type='application/csv') - response['Content-Disposition'] = 'attachment; filename=%s.csv' % filename + response['Content-Disposition'] = f'attachment; filename={filename}.csv' return response + @auth.manager_or_superadmin_required def elections_report(request): """ @@ -156,7 +178,7 @@ def elections_report(request): """ q_param = request.GET.get('q', '') - polls_count = votes_count = voters_count = 0 + polls_count = voters_count = 0 percentage_voted = voters_voted_count = 0 elections = find_elections(request) @@ -170,11 +192,11 @@ def elections_report(request): voters_count += election['nr_voters'] voters_voted_count += election['nr_voters_voted'] - if not voters_count is 0: + if voters_count != 0: percentage_voted = (voters_voted_count / float(voters_count)) * 100 params = '' - for key, value in request.GET.items(): + for key, value in list(request.GET.items()): params = params + key + '=' + value + '&' params = params[:-1] @@ -186,7 +208,7 @@ def elections_report(request): 'percentage_voted': percentage_voted, 'elections': report.objectData, 'elections_per_page': 10, - 'report_table_headers': REPORT_TABLE_HEADERS.items(), + 'report_table_headers': list(REPORT_TABLE_HEADERS.items()), 'params': params, 'q': q_param } From 777245b3df6f39819f4f7ae0844faeceae479160 Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sun, 31 Mar 2024 16:56:18 +0300 Subject: [PATCH 5/6] Updated from python 2 to python 3 and fixed static analysis issues --- zeus/widgets.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/zeus/widgets.py b/zeus/widgets.py index 6faa60440..4824d937a 100644 --- a/zeus/widgets.py +++ b/zeus/widgets.py @@ -1,27 +1,19 @@ # -*- coding: utf-8 -*- import datetime +from time import strftime from time import strptime, strftime -from django import forms -from django.db import models +from django import forms #removed duplicate import from django.forms import fields -from django import forms from django.db import models from django.template.loader import render_to_string from django.forms.widgets import Select, MultiWidget, DateInput, TextInput -from time import strftime - +hour_selections = [("%02d:%02d" % (t, m), "%02d:%02d" % (t, m)) for t in range(24) for m in range(0, 60, 15)] -hour_selections = [('','')] -for t in range(24): - hour_selections.extend([("%02d:00" % t, "%02d:00" % t), - ("%02d:15" % t, "%02d:15" % t), - ("%02d:30" % t, "%02d:30" % t), - ("%02d:45" % t, "%02d:45" % t)]) hour_selections.append(('23:59', '23:59')) - +#divides date and time election data into two django widgets class JqSplitDateTimeWidget(MultiWidget): def __init__(self, attrs=None, date_format=None, time_format=None): @@ -48,7 +40,7 @@ def decompress(self, value): timetuple = value.timetuple() d = strftime("%Y-%m-%d", timetuple) timeofday = strftime("%H:%M", timetuple) - if not timeofday in dict(hour_selections).keys(): + if not timeofday in list(dict(hour_selections).keys()): timeofday = strftime("%H:00",timetuple) return [d, timeofday] else: @@ -67,7 +59,7 @@ def format_output(self, rendered_widgets): """ % (rendered_widgets[0], rendered_widgets[1]) - +#compression of date and time fields into one object class JqSplitDateTimeField(fields.MultiValueField): widget = JqSplitDateTimeWidget From 2a13d6bf038b726f2eba589ab8513156ce6419a9 Mon Sep 17 00:00:00 2001 From: Giannis Sarantopoulos Date: Sun, 31 Mar 2024 16:57:15 +0300 Subject: [PATCH 6/6] Updated from python 2 to python 3 and fixed static analysis issues --- zeus_forum/util.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/zeus_forum/util.py b/zeus_forum/util.py index 75a781e84..22c6bee8a 100644 --- a/zeus_forum/util.py +++ b/zeus_forum/util.py @@ -1,12 +1,14 @@ import markdown -import bleach +# https://stackoverflow.com/a/41831049 +# from django.conf import settings +# from django.db import DEFAULT_DB_ALIAS +# from django.db.transaction import Atomic, get_connection from zeus.utils import sanitize_html from contextlib import contextmanager from django.db import connection, transaction - def parse_markdown(text): md = markdown.Markdown( safe_mode='escape', @@ -16,12 +18,6 @@ def parse_markdown(text): return sanitize_html(html) -# https://stackoverflow.com/a/41831049 -from django.conf import settings -from django.db import DEFAULT_DB_ALIAS -from django.db.transaction import Atomic, get_connection - - @contextmanager def lock_atomic(lock_id=1): cursor = connection.cursor()