# Copyright The IETF Trust 2007, All Rights Reserved import base64 import datetime import os import xml2rfc from django.conf import settings from django.contrib import messages from django.core.urlresolvers import reverse as urlreverse from django.core.validators import validate_email, ValidationError from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.utils.module_loading import import_string import debug # pyflakes:ignore from ietf.doc.models import Document, DocAlias, AddedMessageEvent from ietf.doc.utils import prettify_std_name from ietf.group.models import Group from ietf.ietfauth.utils import has_role, role_required from ietf.mailtrigger.utils import gather_address_lists from ietf.message.models import Message, MessageAttachment from ietf.submit.forms import ( SubmissionUploadForm, NameEmailForm, EditSubmissionForm, PreapprovalForm, ReplacesForm, SubmissionEmailForm, MessageModelForm ) from ietf.submit.mail import ( send_full_url, send_approval_request_to_group, send_submission_confirmation, send_manual_post_request, add_submission_email, get_reply_to ) from ietf.submit.models import (Submission, SubmissionCheck, Preapproval, DraftSubmissionStateName, SubmissionEmailEvent ) from ietf.submit.utils import ( approvable_submissions_for_user, preapprovals_for_user, recently_approved_by_user, validate_submission, create_submission_event, docevent_from_submission, post_submission, cancel_submission, rename_submission_files, get_person_from_name_email ) from ietf.utils.accesstoken import generate_random_key, generate_access_token from ietf.utils.draft import Draft from ietf.utils.log import log from ietf.utils.mail import send_mail_message def upload_submission(request): if request.method == 'POST': try: form = SubmissionUploadForm(request, data=request.POST, files=request.FILES) if form.is_valid(): authors = [] file_name = {} abstract = None file_size = None for ext in form.fields.keys(): f = form.cleaned_data[ext] if not f: continue name = os.path.join(settings.IDSUBMIT_STAGING_PATH, '%s-%s.%s' % (form.filename, form.revision, ext)) file_name[ext] = name with open(name, 'wb+') as destination: for chunk in f.chunks(): destination.write(chunk) if form.cleaned_data['xml']: if not form.cleaned_data['txt']: file_name['txt'] = os.path.join(settings.IDSUBMIT_STAGING_PATH, '%s-%s.txt' % (form.filename, form.revision)) try: pagedwriter = xml2rfc.PaginatedTextRfcWriter(form.xmltree, quiet=True) pagedwriter.write(file_name['txt']) except Exception as e: raise ValidationError("Error from xml2rfc: %s" % e) file_size = os.stat(file_name['txt']).st_size # Some meta-information, such as the page-count, can only # be retrieved from the generated text file. Provide a # parsed draft object to get at that kind of information. with open(file_name['txt']) as txt_file: form.parsed_draft = Draft(txt_file.read(), txt_file.name) else: file_size = form.cleaned_data['txt'].size if form.authors: authors = form.authors else: # If we don't have an xml file, try to extract the # relevant information from the text file for author in form.parsed_draft.get_author_list(): full_name, first_name, middle_initial, last_name, name_suffix, email, company = author line = full_name.replace("\n", "").replace("\r", "").replace("<", "").replace(">", "").strip() email = (email or "").strip() if email: try: validate_email(email) except ValidationError: email = "" if email: # Try various ways of handling name and email, in order to avoid # triggering a 500 error here. If the document contains non-ascii # characters, it will be flagged later by the idnits check. try: line += u" <%s>" % email except UnicodeDecodeError: try: line = line.decode('utf-8') email = email.decode('utf-8') line += u" <%s>" % email except UnicodeDecodeError: try: line = line.decode('latin-1') email = email.decode('latin-1') line += u" <%s>" % email except UnicodeDecodeError: try: line += " <%s>" % email except UnicodeDecodeError: pass authors.append(line) if form.abstract: abstract = form.abstract else: abstract = form.parsed_draft.get_abstract() # See if there is a Submission in state waiting-for-draft # for this revision. # If so - we're going to update it otherwise we create a new object submission = Submission.objects.filter(name=form.filename, rev=form.revision, state_id = "waiting-for-draft").distinct() if (len(submission) == 0): submission = None elif (len(submission) == 1): submission = submission[0] submission.state = DraftSubmissionStateName.objects.get(slug="uploaded") submission.remote_ip=form.remote_ip submission.title=form.title submission.abstract=abstract submission.rev=form.revision submission.pages=form.parsed_draft.get_pagecount() submission.authors="\n".join(authors) submission.first_two_pages=''.join(form.parsed_draft.pages[:2]) submission.file_size=file_size submission.file_types=','.join(form.file_types) submission.submission_date=datetime.date.today() submission.document_date=form.parsed_draft.get_creation_date() submission.replaces="" submission.save() else: raise Exception("Multiple submissions found waiting for upload") if (submission == None): try: submission = Submission.objects.create( state=DraftSubmissionStateName.objects.get(slug="uploaded"), remote_ip=form.remote_ip, name=form.filename, group=form.group, title=form.title, abstract=abstract, rev=form.revision, pages=form.parsed_draft.get_pagecount(), authors="\n".join(authors), note="", first_two_pages=''.join(form.parsed_draft.pages[:2]), file_size=file_size, file_types=','.join(form.file_types), submission_date=datetime.date.today(), document_date=form.parsed_draft.get_creation_date(), replaces="", ) except Exception as e: log("Exception: %s\n" % e) raise # run submission checkers def apply_check(submission, checker, method, fn): func = getattr(checker, method) passed, message, errors, warnings, items = func(fn) check = SubmissionCheck(submission=submission, checker=checker.name, passed=passed, message=message, errors=errors, warnings=warnings, items=items, symbol=checker.symbol) check.save() for checker_path in settings.IDSUBMIT_CHECKER_CLASSES: checker_class = import_string(checker_path) checker = checker_class() # ordered list of methods to try for method in ("check_fragment_xml", "check_file_xml", "check_fragment_txt", "check_file_txt", ): ext = method[-3:] if hasattr(checker, method) and ext in file_name: apply_check(submission, checker, method, file_name[ext]) break create_submission_event(request, submission, desc="Uploaded submission") # Don't add an "Uploaded new revision doevent yet, in case of cancellation return redirect("ietf.submit.views.submission_status", submission_id=submission.pk, access_token=submission.access_token()) except IOError as e: if "read error" in str(e): # The server got an IOError when trying to read POST data form = SubmissionUploadForm(request=request) form._errors = {} form._errors["__all__"] = form.error_class(["There was a failure receiving the complete form data -- please try again."]) else: raise except ValidationError as e: form = SubmissionUploadForm(request=request) form._errors = {} form._errors["__all__"] = form.error_class(["There was a failure converting the xml file to text -- please verify that your xml file is valid. (%s)" % e.message]) else: form = SubmissionUploadForm(request=request) return render(request, 'submit/upload_submission.html', {'selected': 'index', 'form': form}) def note_well(request): return render(request, 'submit/note_well.html', {'selected': 'notewell'}) def tool_instructions(request): return render(request, 'submit/tool_instructions.html', {'selected': 'instructions'}) def search_submission(request): error = None name = None if request.method == 'POST': name = request.POST.get('name', '') submission = Submission.objects.filter(name=name).order_by('-pk').first() if submission: return redirect(submission_status, submission_id=submission.pk) error = 'No valid submission found for %s' % name return render(request, 'submit/search_submission.html', {'selected': 'status', 'error': error, 'name': name}) def can_edit_submission(user, submission, access_token): key_matched = access_token and submission.access_token() == access_token if not key_matched: key_matched = submission.access_key == access_token # backwards-compat return key_matched or has_role(user, "Secretariat") def submission_status(request, submission_id, access_token=None): submission = get_object_or_404(Submission, pk=submission_id) key_matched = access_token and submission.access_token() == access_token if not key_matched: key_matched = submission.access_key == access_token # backwards-compat if access_token and not key_matched: raise Http404 errors = validate_submission(submission) passes_checks = all([ c.passed!=False for c in submission.checks.all() ]) is_secretariat = has_role(request.user, "Secretariat") is_chair = submission.group and submission.group.has_role(request.user, "chair") can_edit = can_edit_submission(request.user, submission, access_token) and submission.state_id == "uploaded" can_cancel = (key_matched or is_secretariat) and submission.state.next_states.filter(slug="cancel") can_group_approve = (is_secretariat or is_chair) and submission.state_id == "grp-appr" can_force_post = ( is_secretariat and submission.state.next_states.filter(slug="posted").exists() and submission.state_id != "waiting-for-draft") show_send_full_url = ( not key_matched and not is_secretariat and not submission.state_id in ("cancel", "posted") ) addrs = gather_address_lists('sub_confirmation_requested',submission=submission) confirmation_list = addrs.to confirmation_list.extend(addrs.cc) requires_group_approval = (submission.rev == '00' and submission.group and submission.group.type_id in ("wg", "rg", "ietf", "irtf", "iab", "iana", "rfcedtyp") and not Preapproval.objects.filter(name=submission.name).exists()) requires_prev_authors_approval = Document.objects.filter(name=submission.name) group_authors_changed = False doc = submission.existing_document() if doc and doc.group: old_authors = [ i.author.person for i in doc.documentauthor_set.all() ] new_authors = [ get_person_from_name_email(**p) for p in submission.authors_parsed() ] group_authors_changed = set(old_authors)!=set(new_authors) message = None if submission.state_id == "cancel": message = ('error', 'This submission has been cancelled, modification is no longer possible.') elif submission.state_id == "auth": message = ('success', u'The submission is pending email authentication. An email has been sent to: %s' % ", ".join(confirmation_list)) elif submission.state_id == "grp-appr": message = ('success', 'The submission is pending approval by the group chairs.') elif submission.state_id == "aut-appr": message = ('success', 'The submission is pending approval by the authors of the previous version. An email has been sent to: %s' % ", ".join(confirmation_list)) submitter_form = NameEmailForm(initial=submission.submitter_parsed(), prefix="submitter") replaces_form = ReplacesForm(name=submission.name,initial=DocAlias.objects.filter(name__in=submission.replaces.split(","))) if request.method == 'POST': action = request.POST.get('action') if action == "autopost" and submission.state_id == "uploaded": if not can_edit: return HttpResponseForbidden("You do not have permission to perform this action") submitter_form = NameEmailForm(request.POST, prefix="submitter") replaces_form = ReplacesForm(request.POST, name=submission.name) validations = [submitter_form.is_valid(), replaces_form.is_valid()] if all(validations): submission.submitter = submitter_form.cleaned_line() replaces = replaces_form.cleaned_data.get("replaces", []) submission.replaces = ",".join(o.name for o in replaces) approvals_received = submitter_form.cleaned_data['approvals_received'] if approvals_received: if not is_secretariat: return HttpResponseForbidden('You do not have permission to perform this action') # go directly to posting submission docevent_from_submission(request, submission, desc="Uploaded new revision") desc = u"Secretariat manually posting. Approvals already received" post_submission(request, submission, desc) create_submission_event(request, submission, desc) else: docevent_from_submission(request, submission, desc="Uploaded new revision") if requires_group_approval: submission.state = DraftSubmissionStateName.objects.get(slug="grp-appr") submission.save() sent_to = send_approval_request_to_group(request, submission) desc = "sent approval email to group chairs: %s" % u", ".join(sent_to) docDesc = u"Request for posting approval emailed to group chairs: %s" % u", ".join(sent_to) else: submission.auth_key = generate_random_key() if requires_prev_authors_approval: submission.state = DraftSubmissionStateName.objects.get(slug="aut-appr") else: submission.state = DraftSubmissionStateName.objects.get(slug="auth") submission.save() sent_to = send_submission_confirmation(request, submission, chair_notice=group_authors_changed) if submission.state_id == "aut-appr": desc = u"sent confirmation email to previous authors: %s" % u", ".join(sent_to) docDesc = "Request for posting confirmation emailed to previous authors: %s" % u", ".join(sent_to) else: desc = u"sent confirmation email to submitter and authors: %s" % u", ".join(sent_to) docDesc = "Request for posting confirmation emailed to submitter and authors: %s" % u", ".join(sent_to) msg = u"Set submitter to \"%s\", replaces to %s and %s" % ( submission.submitter, ", ".join(prettify_std_name(r.name) for r in replaces) if replaces else "(none)", desc) create_submission_event(request, submission, msg) docevent_from_submission(request, submission, docDesc, who="(System)") if access_token: return redirect("ietf.submit.views.submission_status", submission_id=submission.pk, access_token=access_token) else: return redirect("ietf.submit.views.submission_status", submission_id=submission.pk) elif action == "edit" and submission.state_id == "uploaded": if access_token: return redirect("ietf.submit.views.edit_submission", submission_id=submission.pk, access_token=access_token) else: return redirect("ietf.submit.views.edit_submission", submission_id=submission.pk) elif action == "sendfullurl" and submission.state_id not in ("cancel", "posted"): sent_to = send_full_url(request, submission) message = ('success', u'An email has been sent with the full access URL to: %s' % u",".join(confirmation_list)) create_submission_event(request, submission, u"Sent full access URL to: %s" % u", ".join(sent_to)) elif action == "cancel" and submission.state.next_states.filter(slug="cancel"): if not can_cancel: return HttpResponseForbidden('You do not have permission to perform this action') cancel_submission(submission) create_submission_event(request, submission, "Cancelled submission") return redirect("ietf.submit.views.submission_status", submission_id=submission_id) elif action == "approve" and submission.state_id == "grp-appr": if not can_group_approve: return HttpResponseForbidden('You do not have permission to perform this action') post_submission(request, submission, "WG -00 approved") create_submission_event(request, submission, "Approved and posted submission") return redirect("doc_view", name=submission.name) elif action == "forcepost" and submission.state.next_states.filter(slug="posted"): if not can_force_post: return HttpResponseForbidden('You do not have permission to perform this action') if submission.state_id == "manual": desc = "Posted submission manually" else: desc = "Forced post of submission" post_submission(request, submission, desc) create_submission_event(request, submission, desc) return redirect("doc_view", name=submission.name) else: # something went wrong, turn this into a GET and let the user deal with it return HttpResponseRedirect("") return render(request, 'submit/submission_status.html', { 'selected': 'status', 'submission': submission, 'errors': errors, 'passes_checks': passes_checks, 'submitter_form': submitter_form, 'replaces_form': replaces_form, 'message': message, 'can_edit': can_edit, 'can_force_post': can_force_post, 'can_group_approve': can_group_approve, 'can_cancel': can_cancel, 'show_send_full_url': show_send_full_url, 'requires_group_approval': requires_group_approval, 'requires_prev_authors_approval': requires_prev_authors_approval, 'confirmation_list': confirmation_list, }) def edit_submission(request, submission_id, access_token=None): submission = get_object_or_404(Submission, pk=submission_id, state="uploaded") if not can_edit_submission(request.user, submission, access_token): return HttpResponseForbidden('You do not have permission to access this page') errors = validate_submission(submission) form_errors = False # we split the form handling into multiple forms, one for the # submission itself, one for the submitter, and a list of forms # for the authors empty_author_form = NameEmailForm(email_required=False) if request.method == 'POST': # get a backup submission now, the model form may change some # fields during validation prev_submission = Submission.objects.get(pk=submission.pk) edit_form = EditSubmissionForm(request.POST, instance=submission, prefix="edit") submitter_form = NameEmailForm(request.POST, prefix="submitter") replaces_form = ReplacesForm(request.POST,name=submission.name) author_forms = [ NameEmailForm(request.POST, email_required=False, prefix=prefix) for prefix in request.POST.getlist("authors-prefix") if prefix != "authors-" ] # trigger validation of all forms validations = [edit_form.is_valid(), submitter_form.is_valid(), replaces_form.is_valid()] + [ f.is_valid() for f in author_forms ] if all(validations): submission.submitter = submitter_form.cleaned_line() replaces = replaces_form.cleaned_data.get("replaces", []) submission.replaces = ",".join(o.name for o in replaces) submission.authors = "\n".join(f.cleaned_line() for f in author_forms) if hasattr(submission, '_cached_authors_parsed'): del submission._cached_authors_parsed edit_form.save(commit=False) # transfer changes if submission.rev != prev_submission.rev: rename_submission_files(submission, prev_submission.rev, submission.rev) submission.state = DraftSubmissionStateName.objects.get(slug="manual") submission.save() send_manual_post_request(request, submission, errors) changed_fields = [ submission._meta.get_field(f).verbose_name for f in list(edit_form.fields.keys()) + ["submitter", "authors"] if getattr(submission, f) != getattr(prev_submission, f) ] if changed_fields: desc = u"Edited %s and sent request for manual post" % u", ".join(changed_fields) else: desc = "Sent request for manual post" create_submission_event(request, submission, desc) return redirect("ietf.submit.views.submission_status", submission_id=submission.pk) else: form_errors = True else: edit_form = EditSubmissionForm(instance=submission, prefix="edit") submitter_form = NameEmailForm(initial=submission.submitter_parsed(), prefix="submitter") replaces_form = ReplacesForm(name=submission.name,initial=DocAlias.objects.filter(name__in=submission.replaces.split(","))) author_forms = [ NameEmailForm(initial=author, email_required=False, prefix="authors-%s" % i) for i, author in enumerate(submission.authors_parsed()) ] return render(request, 'submit/edit_submission.html', {'selected': 'status', 'submission': submission, 'edit_form': edit_form, 'submitter_form': submitter_form, 'replaces_form': replaces_form, 'author_forms': author_forms, 'empty_author_form': empty_author_form, 'errors': errors, 'form_errors': form_errors, }) def confirm_submission(request, submission_id, auth_token): submission = get_object_or_404(Submission, pk=submission_id) key_matched = submission.auth_key and auth_token == generate_access_token(submission.auth_key) if not key_matched: key_matched = auth_token == submission.auth_key # backwards-compat if request.method == 'POST' and submission.state_id in ("auth", "aut-appr") and key_matched: submitter_parsed = submission.submitter_parsed() if submitter_parsed["name"] and submitter_parsed["email"]: # We know who approved it desc = "New version approved" elif submission.state_id == "auth": desc = "New version approved by author" else: desc = "New version approved by previous author" post_submission(request, submission, desc) create_submission_event(request, submission, "Confirmed and posted submission") return redirect("doc_view", name=submission.name) return render(request, 'submit/confirm_submission.html', { 'submission': submission, 'key_matched': key_matched, }) def approvals(request): approvals = approvable_submissions_for_user(request.user) preapprovals = preapprovals_for_user(request.user) days = 30 recently_approved = recently_approved_by_user(request.user, datetime.date.today() - datetime.timedelta(days=days)) return render(request, 'submit/approvals.html', {'selected': 'approvals', 'approvals': approvals, 'preapprovals': preapprovals, 'recently_approved': recently_approved, 'days': days }) @role_required("Secretariat", "Area Director", "WG Chair", "RG Chair") def add_preapproval(request): groups = Group.objects.filter(type__in=("wg", "rg")).exclude(state__in=["conclude","bof-conc"]).order_by("acronym").distinct() if not has_role(request.user, "Secretariat"): groups = groups.filter(role__person__user=request.user,role__name__in=['ad','chair','delegate','secr']) if request.method == "POST": form = PreapprovalForm(request.POST) form.groups = groups if form.is_valid(): p = Preapproval() p.name = form.cleaned_data["name"] p.by = request.user.person p.save() return HttpResponseRedirect(urlreverse("ietf.submit.views.approvals") + "#preapprovals") else: form = PreapprovalForm() return render(request, 'submit/add_preapproval.html', {'selected': 'approvals', 'groups': groups, 'form': form }) @role_required("Secretariat", "WG Chair", "RG Chair") def cancel_preapproval(request, preapproval_id): preapproval = get_object_or_404(Preapproval, pk=preapproval_id) if preapproval not in preapprovals_for_user(request.user): raise HttpResponseForbidden("You do not have permission to cancel this preapproval.") if request.method == "POST" and request.POST.get("action", "") == "cancel": preapproval.delete() return HttpResponseRedirect(urlreverse("ietf.submit.views.approvals") + "#preapprovals") return render(request, 'submit/cancel_preapproval.html', {'selected': 'approvals', 'preapproval': preapproval }) def manualpost(request): ''' Main view for manual post requests ''' manual = Submission.objects.filter(state_id = "manual").distinct() for s in manual: s.passes_checks = all([ c.passed!=False for c in s.checks.all() ]) s.errors = validate_submission(s) waiting_for_draft = Submission.objects.filter(state_id = "waiting-for-draft").distinct() return render(request, 'submit/manual_post.html', {'manual': manual, 'selected': 'manual_posts', 'waiting_for_draft': waiting_for_draft}) def cancel_waiting_for_draft(request): if request.method == 'POST': can_cancel = has_role(request.user, "Secretariat") if not can_cancel: return HttpResponseForbidden('You do not have permission to perform this action') submission_id = request.POST.get('submission_id', '') access_token = request.POST.get('access_token', '') submission = get_submission_or_404(submission_id, access_token = access_token) cancel_submission(submission) create_submission_event(request, submission, "Cancelled submission") if (submission.rev != "00"): # Add a doc event docevent_from_submission(request, submission, "Cancelled submission for rev {}".format(submission.rev)) return redirect("ietf.submit.views.manualpost") @role_required('Secretariat',) def add_manualpost_email(request, submission_id=None, access_token=None): """Add email to submission history""" if request.method == 'POST': try: button_text = request.POST.get('submit', '') if button_text == 'Cancel': return redirect("submit/manual_post.html") form = SubmissionEmailForm(request.POST) if form.is_valid(): submission_pk = form.cleaned_data['submission_pk'] message = form.cleaned_data['message'] #in_reply_to = form.cleaned_data['in_reply_to'] # create Message if form.cleaned_data['direction'] == 'incoming': msgtype = 'msgin' else: msgtype = 'msgout' submission, submission_email_event = ( add_submission_email(request=request, remote_ip=request.META.get('REMOTE_ADDR', None), name = form.draft_name, rev=form.revision, submission_pk = submission_pk, message = message, by = request.user.person, msgtype = msgtype) ) messages.success(request, 'Email added.') try: draft = Document.objects.get(name=submission.name) except Document.DoesNotExist: # Assume this is revision 00 - we'll do this later draft = None if (draft != None): e = AddedMessageEvent(type="added_message", doc=draft) e.message = submission_email_event.submissionemailevent.message e.msgtype = submission_email_event.submissionemailevent.msgtype e.in_reply_to = submission_email_event.submissionemailevent.in_reply_to e.by = request.user.person e.desc = submission_email_event.desc e.time = submission_email_event.time e.save() return redirect("ietf.submit.views.manualpost") except ValidationError as e: form = SubmissionEmailForm(request.POST) form._errors = {} form._errors["__all__"] = form.error_class(["There was a failure uploading your message. (%s)" % e.message]) else: initial = { } if (submission_id != None): submission = get_submission_or_404(submission_id, access_token) initial['name'] = "{}-{}".format(submission.name, submission.rev) initial['direction'] = 'incoming' initial['submission_pk'] = submission.pk else: initial['direction'] = 'incoming' form = SubmissionEmailForm(initial=initial) return render(request, 'submit/add_submit_email.html',dict(form=form)) @role_required('Secretariat',) def send_submission_email(request, submission_id, message_id=None): """Send an email related to a submission""" submission = get_submission_or_404(submission_id, access_token = None) if request.method == 'POST': button_text = request.POST.get('submit', '') if button_text == 'Cancel': return redirect('ietf.submit.views.submission_status', submission_id=submission.id, access_token=submission.access_token()) form = MessageModelForm(request.POST) if form.is_valid(): # create Message msg = Message.objects.create( by = request.user.person, subject = form.cleaned_data['subject'], frm = form.cleaned_data['frm'], to = form.cleaned_data['to'], cc = form.cleaned_data['cc'], bcc = form.cleaned_data['bcc'], reply_to = form.cleaned_data['reply_to'], body = form.cleaned_data['body'] ) in_reply_to_id = form.cleaned_data['in_reply_to_id'] in_reply_to = None rp = "" if in_reply_to_id: rp = " reply" try: in_reply_to = Message.objects.get(id=in_reply_to_id) except Message.DoesNotExist: log("Unable to retrieve in_reply_to message: %s" % in_reply_to_id) desc = "Sent message {} - manual post - {}-{}".format(rp, submission.name, submission.rev) SubmissionEmailEvent.objects.create( submission = submission, desc = desc, msgtype = 'msgout', by = request.user.person, message = msg, in_reply_to = in_reply_to) # send email send_mail_message(None,msg) messages.success(request, 'Email sent.') return redirect('ietf.submit.views.submission_status', submission_id=submission.id, access_token=submission.access_token()) else: reply_to = get_reply_to() msg = None if not message_id: addrs = gather_address_lists('sub_confirmation_requested',submission=submission).as_strings(compact=False) to_email = addrs.to cc = addrs.cc subject = 'Regarding {}'.format(submission.name) else: try: submitEmail = SubmissionEmailEvent.objects.get(id=message_id) msg = submitEmail.message if msg: to_email = msg.frm cc = msg.cc subject = 'Re:{}'.format(msg.subject) else: to_email = None cc = None subject = 'Regarding {}'.format(submission.name) except Message.DoesNotExist: to_email = None cc = None subject = 'Regarding {}'.format(submission.name) initial = { 'to': to_email, 'cc': cc, 'frm': settings.IDSUBMIT_FROM_EMAIL, 'subject': subject, 'reply_to': reply_to, } if msg: initial['in_reply_to_id'] = msg.id form = MessageModelForm(initial=initial) return render(request, "submit/email.html", { 'submission': submission, 'access_token': submission.access_token(), 'form':form}) def show_submission_email_message(request, submission_id, message_id, access_token=None): submission = get_submission_or_404(submission_id, access_token) submitEmail = get_object_or_404(SubmissionEmailEvent, pk=message_id) attachments = submitEmail.message.messageattachment_set.all() return render(request, 'submit/submission_email.html', {'submission': submission, 'message': submitEmail, 'attachments': attachments}) def show_submission_email_attachment(request, submission_id, message_id, filename, access_token=None): get_submission_or_404(submission_id, access_token) message = get_object_or_404(SubmissionEmailEvent, pk=message_id) attach = get_object_or_404(MessageAttachment, message=message.message, filename=filename) if attach.encoding == "base64": body = base64.b64decode(attach.body) else: body = attach.body.encode('utf-8') if attach.content_type is None: content_type='text/plain' else: content_type=attach.content_type response = HttpResponse(body, content_type=content_type) response['Content-Disposition'] = 'attachment; filename=%s' % attach.filename response['Content-Length'] = len(body) return response def get_submission_or_404(submission_id, access_token=None): submission = get_object_or_404(Submission, pk=submission_id) key_matched = access_token and submission.access_token() == access_token if not key_matched: key_matched = submission.access_key == access_token # backwards-compat if access_token and not key_matched: raise Http404 return submission