From cfaed84ba532123ffdce19e4eab94c1169b4088c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20A=2E=20S=C3=A1nchez=20L=C3=B3pez?= Date: Fri, 11 Feb 2011 13:12:37 +0000 Subject: [PATCH] Authenticated post actions. Fixes #597 - Legacy-Id: 2850 --- ietf/submit/forms.py | 2 +- ietf/submit/urls.py | 1 + ietf/submit/utils.py | 42 ++++++++---- ietf/submit/views.py | 88 +++++++++++++++++-------- ietf/templates/submit/draft_status.html | 18 ++++- 5 files changed, 104 insertions(+), 47 deletions(-) diff --git a/ietf/submit/forms.py b/ietf/submit/forms.py index 7f58623b2..7b4cf25c6 100644 --- a/ietf/submit/forms.py +++ b/ietf/submit/forms.py @@ -416,7 +416,7 @@ class MetaDataForm(AutoPostForm): if existing_revisions: expected = max(existing_revisions) + 1 if version_int != expected: - raise forms.ValidationError('Invalid Version Number (Version %00d is expected)' % expected) + raise forms.ValidationError('Invalid Version Number (Version %02d is expected)' % expected) return version def clean(self): diff --git a/ietf/submit/urls.py b/ietf/submit/urls.py index 4afee3f09..7e39c6d92 100644 --- a/ietf/submit/urls.py +++ b/ietf/submit/urls.py @@ -9,6 +9,7 @@ urlpatterns = patterns('ietf.submit.views', url(r'^status/(?P\d+)/confirm/(?P[a-f\d]+)/$', 'draft_confirm', name='draft_confirm'), url(r'^status/(?P\d+)/cancel/$', 'draft_cancel', name='draft_cancel'), url(r'^status/(?P\d+)/approve/$', 'draft_approve', name='draft_approve'), + url(r'^status/(?P\d+)/force/$', 'draft_force', name='draft_force'), ) urlpatterns += patterns('django.views.generic.simple', diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py index 7f88ecbf6..3d578b701 100644 --- a/ietf/submit/utils.py +++ b/ietf/submit/utils.py @@ -3,7 +3,7 @@ import re import datetime from django.conf import settings -from ietf.idtracker.models import InternetDraft, EmailAddress, PersonOrOrgInfo +from ietf.idtracker.models import InternetDraft, PersonOrOrgInfo # Some usefull states @@ -38,23 +38,37 @@ def perform_post(submission): updated = True except InternetDraft.DoesNotExist: draft = InternetDraft.objects.create( - title = submission.id_document_name, - group_id = group_id, - filename = submission.filename, - revision = submission.revision, - revision_date = submission.creation_date, - file_type = submission.file_type, - txt_page_count = submission.txt_page_count, - start_date = datetime.date.today(), - last_modified_date = datetime.date.today(), - abstract = submission.abstract, - status_id = 1, # Active - intended_status_id = 8, # None + title=submission.id_document_name, + group_id=group_id, + filename=submission.filename, + revision=submission.revision, + revision_date=submission.creation_date, + file_type=submission.file_type, + txt_page_count=submission.txt_page_count, + start_date=datetime.date.today(), + last_modified_date=datetime.date.today(), + abstract=submission.abstract, + status_id=1, # Active + intended_status_id=8, # None ) move_docs(submission) submission.status_id = POSTED submission.save() + +def get_person_for_user(user): + try: + return user.get_profile().person() + except: + return None + + +def is_secretariat(user): + if not user or not user.is_authenticated(): + return False + return bool(user.groups.filter(name='Secretariat')) + + def move_docs(submission): for ext in submission.file_type.split(','): source = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (submission.filename, submission.revision, ext)) @@ -118,7 +132,7 @@ class DraftValidation(object): if existing_revisions: expected = max(existing_revisions) + 1 if int(revision) != expected: - self.add_warning('revision', 'Invalid Version Number (Version %00d is expected)' % expected) + self.add_warning('revision', 'Invalid Version Number (Version %02d is expected)' % expected) def validate_authors(self): if not self.authors: diff --git a/ietf/submit/views.py b/ietf/submit/views.py index d0d207f25..0adb2b8e1 100644 --- a/ietf/submit/views.py +++ b/ietf/submit/views.py @@ -1,7 +1,7 @@ # Copyright The IETF Trust 2007, All Rights Reserved from django.conf import settings from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect, Http404 +from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden from django.shortcuts import get_object_or_404 from django.shortcuts import render_to_response from django.template import RequestContext @@ -10,7 +10,10 @@ from django.core.exceptions import ObjectDoesNotExist from ietf.submit.models import IdSubmissionDetail, IdApprovedDetail from ietf.submit.forms import UploadForm, AutoPostForm, MetaDataForm from ietf.submit.utils import (DraftValidation, perform_post, - UPLOADED, WAITING_AUTHENTICATION, CANCELED, INITIAL_VERSION_APPROVAL_REQUESTED) + get_person_for_user, is_secretariat, + UPLOADED, WAITING_AUTHENTICATION, CANCELED, + INITIAL_VERSION_APPROVAL_REQUESTED, + MANUAL_POST_REQUESTED) from ietf.utils.mail import send_mail @@ -46,12 +49,30 @@ def submit_status(request): +def _can_approve(user, detail): + person = get_person_for_user(user) + if detail.status_id != INITIAL_VERSION_APPROVAL_REQUESTED or not detail.group_acronym: + return None + if person in [i.person for i in detail.group_acronym.wgchair_set.all()] or is_secretariat(user): + return True + return False + +def _can_force_post(user, detail): + person = get_person_for_user(user) + if detail.status_id != MANUAL_POST_REQUESTED: + return None + if is_secretariat(user): + return True + return False + def draft_status(request, submission_id, message=None): detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id) validation = DraftValidation(detail) is_valid = validation.is_valid() status = None allow_edit = True + can_force_post = _can_force_post(request.user, detail) + can_approve = _can_approve(request.user, detail) if detail.status_id != UPLOADED: if detail.status_id == CANCELED: message=('error', 'This submission has been canceled, modification is no longer possible') @@ -60,30 +81,29 @@ def draft_status(request, submission_id, message=None): if request.method=='POST' and allow_edit: if request.POST.get('autopost', False): - try: - approved_detail = IdApprovedDetail.objects.get(filename=detail.filename) - except ObjectDoesNotExist: - approved_detail = None - detail.status_id = INITIAL_VERSION_APPROVAL_REQUESTED - detail.save() + auto_post_form = AutoPostForm(draft=detail, validation=validation, data=request.POST) + if auto_post_form.is_valid(): + try: + approved_detail = IdApprovedDetail.objects.get(filename=detail.filename) + except ObjectDoesNotExist: + approved_detail = None + detail.status_id = INITIAL_VERSION_APPROVAL_REQUESTED + detail.save() - if detail.revision == '00' and not approved_detail: - subject = 'New draft waiting for approval: %s' % detail.filename - from_email = settings.IDST_FROM_EMAIL - to_email = [] - if detail.group_acronym: - to_email += [i.person.email()[1] for i in detail.group_acronym.wgchair_set.all()] - to_email = list(set(to_email)) - if to_email: - metadata_form = MetaDataForm(draft=detail, validation=validation) - send_mail(request, to_email, from_email, subject, 'submit/manual_post_mail.txt', - {'form': metadata_form, 'draft': detail}) - else: - auto_post_form = AutoPostForm(draft=detail, validation=validation, data=request.POST) - if auto_post_form.is_valid(): + if detail.revision == '00' and not approved_detail: + subject = 'New draft waiting for approval: %s' % detail.filename + from_email = settings.IDST_FROM_EMAIL + to_email = [] + if detail.group_acronym: + to_email += [i.person.email()[1] for i in detail.group_acronym.wgchair_set.all()] + to_email = list(set(to_email)) + if to_email: + metadata_form = MetaDataForm(draft=detail, validation=validation) + send_mail(request, to_email, from_email, subject, 'submit/manual_post_mail.txt', + {'form': metadata_form, 'draft': detail}) + return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id})) + else: auto_post_form.save(request) - return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id})) - else: return HttpResponseRedirect(reverse(draft_edit, None, kwargs={'submission_id': detail.submission_id})) else: @@ -97,6 +117,8 @@ def draft_status(request, submission_id, message=None): 'status': status, 'message': message, 'allow_edit': allow_edit, + 'can_force_post': can_force_post, + 'can_approve': can_approve, }, context_instance=RequestContext(request)) @@ -117,6 +139,7 @@ def draft_edit(request, submission_id): form = MetaDataForm(draft=detail, validation=validation, data=request.POST) if form.is_valid(): form.save(request) + return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id})) else: form = MetaDataForm(draft=detail, validation=validation) return render_to_response('submit/draft_edit.html', @@ -141,10 +164,17 @@ def draft_confirm(request, submission_id, auth_key): return draft_status(request, submission_id, message) -def draft_approve(request, submission_id): +def draft_approve(request, submission_id, check_function=_can_approve): detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id) - if detail.status_id == INITIAL_VERSION_APPROVAL_REQUESTED: - validation = DraftValidation(detail) - approved_detail = IdApprovedDetail() - perform_post(detail) + person = get_person_for_user(request.user) + can_perform = check_function(request.user, detail) + if not can_perform: + if can_perform == None: + raise Http404 + return HttpResponseForbidden('You have no permission to perform this action') + perform_post(detail) return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id})) + + +def draft_force(request, submission_id): + return draft_approve(request, submission_id, check_function=_can_force_post) diff --git a/ietf/templates/submit/draft_status.html b/ietf/templates/submit/draft_status.html index 2612b1c99..942b581e4 100644 --- a/ietf/templates/submit/draft_status.html +++ b/ietf/templates/submit/draft_status.html @@ -76,6 +76,10 @@ function confirmCancelation(){
{{ message.1 }}
{% endif %} +{% if auto_post_form.errors %} +
Please fix errors in the form below
+{% endif %} +

Check Page

{% if validation.passes_idnits %} @@ -146,7 +150,7 @@ returned to the submitter. {% if allow_edit %} -

+ (Leads to manual post by the Secretariat)
@@ -181,13 +185,21 @@ returned to the submitter. {% endif %} {% endif %} -{% ifequal status.status_value "Initial Version Approval Requested" %} +{% if can_approve %}

-{% endifequal %} +{% endif %} + +{% if can_force_post %} +

+

+ +
+

+{% endif %}

The IETF is an organized activity of the Internet Society