Add view to edit nomcom

Merge public key edit view whith nomcom edit view
Add view to delete nomcom
Add hash url to accept o decline nominations
Change new nominee template to include hash urls
See #976 #977
 - Legacy-Id: 5578
This commit is contained in:
Emilio Jiménez 2013-03-19 17:51:09 +00:00
parent d3731ce77e
commit a9c33ed9f1
9 changed files with 174 additions and 32 deletions

View file

@ -1,3 +1,5 @@
import datetime
from django.conf import settings
from django import forms
from django.contrib.formtools.preview import FormPreview, AUTO_ID
@ -8,6 +10,7 @@ from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.contrib.sites.models import Site
from ietf.dbtemplate.forms import DBTemplateForm
from ietf.utils import unaccent
@ -22,7 +25,7 @@ from ietf.nomcom.models import NomCom, Nomination, Nominee, NomineePosition, \
from ietf.nomcom.utils import QUESTIONNAIRE_TEMPLATE, NOMINATION_EMAIL_TEMPLATE, \
INEXISTENT_PERSON_TEMPLATE, NOMINEE_EMAIL_TEMPLATE, \
NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE, \
get_user_email
get_user_email, get_hash_nominee_position, get_year_by_nomcom
from ietf.nomcom.decorators import member_required
ROLODEX_URL = getattr(settings, 'ROLODEX_URL', None)
@ -190,17 +193,13 @@ class EditChairFormPreview(FormPreview):
return HttpResponseRedirect(reverse('nomcom_edit_chair', kwargs={'year': self.year}))
class EditPublicKeyForm(BaseNomcomForm, forms.ModelForm):
class EditNomcomForm(BaseNomcomForm, forms.ModelForm):
fieldsets = [('Public Key', ('public_key',))]
fieldsets = [('Edit nomcom', ('public_key', 'send_questionnaire'))]
class Meta:
model = NomCom
fields = ('public_key',)
def __init__(self, *args, **kwargs):
super(EditPublicKeyForm, self).__init__(*args, **kwargs)
self.fields['public_key'].required = True
fields = ('public_key', 'send_questionnaire')
class MergeForm(BaseNomcomForm, forms.Form):
@ -393,8 +392,30 @@ class NominateForm(BaseNomcomForm, forms.ModelForm):
subject = 'IETF Nomination Information'
from_email = settings.NOMCOM_FROM_EMAIL
to_email = email.address
domain = Site.objects.get_current().domain
today = datetime.date.today().strftime('%Y%m%d')
hash = get_hash_nominee_position(today, nominee_position.id)
accept_url = reverse('nomcom_process_nomination_status',
None,
args=(get_year_by_nomcom(self.nomcom),
nominee_position.id,
'accepted',
today,
hash))
decline_url = reverse('nomcom_process_nomination_status',
None,
args=(get_year_by_nomcom(self.nomcom),
nominee_position.id,
'declined',
today,
hash))
context = {'nominee': email.person.name,
'position': position.name}
'position': position.name,
'domain': domain,
'accept_url': accept_url,
'decline_url': decline_url}
path = nomcom_template_path + NOMINEE_EMAIL_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)

View file

@ -1,4 +1,5 @@
from django.conf.urls.defaults import patterns, url
from django.views.generic.simple import direct_to_template
from ietf.nomcom.forms import EditChairForm, EditChairFormPreview, \
EditMembersForm, EditMembersFormPreview
@ -14,7 +15,9 @@ urlpatterns = patterns('ietf.nomcom.views',
url(r'^(?P<year>\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'),
url(r'^(?P<year>\d{4})/private/edit-members/$', EditMembersFormPreview(EditMembersForm), name='nomcom_edit_members'),
url(r'^(?P<year>\d{4})/private/edit-chair/$', EditChairFormPreview(EditChairForm), name='nomcom_edit_chair'),
url(r'^(?P<year>\d{4})/private/edit-publickey/$', 'edit_publickey', name='nomcom_edit_publickey'),
url(r'^(?P<year>\d{4})/private/edit-nomcom/$', 'edit_nomcom', name='nomcom_edit_nomcom'),
url(r'^(?P<year>\d{4})/private/delete-nomcom/$', 'delete_nomcom', name='nomcom_delete_nomcom'),
url(r'^deleted/$', direct_to_template, {'template': 'nomcom/deleted.html'}, name='nomcom_deleted'),
url(r'^(?P<year>\d{4})/private/chair/templates/$', 'list_templates', name='nomcom_list_templates'),
url(r'^(?P<year>\d{4})/private/chair/templates/(?P<template_id>\d+)/$', 'edit_template', name='nomcom_edit_template'),
url(r'^(?P<year>\d{4})/private/chair/position/$', 'list_positions', name='nomcom_list_positions'),
@ -27,6 +30,7 @@ urlpatterns = patterns('ietf.nomcom.views',
url(r'^(?P<year>\d{4})/questionnaires/$', 'questionnaires', name='nomcom_questionnaires'),
url(r'^(?P<year>\d{4})/feedback/$', 'public_feedback', name='nomcom_public_feedback'),
url(r'^(?P<year>\d{4})/nominate/$', 'public_nominate', name='nomcom_public_nominate'),
url(r'^(?P<year>\d{4})/process-nomination-status/(?P<nominee_position_id>\d+)/(?P<state>[\w]+)/(?P<date>[\d]+)/(?P<hash>[a-f0-9]+)/$', 'process_nomination_status', name='nomcom_process_nomination_status'),
url(r'^ajax/position-text/(?P<position_id>\d+)/$', 'ajax_position_text', name='nomcom_ajax_position_text'),
)

View file

@ -1,3 +1,6 @@
import hashlib
import re
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
@ -34,6 +37,12 @@ def get_nomcom_by_year(year):
group__state__slug='active')
def get_year_by_nomcom(nomcom):
acronym = nomcom.group.acronym
m = re.search('(?P<year>\d\d\d\d)', acronym)
return m.group(0)
def get_user_email(user):
emails = Email.objects.filter(person__user=user)
email = emails and emails[0] or None
@ -52,6 +61,10 @@ def is_nomcom_chair(user, nomcom):
raise PermissionDenied("Must be nomcom chair")
def get_hash_nominee_position(date, nominee_position_id):
return hashlib.md5('%s%s%s' % (settings.SECRET_KEY, date, nominee_position_id)).hexdigest()
def initialize_templates_for_group(group):
for template_name in DEFAULT_NOMCOM_TEMPLATES:
template_path = MAIN_NOMCOM_TEMPLATE_PATH + template_name

View file

@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
import datetime
from django.views.generic.create_update import delete_object
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.template.loader import render_to_string
@ -17,12 +20,14 @@ from ietf.dbtemplate.views import template_edit
from ietf.name.models import NomineePositionState, FeedbackType
from ietf.nomcom.decorators import member_required, private_key_required
from ietf.nomcom.forms import (EditPublicKeyForm, NominateForm, FeedbackForm, MergeForm,
NomComTemplateForm, PositionForm, PrivateKeyForm)
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback
from ietf.nomcom.forms import (NominateForm, FeedbackForm, MergeForm,
NomComTemplateForm, PositionForm, PrivateKeyForm,
EditNomcomForm)
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom
from ietf.nomcom.utils import (get_nomcom_by_year, HOME_TEMPLATE,
retrieve_nomcom_private_key,
store_nomcom_private_key, NOMINEE_REMINDER_TEMPLATE)
store_nomcom_private_key, get_hash_nominee_position,
NOMINEE_REMINDER_TEMPLATE)
def index(request, year):
@ -71,13 +76,13 @@ def private_index(request, year):
nominations = all_nominee_positions.filter(id__in=nominations_to_modify)
if action == "set_as_accepted":
nominations.update(state='accepted')
message = ('success', 'The selected nominations has been set as accepted')
message = ('success', 'The selected nominations have been set as accepted')
elif action == "set_as_declined":
nominations.update(state='declined')
message = ('success', 'The selected nominations has been set as declined')
message = ('success', 'The selected nominations have been set as declined')
elif action == "set_as_pending":
nominations.update(state='pending')
message = ('success', 'The selected nominations has been set as pending')
message = ('success', 'The selected nominations have been set as pending')
else:
message = ('warning', "Please, select some nominations to work with")
@ -164,7 +169,7 @@ def private_merge(request, year):
form = MergeForm(request.POST, nomcom=nomcom)
if form.is_valid():
form.save()
message = ('success', 'The emails has been unified')
message = ('success', 'The emails have been unified')
else:
form = MergeForm(nomcom=nomcom)
@ -251,6 +256,42 @@ def private_feedback(request, year):
return feedback(request, year, False)
def process_nomination_status(request, year, nominee_position_id, state, date, hash):
valid = get_hash_nominee_position(date, nominee_position_id) == hash
if not valid:
return HttpResponseForbidden("Bad hash!")
expiration_days = getattr(settings, 'DAYS_TO_EXPIRE_NOMINATION_LINK', None)
if expiration_days:
request_date = datetime.date(int(date[:4]), int(date[4:6]), int(date[6:]))
if datetime.date.today() > (request_date + datetime.timedelta(days=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK)):
return HttpResponseForbidden("Link expired")
need_confirmation = True
nomcom = get_nomcom_by_year(year)
nominee_position = get_object_or_404(NomineePosition, id=nominee_position_id)
if nominee_position.state.slug != "pending":
return HttpResponseForbidden("The nomination already was %s" % nominee_position.state)
state = get_object_or_404(NomineePositionState, slug=state)
message = ('warning', "Are you sure to change the nomination on %s as %s?" % (nominee_position.position.name,
state.name))
if request.method == 'POST':
nominee_position.state = state
nominee_position.save()
need_confirmation = False
message = message = ('success', 'Your nomination on %s has been set as %s' % (nominee_position.position.name,
state.name))
return render_to_response('nomcom/process_nomination_status.html',
{'message': message,
'nomcom': nomcom,
'year': year,
'nominee_position': nominee_position,
'state': state,
'need_confirmation': need_confirmation,
'selected': 'feedback'}, RequestContext(request))
def feedback(request, year, public):
nomcom = get_nomcom_by_year(year)
has_publickey = nomcom.public_key and True or False
@ -358,27 +399,42 @@ def view_feedback_nominee(request, year, nominee_id):
@member_required(role='chair')
def edit_publickey(request, year):
def edit_nomcom(request, year):
nomcom = get_nomcom_by_year(year)
message = ('warning', 'Previous data will remain encrypted with the old key')
if request.method == 'POST':
form = EditPublicKeyForm(request.POST,
request.FILES,
instance=nomcom,
initial={'public_key': None})
form = EditNomcomForm(request.POST,
request.FILES,
instance=nomcom)
if form.is_valid():
form.save()
message = ('success', 'The public key has been changed')
message = ('success', 'The nomcom has been changed')
else:
form = EditPublicKeyForm()
form = EditNomcomForm(instance=nomcom)
return render_to_response('nomcom/edit_publickey.html',
return render_to_response('nomcom/edit_nomcom.html',
{'form': form,
'group': nomcom.group,
'nomcom': nomcom,
'message': message,
'year': year,
'selected': 'edit_publickey'}, RequestContext(request))
'selected': 'edit_nomcom'}, RequestContext(request))
@member_required(role='chair')
def delete_nomcom(request, year):
nomcom = get_nomcom_by_year(year)
post_delete_redirect = reverse('nomcom_deleted')
extra_context = {'year': year,
'selected': 'edit_nomcom',
'nomcom': nomcom}
return delete_object(request,
model=NomCom,
object_id=nomcom.id,
post_delete_redirect=post_delete_redirect,
template_name='nomcom/delete_nomcom.html',
extra_context=extra_context)
@member_required(role='chair')

View file

@ -0,0 +1,15 @@
{% extends "nomcom/nomcom_private_base.html" %}
{% block subtitle %}- Delete Nomcom{% endblock %}
{% block nomcom_content %}
<p>Are you sure you want to delete all data about {{ nomcom.group.name }}?</p>
<form action="" method="post">{% csrf_token %}
<div>
<input type="hidden" name="post" value="yes" />
<input type="submit" value="Yes, I'm sure" />
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,7 @@
{% extends "nomcom/nomcom_base.html" %}
{% block content %}
<div class="info-message-success">All data about the nomcom has been removed</div>
{% endblock %}

View file

@ -1,9 +1,9 @@
{% extends "nomcom/nomcom_private_base.html" %}
{% block subtitle %}- Edit public key{% endblock %}
{% block subtitle %}- Edit Nomcom{% endblock %}
{% block nomcom_content %}
<h2>Edit public key</h2>
<h2>Edit Nomcom</h2>
{% if message %}
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
@ -18,4 +18,8 @@
<p><input type="submit" value="Save" /></p>
</form>
<h2>Delete Nomcom</h2>
<p>To delete all data about {{ nomcom.group.name }}, <a href="{% url nomcom_delete_nomcom year %}" class="deletelink">click here</a></p>
{% endblock %}

View file

@ -16,7 +16,7 @@
{% if selected == "merge" %}<span class="selected">Merge nominee email addr</span>{% else %}<a href="{% url nomcom_private_merge year %}">Merge nominee email addr</a>{% endif %} |
{% if selected == "send_reminder_mail" %}<span class="selected">Send Reminder Mail</span>{% else %}<a href="{% url nomcom_send_reminder_mail year %}">Send reminder mail</a>{% endif %} |
{% if selected == "edit_members" %}<span class="selected">Nomcom members</span>{% else %}<a href="{% url nomcom_edit_members year %}">Nomcom members</a>{% endif %} |
{% if selected == "edit_publickey" %}<span class="selected">Public key</span>{% else %}<a href="{% url nomcom_edit_publickey year %}">Public key</a>{% endif %} |
{% if selected == "edit_nomcom" %}<span class="selected">Edit Nomcom</span>{% else %}<a href="{% url nomcom_edit_nomcom year %}">Edit Nomcom</a>{% endif %} |
{% if selected == "edit_templates" %}<span class="selected">Templates</span>{% else %}<a href="{% url nomcom_list_templates year %}">Templates</a>{% endif %} |
{% if selected == "edit_positions" %}<span class="selected">Positions</span>{% else %}<a href="{% url nomcom_list_positions year %}">Positions</a>{% endif %}
{% endif %}

View file

@ -0,0 +1,22 @@
{% extends "nomcom/nomcom_public_base.html" %}
{% block subtitle %} - Change Nomination {% endblock %}
{% block nomcom_content %}
{% if message %}
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
{% endif %}
{% if need_confirmation %}
<form action="" method="post">{% csrf_token %}
{{ form }}
<div class="submitrow">
<input type="submit" value="Save" name="save"/>
</div>
</form>
{% endif %}
{% endblock %}