chore: remove unused submit by email functionality (#7249)
This commit is contained in:
parent
891c0e975d
commit
a00dfc0c27
|
@ -149,9 +149,5 @@ def gather_relevant_expansions(**kwargs):
|
|||
return sorted(rule_list)
|
||||
|
||||
|
||||
def get_base_submission_message_address():
|
||||
return Recipient.objects.get(slug="submission_manualpost_handling").gather()[0]
|
||||
|
||||
|
||||
def get_base_ipr_request_address():
|
||||
return Recipient.objects.get(slug="ipr_requests").gather()[0]
|
||||
|
|
|
@ -1,33 +1,22 @@
|
|||
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import re
|
||||
import email
|
||||
import base64
|
||||
import os
|
||||
import pyzmail
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse as urlreverse
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.sites.models import Site
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.utils.log import log
|
||||
from ietf.utils.mail import send_mail, send_mail_message
|
||||
from ietf.doc.models import Document
|
||||
from ietf.ipr.mail import utc_from_string
|
||||
from ietf.person.models import Person
|
||||
from ietf.message.models import Message, MessageAttachment
|
||||
from ietf.message.models import Message
|
||||
from ietf.utils.accesstoken import generate_access_token
|
||||
from ietf.mailtrigger.utils import gather_address_lists, get_base_submission_message_address
|
||||
from ietf.submit.models import SubmissionEmailEvent, Submission
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
from ietf.submit.checkers import DraftIdnitsChecker
|
||||
from ietf.utils.timezone import date_today
|
||||
|
||||
|
||||
def send_submission_confirmation(request, submission, chair_notice=False):
|
||||
|
@ -196,181 +185,3 @@ def announce_to_authors(request, submission):
|
|||
'group': group},
|
||||
cc=cc)
|
||||
|
||||
|
||||
def get_reply_to():
|
||||
"""Returns a new reply-to address for use with an outgoing message. This is an
|
||||
address with "plus addressing" using a random string. Guaranteed to be unique"""
|
||||
local,domain = get_base_submission_message_address().split('@')
|
||||
while True:
|
||||
rand = force_str(base64.urlsafe_b64encode(os.urandom(12)))
|
||||
address = "{}+{}@{}".format(local,rand,domain)
|
||||
q = Message.objects.filter(reply_to=address)
|
||||
if not q:
|
||||
return address
|
||||
|
||||
|
||||
def process_response_email(msg):
|
||||
"""Saves an incoming message. msg=string. Message "To" field is expected to
|
||||
be in the format ietf-submit+[identifier]@ietf.org. Expect to find a message with
|
||||
a matching value in the reply_to field, associated to a submission.
|
||||
Create a Message object for the incoming message and associate it to
|
||||
the original message via new SubmissionEvent"""
|
||||
message = email.message_from_string(force_str(msg))
|
||||
to = message.get('To')
|
||||
|
||||
# exit if this isn't a response we're interested in (with plus addressing)
|
||||
local,domain = get_base_submission_message_address().split('@')
|
||||
if not re.match(r'^{}\+[a-zA-Z0-9_\-]{}@{}'.format(local,'{16}',domain),to):
|
||||
return None
|
||||
|
||||
try:
|
||||
to_message = Message.objects.get(reply_to=to)
|
||||
except Message.DoesNotExist:
|
||||
log('Error finding matching message ({})'.format(to))
|
||||
return None
|
||||
|
||||
try:
|
||||
submission = to_message.manualevents.first().submission
|
||||
except:
|
||||
log('Error processing message ({})'.format(to))
|
||||
return None
|
||||
|
||||
if not submission:
|
||||
log('Error processing message - no submission ({})'.format(to))
|
||||
return None
|
||||
|
||||
parts = pyzmail.parse.get_mail_parts(message)
|
||||
body=''
|
||||
for part in parts:
|
||||
if part.is_body == 'text/plain' and part.disposition == None:
|
||||
payload, used_charset = pyzmail.decode_text(part.get_payload(), part.charset, None)
|
||||
body = body + payload + '\n'
|
||||
|
||||
by = Person.objects.get(name="(System)")
|
||||
msg = submit_message_from_message(message, body, by)
|
||||
|
||||
desc = "Email: received message - manual post - {}-{}".format(
|
||||
submission.name,
|
||||
submission.rev)
|
||||
|
||||
submission_email_event = SubmissionEmailEvent.objects.create(
|
||||
submission = submission,
|
||||
desc = desc,
|
||||
msgtype = 'msgin',
|
||||
by = by,
|
||||
message = msg,
|
||||
in_reply_to = to_message
|
||||
)
|
||||
|
||||
save_submission_email_attachments(submission_email_event, parts)
|
||||
|
||||
log("Received submission email from %s" % msg.frm)
|
||||
return msg
|
||||
|
||||
|
||||
def add_submission_email(request, remote_ip, name, rev, submission_pk, message, by, msgtype):
|
||||
"""Add email to submission history"""
|
||||
|
||||
#in_reply_to = form.cleaned_data['in_reply_to']
|
||||
# create Message
|
||||
parts = pyzmail.parse.get_mail_parts(message)
|
||||
body=''
|
||||
for part in parts:
|
||||
if part.is_body == 'text/plain' and part.disposition == None:
|
||||
payload, used_charset = pyzmail.decode_text(part.get_payload(), part.charset, None)
|
||||
body = body + payload + '\n'
|
||||
|
||||
msg = submit_message_from_message(message, body, by)
|
||||
|
||||
if (submission_pk != None):
|
||||
# Must exist - we're adding a message to an existing submission
|
||||
submission = Submission.objects.get(pk=submission_pk)
|
||||
else:
|
||||
# Must not exist
|
||||
submissions = Submission.objects.filter(name=name,rev=rev).exclude(state_id='cancel')
|
||||
if submissions.count() > 0:
|
||||
raise ValidationError("Submission {} already exists".format(name))
|
||||
|
||||
# create Submission using the name
|
||||
try:
|
||||
submission = Submission.objects.create(
|
||||
state_id="waiting-for-draft",
|
||||
remote_ip=remote_ip,
|
||||
name=name,
|
||||
rev=rev,
|
||||
title=name,
|
||||
note="",
|
||||
submission_date=date_today(),
|
||||
replaces="",
|
||||
)
|
||||
from ietf.submit.utils import create_submission_event, docevent_from_submission
|
||||
desc = "Submission created for rev {} in response to email".format(rev)
|
||||
create_submission_event(request,
|
||||
submission,
|
||||
desc)
|
||||
docevent_from_submission(submission, desc)
|
||||
except Exception as e:
|
||||
log("Exception: %s\n" % e)
|
||||
raise
|
||||
|
||||
if msgtype == 'msgin':
|
||||
rs = "Received"
|
||||
else:
|
||||
rs = "Sent"
|
||||
|
||||
desc = "{} message - manual post - {}-{}".format(rs, name, rev)
|
||||
submission_email_event = SubmissionEmailEvent.objects.create(
|
||||
desc = desc,
|
||||
submission = submission,
|
||||
msgtype = msgtype,
|
||||
by = by,
|
||||
message = msg)
|
||||
#in_reply_to = in_reply_to
|
||||
|
||||
save_submission_email_attachments(submission_email_event, parts)
|
||||
return submission, submission_email_event
|
||||
|
||||
|
||||
def submit_message_from_message(message,body,by=None):
|
||||
"""Returns a ietf.message.models.Message. msg=email.Message
|
||||
A copy of mail.message_from_message with different body handling
|
||||
"""
|
||||
if not by:
|
||||
by = Person.objects.get(name="(System)")
|
||||
msg = Message.objects.create(
|
||||
by = by,
|
||||
subject = message.get('subject',''),
|
||||
frm = message.get('from',''),
|
||||
to = message.get('to',''),
|
||||
cc = message.get('cc',''),
|
||||
bcc = message.get('bcc',''),
|
||||
reply_to = message.get('reply_to',''),
|
||||
body = body,
|
||||
time = utc_from_string(message.get('date', '')),
|
||||
content_type = message.get('content_type', 'text/plain'),
|
||||
)
|
||||
return msg
|
||||
|
||||
def save_submission_email_attachments(submission_email_event, parts):
|
||||
for part in parts:
|
||||
if part.disposition != 'attachment':
|
||||
continue
|
||||
|
||||
if part.type == 'text/plain':
|
||||
payload, used_charset = pyzmail.decode_text(part.get_payload(),
|
||||
part.charset,
|
||||
None)
|
||||
encoding = ""
|
||||
else:
|
||||
# Need a better approach - for the moment we'll just handle these
|
||||
# and encode as base64
|
||||
payload = base64.b64encode(part.get_payload())
|
||||
encoding = "base64"
|
||||
|
||||
#name = submission_email_event.submission.name
|
||||
|
||||
MessageAttachment.objects.create(message = submission_email_event.message,
|
||||
content_type = part.type,
|
||||
encoding = encoding,
|
||||
filename=part.filename,
|
||||
body=payload)
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
# Copyright The IETF Trust 2016-2020, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import io
|
||||
import sys
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from ietf.submit.mail import process_response_email
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = ("Process incoming manual post email responses")
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--email-file', dest='email', help='File containing email (default: stdin)')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
email = options.get('email', None)
|
||||
msg = None
|
||||
|
||||
if not email:
|
||||
msg = sys.stdin.read()
|
||||
else:
|
||||
msg = io.open(email, "r").read()
|
||||
|
||||
try:
|
||||
process_response_email(msg)
|
||||
except ValueError as e:
|
||||
raise CommandError(e)
|
|
@ -42,17 +42,15 @@ from ietf.group.models import Group
|
|||
from ietf.group.utils import setup_default_community_list_for_group
|
||||
from ietf.meeting.models import Meeting
|
||||
from ietf.meeting.factories import MeetingFactory
|
||||
from ietf.message.models import Message
|
||||
from ietf.name.models import FormalLanguageName
|
||||
from ietf.person.models import Person
|
||||
from ietf.person.factories import UserFactory, PersonFactory, EmailFactory
|
||||
from ietf.submit.factories import SubmissionFactory, SubmissionExtResourceFactory
|
||||
from ietf.submit.forms import SubmissionBaseUploadForm, SubmissionAutoUploadForm
|
||||
from ietf.submit.models import Submission, Preapproval, SubmissionExtResource
|
||||
from ietf.submit.mail import add_submission_email, process_response_email
|
||||
from ietf.submit.tasks import cancel_stale_submissions, process_and_accept_uploaded_submission_task
|
||||
from ietf.utils.accesstoken import generate_access_token
|
||||
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
||||
from ietf.utils.mail import outbox, get_payload_text
|
||||
from ietf.utils.models import VersionInfo
|
||||
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
|
||||
from ietf.utils.timezone import date_today
|
||||
|
@ -198,6 +196,28 @@ def create_draft_submission_with_rev_mismatch(rev='01'):
|
|||
return draft, sub
|
||||
|
||||
|
||||
class ManualSubmissionTests(TestCase):
|
||||
def test_manualpost_view(self):
|
||||
submission = SubmissionFactory(state_id="manual")
|
||||
url = urlreverse("ietf.submit.views.manualpost")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(
|
||||
urlreverse(
|
||||
"ietf.submit.views.submission_status",
|
||||
kwargs=dict(submission_id=submission.pk)
|
||||
),
|
||||
q("#manual.submissions td a").attr("href")
|
||||
)
|
||||
self.assertIn(
|
||||
submission.name,
|
||||
q("#manual.submissions td a").text()
|
||||
)
|
||||
|
||||
def test_manualpost_cancel(self):
|
||||
pass
|
||||
|
||||
class SubmitTests(BaseSubmitTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
@ -2293,451 +2313,6 @@ class ApprovalsTestCase(BaseSubmitTestCase):
|
|||
|
||||
self.assertEqual(len(Preapproval.objects.filter(name=preapproval.name)), 0)
|
||||
|
||||
class ManualPostsTestCase(BaseSubmitTestCase):
|
||||
def test_manual_posts(self):
|
||||
GroupFactory(acronym='mars')
|
||||
|
||||
url = urlreverse('ietf.submit.views.manualpost')
|
||||
# Secretariat has access
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
|
||||
Submission.objects.create(name="draft-ietf-mars-foo",
|
||||
group=Group.objects.get(acronym="mars"),
|
||||
submission_date=date_today(),
|
||||
state_id="manual")
|
||||
Submission.objects.create(name="draft-ietf-mars-bar",
|
||||
group=Group.objects.get(acronym="mars"),
|
||||
submission_date=date_today(),
|
||||
rev="00",
|
||||
state_id="grp-appr")
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
||||
self.assertEqual(len(q('.submissions a:contains("draft-ietf-mars-foo")')), 1)
|
||||
self.assertEqual(len(q('.submissions a:contains("draft-ietf-mars-bar")')), 0)
|
||||
|
||||
def test_waiting_for_draft(self):
|
||||
message_string = """To: somebody@ietf.org
|
||||
From: joe@test.com
|
||||
Date: {}
|
||||
Subject: test submission via email
|
||||
|
||||
Please submit my draft at http://test.com/mydraft.txt
|
||||
|
||||
Thank you
|
||||
""".format(timezone.now().ctime())
|
||||
message = email.message_from_string(force_str(message_string))
|
||||
submission, submission_email_event = (
|
||||
add_submission_email(request=None,
|
||||
remote_ip ="192.168.0.1",
|
||||
name = "draft-my-new-draft",
|
||||
rev='00',
|
||||
submission_pk=None,
|
||||
message = message,
|
||||
by = Person.objects.get(name="(System)"),
|
||||
msgtype = "msgin") )
|
||||
|
||||
url = urlreverse('ietf.submit.views.manualpost')
|
||||
# Secretariat has access
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
||||
self.assertEqual(len(q('.waiting-for-draft a:contains("draft-my-new-draft")')), 1)
|
||||
|
||||
# Same name should raise an error
|
||||
with self.assertRaises(Exception):
|
||||
add_submission_email(request=None,
|
||||
remote_ip ="192.168.0.1",
|
||||
name = "draft-my-new-draft",
|
||||
rev='00',
|
||||
submission_pk=None,
|
||||
message = message,
|
||||
by = Person.objects.get(name="(System)"),
|
||||
msgtype = "msgin")
|
||||
|
||||
# Cancel this one
|
||||
r = self.client.post(urlreverse("ietf.submit.views.cancel_waiting_for_draft"), {
|
||||
"submission_id": submission.pk,
|
||||
"access_token": submission.access_token(),
|
||||
})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
url = r["Location"]
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('.waiting-for-draft a:contains("draft-my-new-draft")')), 0)
|
||||
|
||||
# Should now be able to add it again
|
||||
submission, submission_email_event = (
|
||||
add_submission_email(request=None,
|
||||
remote_ip ="192.168.0.1",
|
||||
name = "draft-my-new-draft",
|
||||
rev='00',
|
||||
submission_pk=None,
|
||||
message = message,
|
||||
by = Person.objects.get(name="(System)"),
|
||||
msgtype = "msgin") )
|
||||
|
||||
|
||||
def test_waiting_for_draft_with_attachment(self):
|
||||
frm = "joe@test.com"
|
||||
|
||||
message_string = """To: somebody@ietf.org
|
||||
From: {}
|
||||
Date: {}
|
||||
Subject: A very important message with a small attachment
|
||||
Content-Type: multipart/mixed; boundary="------------090908050800030909090207"
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
--------------090908050800030909090207
|
||||
Content-Type: text/plain; charset=utf-8; format=flowed
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
The message body will probably say something about the attached document
|
||||
|
||||
--------------090908050800030909090207
|
||||
Content-Type: text/plain; charset=UTF-8; name="attach.txt"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="attach.txt"
|
||||
|
||||
QW4gZXhhbXBsZSBhdHRhY2htZW50IHd0aG91dCB2ZXJ5IG11Y2ggaW4gaXQuCgpBIGNvdXBs
|
||||
ZSBvZiBsaW5lcyAtIGJ1dCBpdCBjb3VsZCBiZSBhIGRyYWZ0Cg==
|
||||
--------------090908050800030909090207--
|
||||
""".format(frm, timezone.now().ctime())
|
||||
|
||||
message = email.message_from_string(force_str(message_string))
|
||||
submission, submission_email_event = (
|
||||
add_submission_email(request=None,
|
||||
remote_ip ="192.168.0.1",
|
||||
name = "draft-my-new-draft",
|
||||
rev='00',
|
||||
submission_pk=None,
|
||||
message = message,
|
||||
by = Person.objects.get(name="(System)"),
|
||||
msgtype = "msgin") )
|
||||
|
||||
manualpost_page_url = urlreverse('ietf.submit.views.manualpost')
|
||||
# Secretariat has access
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
|
||||
self.check_manualpost_page(submission=submission,
|
||||
submission_email_event=submission_email_event,
|
||||
the_url=manualpost_page_url,
|
||||
submission_name_fragment='draft-my-new-draft',
|
||||
frm=frm,
|
||||
is_secretariat=True)
|
||||
|
||||
# Try the status page with no credentials
|
||||
self.client.logout()
|
||||
|
||||
self.check_manualpost_page(submission=submission,
|
||||
submission_email_event=submission_email_event,
|
||||
the_url=manualpost_page_url,
|
||||
submission_name_fragment='draft-my-new-draft',
|
||||
frm=frm,
|
||||
is_secretariat=False)
|
||||
|
||||
# Post another message to this submission using the link
|
||||
message_string = """To: somebody@ietf.org
|
||||
From: joe@test.com
|
||||
Date: {}
|
||||
Subject: A new submission message with a small attachment
|
||||
Content-Type: multipart/mixed; boundary="------------090908050800030909090207"
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
--------------090908050800030909090207
|
||||
Content-Type: text/plain; charset=utf-8; format=flowed
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
The message body will probably say something more about the attached document
|
||||
|
||||
--------------090908050800030909090207
|
||||
Content-Type: text/plain; charset=UTF-8; name="attach.txt"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="attachment.txt"
|
||||
|
||||
QW4gZXhhbXBsZSBhdHRhY2htZW50IHd0aG91dCB2ZXJ5IG11Y2ggaW4gaXQuCgpBIGNvdXBs
|
||||
ZSBvZiBsaW5lcyAtIGJ1dCBpdCBjb3VsZCBiZSBhIGRyYWZ0Cg==
|
||||
--------------090908050800030909090207--
|
||||
""".format(timezone.now().ctime())
|
||||
|
||||
# Back to secretariat
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
|
||||
r, q = self.request_and_parse(manualpost_page_url)
|
||||
|
||||
url = self.get_href(q, "a#new-submission-email:contains('New submission from email')")
|
||||
|
||||
# Get the form
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
#self.assertEqual(len(q('input[name=edit-title]')), 1)
|
||||
|
||||
# Post the new message
|
||||
r = self.client.post(url, {
|
||||
"name": "draft-my-next-new-draft-00",
|
||||
"direction": "incoming",
|
||||
"message": message_string,
|
||||
})
|
||||
|
||||
if r.status_code != 302:
|
||||
q = PyQuery(r.content)
|
||||
print(q)
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
|
||||
#self.check_manualpost_page(submission, submission_email_event,
|
||||
# url, 'draft-my-next-new-draft'
|
||||
# 'Another very important message',
|
||||
# true)
|
||||
|
||||
def check_manualpost_page(self, submission, submission_email_event,
|
||||
the_url, submission_name_fragment,
|
||||
frm,
|
||||
is_secretariat):
|
||||
# get the page listing manual posts
|
||||
r, q = self.request_and_parse(the_url)
|
||||
selector = "#waiting-for-draft a#add-submission-email%s:contains('Add email')" % submission.pk
|
||||
|
||||
if is_secretariat:
|
||||
# Can add an email to the submission
|
||||
add_email_url = self.get_href(q, selector)
|
||||
else:
|
||||
# No add email button button
|
||||
self.assertEqual(len(q(selector)), 0)
|
||||
|
||||
# Find the link for our submission in those awaiting drafts
|
||||
submission_url = self.get_href(q, "#waiting-for-draft a#aw{}:contains('{}')".
|
||||
format(submission.pk, submission_name_fragment))
|
||||
|
||||
# Follow the link to the status page for this submission
|
||||
r, q = self.request_and_parse(submission_url)
|
||||
|
||||
selector = "#history a#reply%s:contains('Reply')" % submission.pk
|
||||
|
||||
if is_secretariat:
|
||||
# check that reply button is visible and get the form
|
||||
reply_url = self.get_href(q, selector)
|
||||
|
||||
# Get the form
|
||||
r = self.client.get(reply_url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
reply_q = PyQuery(r.content)
|
||||
self.assertEqual(len(reply_q('input[name=to]')), 1)
|
||||
else:
|
||||
# No reply button
|
||||
self.assertEqual(len(q(selector)), 0)
|
||||
|
||||
if is_secretariat:
|
||||
# Now try to send an email using the send email link
|
||||
|
||||
selector = "a#send%s:contains('Send Email')" % submission.pk
|
||||
send_url = self.get_href(q, selector)
|
||||
|
||||
self.do_submission_email(the_url = send_url,
|
||||
to = frm,
|
||||
body = "A new message")
|
||||
|
||||
# print q
|
||||
# print submission.pk
|
||||
# print submission_email_event.pk
|
||||
|
||||
# Find the link for our message in the list
|
||||
url = self.get_href(q, "#aw{}-{}:contains('{}')".format(submission.pk,
|
||||
submission_email_event.message.pk,
|
||||
"Received message - manual post"))
|
||||
|
||||
# Page displaying message details
|
||||
r, q = self.request_and_parse(url)
|
||||
|
||||
if is_secretariat:
|
||||
# check that reply button is visible
|
||||
|
||||
reply_href = self.get_href(q, "a#reply%s:contains('Reply')" % submission.pk)
|
||||
|
||||
else:
|
||||
# No reply button
|
||||
self.assertEqual(len(q(selector)), 0)
|
||||
reply_href = None
|
||||
|
||||
# check that attachment link is visible
|
||||
|
||||
url = self.get_href(q, "#email-details a#attach{}:contains('attach.txt')".format(submission.pk))
|
||||
|
||||
# Fetch the attachment
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Attempt a reply if we can
|
||||
if reply_href == None:
|
||||
return
|
||||
|
||||
self.do_submission_email(the_url = reply_href,
|
||||
to = frm,
|
||||
body = "A reply to the message")
|
||||
|
||||
# try adding an email to the submission
|
||||
# Use the add email link from the manual post listing page
|
||||
|
||||
if is_secretariat:
|
||||
# Can add an email to the submission
|
||||
# add_email_url set previously
|
||||
r = self.client.get(add_email_url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
add_email_q = PyQuery(r.content)
|
||||
self.assertEqual(len(add_email_q('input[name=submission_pk]')), 1)
|
||||
|
||||
# Add a simple email
|
||||
new_message_string = """To: somebody@ietf.org
|
||||
From: joe@test.com
|
||||
Date: {}
|
||||
Subject: Another message
|
||||
|
||||
About my submission
|
||||
|
||||
Thank you
|
||||
""".format(timezone.now().ctime())
|
||||
|
||||
r = self.client.post(add_email_url, {
|
||||
"name": "{}-{}".format(submission.name, submission.rev),
|
||||
"direction": "incoming",
|
||||
"submission_pk": submission.pk,
|
||||
"message": new_message_string,
|
||||
})
|
||||
|
||||
if r.status_code != 302:
|
||||
q = PyQuery(r.content)
|
||||
print(q)
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
def request_and_parse(self, url):
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
return r, PyQuery(r.content)
|
||||
|
||||
|
||||
def get_href(self, q, query):
|
||||
link = q(query)
|
||||
self.assertEqual(len(link), 1)
|
||||
|
||||
return PyQuery(link[0]).attr('href')
|
||||
|
||||
|
||||
def do_submission_email(self, the_url, to, body):
|
||||
# check the page
|
||||
r = self.client.get(the_url)
|
||||
q = PyQuery(r.content)
|
||||
post_button = q('[type=submit]:contains("Send email")')
|
||||
self.assertEqual(len(post_button), 1)
|
||||
subject = post_button.parents("form").find('input[name="subject"]').val()
|
||||
frm = post_button.parents("form").find('input[name="frm"]').val()
|
||||
cc = post_button.parents("form").find('input[name="cc"]').val()
|
||||
reply_to = post_button.parents("form").find('input[name="reply_to"]').val()
|
||||
|
||||
empty_outbox()
|
||||
|
||||
# post submitter info
|
||||
r = self.client.post(the_url, {
|
||||
"subject": subject,
|
||||
"frm": frm,
|
||||
"to": to,
|
||||
"cc": cc,
|
||||
"reply_to": reply_to,
|
||||
"body": body,
|
||||
})
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
self.assertEqual(len(outbox), 1)
|
||||
|
||||
outmsg = outbox[0]
|
||||
self.assertTrue(to in outmsg['To'])
|
||||
|
||||
reply_to = outmsg['Reply-To']
|
||||
self.assertIsNotNone(reply_to, "Expected Reply-To")
|
||||
|
||||
# Build a reply
|
||||
|
||||
message_string = """To: {}
|
||||
From: {}
|
||||
Date: {}
|
||||
Subject: test
|
||||
""".format(reply_to, to, timezone.now().ctime())
|
||||
|
||||
result = process_response_email(message_string)
|
||||
self.assertIsInstance(result, Message)
|
||||
|
||||
return r
|
||||
|
||||
def do_submission(self, name, rev, group=None, formats=["txt",]):
|
||||
# We're not testing the submission process - just the submission status
|
||||
|
||||
# get
|
||||
url = urlreverse('ietf.submit.views.upload_submission')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('input[type=file][name=txt]')), 1)
|
||||
self.assertEqual(len(q('input[type=file][name=xml]')), 1)
|
||||
|
||||
# submit
|
||||
files = {}
|
||||
for format in formats:
|
||||
files[format], author = submission_file(f'{name}-{rev}', f'{name}-{rev}.{format}', group, "test_submission.%s" % format)
|
||||
|
||||
r = self.post_to_upload_submission(url, files)
|
||||
if r.status_code != 302:
|
||||
q = PyQuery(r.content)
|
||||
print(q('div.invalid-feedback span.form-text div').text())
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
status_url = r["Location"]
|
||||
for format in formats:
|
||||
self.assertTrue(os.path.exists(os.path.join(self.staging_dir, "%s-%s.%s" % (name, rev, format))))
|
||||
self.assertEqual(Submission.objects.filter(name=name).count(), 1)
|
||||
submission = Submission.objects.get(name=name)
|
||||
self.assertTrue(all([ c.passed!=False for c in submission.checks.all() ]))
|
||||
self.assertEqual(len(submission.authors), 1)
|
||||
author = submission.authors[0]
|
||||
self.assertEqual(author["name"], "Author Name")
|
||||
self.assertEqual(author["email"], "author@example.com")
|
||||
|
||||
return status_url
|
||||
|
||||
|
||||
def supply_extra_metadata(self, name, status_url, submitter_name, submitter_email):
|
||||
# check the page
|
||||
r = self.client.get(status_url)
|
||||
q = PyQuery(r.content)
|
||||
post_button = q('[type=submit]:contains("Post")')
|
||||
self.assertEqual(len(post_button), 1)
|
||||
action = post_button.parents("form").find('input[type=hidden][name="action"]').val()
|
||||
|
||||
# post submitter info
|
||||
r = self.client.post(status_url, {
|
||||
"action": action,
|
||||
"submitter-name": submitter_name,
|
||||
"submitter-email": submitter_email,
|
||||
"approvals_received": True,
|
||||
})
|
||||
|
||||
if r.status_code == 302:
|
||||
submission = Submission.objects.get(name=name)
|
||||
self.assertEqual(submission.submitter, email.utils.formataddr((submitter_name, submitter_email)))
|
||||
|
||||
return r
|
||||
|
||||
|
||||
# Transaction.on_commit() requires use of TransactionTestCase, but that has a performance penalty. Replace it
|
||||
# with a no-op for testing purposes.
|
||||
|
|
|
@ -17,15 +17,6 @@ urlpatterns = [
|
|||
url(r'^approvals/cancelpreapproval/(?P<preapproval_id>[a-f\d]+)/$', views.cancel_preapproval),
|
||||
|
||||
url(r'^manualpost/$', views.manualpost),
|
||||
url(r'^manualpost/addemail$', views.add_manualpost_email),
|
||||
url(r'^manualpost/addemail/(?P<submission_id>\d+)/(?P<access_token>[a-f\d]*)/$', views.add_manualpost_email),
|
||||
url(r'^manualpost/attachment/(?P<submission_id>\d+)/(?P<message_id>\d+)/(?P<filename>.*)$', views.show_submission_email_attachment),
|
||||
url(r'^manualpost/cancel$', views.cancel_waiting_for_draft),
|
||||
url(r'^manualpost/email/(?P<submission_id>\d+)/(?P<message_id>\d+)/$', views.show_submission_email_message),
|
||||
url(r'^manualpost/email/(?P<submission_id>\d+)/(?P<message_id>\d+)/(?P<access_token>[a-f\d]*)/$', views.show_submission_email_message),
|
||||
url(r'^manualpost/replyemail/(?P<submission_id>\d+)/(?P<message_id>\d+)/$', views.send_submission_email),
|
||||
url(r'^manualpost/sendemail/(?P<submission_id>\d+)/$', views.send_submission_email),
|
||||
|
||||
# proof-of-concept for celery async tasks
|
||||
url(r'^async-poke/?$', views.async_poke_test),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
|
||||
import re
|
||||
import base64
|
||||
import datetime
|
||||
|
||||
from typing import Optional, cast # pyflakes:ignore
|
||||
|
@ -22,31 +21,30 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document, AddedMessageEvent
|
||||
from ietf.doc.models import Document
|
||||
from ietf.doc.forms import ExtResourceForm
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import group_features_group_filter
|
||||
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.person.models import Email
|
||||
from ietf.submit.forms import (SubmissionAutoUploadForm, AuthorForm, SubmitterForm, EditSubmissionForm,
|
||||
PreapprovalForm, ReplacesForm, SubmissionEmailForm, MessageModelForm,
|
||||
PreapprovalForm, ReplacesForm,
|
||||
DeprecatedSubmissionAutoUploadForm, SubmissionManualUploadForm)
|
||||
from ietf.submit.mail import send_full_url, send_manual_post_request, add_submission_email, get_reply_to
|
||||
from ietf.submit.mail import send_full_url, send_manual_post_request
|
||||
from ietf.submit.models import (Submission, Preapproval, SubmissionExtResource,
|
||||
DraftSubmissionStateName, SubmissionEmailEvent )
|
||||
DraftSubmissionStateName )
|
||||
from ietf.submit.tasks import process_uploaded_submission_task, process_and_accept_uploaded_submission_task, poke
|
||||
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, remove_submission_files, get_draft_meta,
|
||||
get_submission, fill_in_submission, apply_checkers, save_files, clear_existing_files,
|
||||
check_submission_revision_consistency, accept_submission, accept_submission_requires_group_approval,
|
||||
accept_submission_requires_prev_auth_approval, update_submission_external_resources, remote_ip )
|
||||
accept_submission_requires_prev_auth_approval, update_submission_external_resources)
|
||||
from ietf.stats.utils import clean_country_name
|
||||
from ietf.utils.accesstoken import generate_access_token
|
||||
from ietf.utils.log import log
|
||||
from ietf.utils.mail import parseaddr, send_mail_message
|
||||
from ietf.utils.mail import parseaddr
|
||||
from ietf.utils.response import permission_denied
|
||||
from ietf.utils.timezone import date_today
|
||||
|
||||
|
@ -780,243 +778,14 @@ def manualpost(request):
|
|||
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:
|
||||
permission_denied(request, '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(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=remote_ip(request),
|
||||
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 = {
|
||||
return render(
|
||||
request,
|
||||
'submit/manual_post.html',
|
||||
{
|
||||
'manual': manual,
|
||||
'selected': 'manual_posts'
|
||||
}
|
||||
|
||||
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):
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% block title %}
|
||||
{% if submission == None %}
|
||||
Add new submission request email
|
||||
{% else %}
|
||||
Add submission request email to {{ submission.name }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Add email</h1>
|
||||
<p class="my-3">
|
||||
{% if submission == None %}
|
||||
A new submission request will be created for the given name and revision. The
|
||||
name must take the form <code>draft-xxx-nn</code> where <code>xxx</code> is lowercase letters, digits or dashes
|
||||
and <code>nn</code> is the revision number, <code>00</code> for the initial revision. For example,
|
||||
<code>draft-my-spec-00</code>.
|
||||
{% else %}
|
||||
The email will be added to the submission history for {{ submission.name }}.
|
||||
{% endif %}
|
||||
</p>
|
||||
<form class="add-email my-3" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
<button type="submit" class="btn btn-primary">Add Email</button>
|
||||
<a class="btn btn-secondary float-end"
|
||||
href="{% url "ietf.submit.views.manualpost" %}">Back</a>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,25 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% block title %}Email related to{{ submission.name }}{% endblock %}
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" href="{% static 'ietf/css/datepicker.css' %}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>
|
||||
Email related to
|
||||
<br>
|
||||
<small class="text-body-secondary">{{ submission.name }}</small>
|
||||
</h1>
|
||||
<form method="post" class="show-required my-3">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
<button type="submit" class="btn btn-primary">Send email</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<script src="{% static 'ietf/js/datepicker.js' %}"></script>
|
||||
{% endblock %}
|
|
@ -58,76 +58,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<h2 class="mt-3" id="id_upload">Submissions awaiting Internet-Draft upload</h2>
|
||||
{% if not waiting_for_draft %}
|
||||
<p class="alert alert-info my-3" id="no-waiting-for-draft">
|
||||
There are no submissions awaiting Internet-Draft upload.
|
||||
</p>
|
||||
{% else %}
|
||||
<table id="waiting-for-draft"
|
||||
class="waiting-for-draft table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="name">Name</th>
|
||||
<th scope="col" data-sort="rev">Rev</th>
|
||||
<th scope="col" data-sort="date">Submitted</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for s in waiting_for_draft %}
|
||||
<tr>
|
||||
{% if user.is_authenticated %}
|
||||
<td>
|
||||
<a id="aw{{ s.pk }}"
|
||||
href="{% url "ietf.submit.views.submission_status" submission_id=s.pk access_token=s.access_token %}">
|
||||
{{ s.name }}
|
||||
</a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>
|
||||
<a id="aw{{ s.pk }}"
|
||||
href="{% url "ietf.submit.views.submission_status" submission_id=s.pk %}">{{ s.name }}</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>{{ s.rev }}</td>
|
||||
<td>{{ s.submission_date }}</td>
|
||||
<td>
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<form id="cancel-submission"
|
||||
action="/submit/awaitingdraft/cancel"
|
||||
method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="submission_id" value="{{ s.pk }}">
|
||||
<input type="hidden" name="access_token" value="{{ s.access_token }}">
|
||||
<button class="btn btn-danger btn-sm float-end ms-1"
|
||||
type="submit"
|
||||
data-bs-toggle="tooltip"
|
||||
title="Cancels the submission permanently.">
|
||||
Cancel submission
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<a id="add-submission-email{{ s.pk }}"
|
||||
class="btn btn-primary btn-sm float-end ms-1"
|
||||
href="{% url "ietf.submit.views.add_manualpost_email" submission_id=s.pk access_token=s.access_token %}">
|
||||
Add email
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<a id="new-submission-email"
|
||||
class="btn btn-primary"
|
||||
href="{% url "ietf.submit.views.add_manualpost_email" %}">
|
||||
New submission from email
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<script src="{% static "ietf/js/list.js" %}"></script>
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin static textfilters ietf_filters %}
|
||||
{% block title %}Submission email{% endblock %}
|
||||
{% load ietf_filters %}
|
||||
{% block submit_content %}
|
||||
{% origin %}
|
||||
<h2 id="approvals">Email for {{ submission.name }}</h2>
|
||||
<dl id="email-details" class="emails row my-3">
|
||||
<dt class="col-sm-2">
|
||||
Uploaded
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
{{ message.time }}
|
||||
</dd>
|
||||
<dt class="col-sm-2">
|
||||
Date
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
{{ message.message.time }}
|
||||
</dd>
|
||||
<dt class="col-sm-2">
|
||||
From
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
{{ message.message.frm|linkify }}
|
||||
</dd>
|
||||
<dt class="col-sm-2">
|
||||
Subject
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
{{ message.message.subject }}
|
||||
</dd>
|
||||
<dt class="col-sm-2">
|
||||
Message
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
<pre>{{ message.message.body|urlize_ietf_docs|linkify|linebreaksbr }}</pre>
|
||||
</dd>
|
||||
<dt class="col-sm-2">
|
||||
Attachment
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
{% for a in attachments %}
|
||||
<a id="attach{{ submission.pk }}"
|
||||
href="{% url "ietf.submit.views.show_submission_email_attachment" submission_id=submission.pk message_id=message.pk filename=a.filename %}">
|
||||
{{ a.filename }}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
</dd>
|
||||
</dl>
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<a id="reply{{ submission.pk }}"
|
||||
class="btn btn-primary"
|
||||
href="{% url "ietf.submit.views.send_submission_email" submission_id=submission.pk message_id=message.pk %}"
|
||||
title="Reply">
|
||||
<i class="bi bi-envelope" aria-hidden="true"></i> Reply
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -520,14 +520,6 @@
|
|||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<a id="send{{ submission.pk }}"
|
||||
class="btn btn-primary mt-3"
|
||||
href="{% url "ietf.submit.views.send_submission_email" submission_id=submission.pk %}"
|
||||
title="Email submitter">
|
||||
<i class="bi bi-envelope" aria-hidden="true"></i> Send Email
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if show_send_full_url %}
|
||||
<div class="alert alert-info my-3">
|
||||
<p>
|
||||
|
@ -584,39 +576,10 @@
|
|||
{% endif %}
|
||||
|
||||
</td>
|
||||
{% if e.desc|startswith:"Received message" or e.desc|startswith:"Sent message" %}
|
||||
{% with m=e.submissionemailevent.message %}
|
||||
{% if user.is_authenticated %}
|
||||
<td>
|
||||
{% if e.desc|startswith:"Received message" and user|has_role:"Secretariat" %}
|
||||
<a id="reply{{ submission.pk }}"
|
||||
class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.submit.views.send_submission_email" submission_id=submission.pk message_id=e.submissionemailevent.pk %}"
|
||||
title="Reply">
|
||||
<i class="bi bi-envelope" aria-hidden="true"></i> Reply
|
||||
</a>
|
||||
{% endif %}
|
||||
Email:
|
||||
<a id="aw{{ submission.pk }}-{{ m.pk }}"
|
||||
href="{% url "ietf.submit.views.show_submission_email_message" submission_id=submission.pk message_id=e.submissionemailevent.pk access_token=submission.access_token %}">
|
||||
{{ e.desc }}
|
||||
</a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>
|
||||
Email:
|
||||
<a id="aw{{ submission.pk }}-{{ m.pk }}"
|
||||
href="{% url "ietf.submit.views.show_submission_email_message" submission_id=submission.pk message_id=e.submissionemailevent.pk %}">
|
||||
{{ e.desc }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<td>
|
||||
{{ e.desc|urlize_ietf_docs|linkify }}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
<td>
|
||||
{{ e.desc|urlize_ietf_docs|linkify }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
Loading…
Reference in a new issue