From 1155fb32f6edbd230b62c39399bf2bdd96f12468 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 21 May 2021 15:54:03 +0000 Subject: [PATCH] Accept 'None' when updating DocumentAuthor affiliation / country. Commit ready for merge. - Legacy-Id: 19028 --- ietf/doc/tests_utils.py | 40 ++- ietf/doc/utils.py | 6 +- .../test_submission_no_org_or_address.txt | 243 ++++++++++++++++++ .../test_submission_no_org_or_address.xml | 143 +++++++++++ ietf/submit/tests.py | 47 +++- 5 files changed, 470 insertions(+), 9 deletions(-) create mode 100644 ietf/submit/test_submission_no_org_or_address.txt create mode 100644 ietf/submit/test_submission_no_org_or_address.xml diff --git a/ietf/doc/tests_utils.py b/ietf/doc/tests_utils.py index 7bc5adab6..cd6be0a3d 100644 --- a/ietf/doc/tests_utils.py +++ b/ietf/doc/tests_utils.py @@ -1,14 +1,16 @@ # Copyright The IETF Trust 2020, All Rights Reserved import datetime +from django.db import IntegrityError + from ietf.group.factories import GroupFactory, RoleFactory from ietf.name.models import DocTagName from ietf.person.factories import PersonFactory from ietf.utils.test_utils import TestCase from ietf.person.models import Person from ietf.doc.factories import DocumentFactory -from ietf.doc.models import State, DocumentActionHolder -from ietf.doc.utils import update_action_holders, add_state_change_event +from ietf.doc.models import State, DocumentActionHolder, DocumentAuthor +from ietf.doc.utils import update_action_holders, add_state_change_event, update_documentauthors class ActionHoldersTests(TestCase): @@ -204,4 +206,36 @@ class ActionHoldersTests(TestCase): for state in State.objects.filter(type='draft-iesg').exclude(slug='idexists'): doc.set_state(state) - self.assertTrue(doc.action_holders_enabled()) \ No newline at end of file + self.assertTrue(doc.action_holders_enabled()) + + +class MiscTests(TestCase): + def test_update_documentauthors_with_nulls(self): + """A 'None' value in the affiliation/country should be handled correctly""" + author_person = PersonFactory() + doc = DocumentFactory(authors=[author_person]) + doc.documentauthor_set.update( + affiliation='Some Affiliation', country='USA' + ) + try: + events = update_documentauthors( + doc, + [ + DocumentAuthor( + person=author_person, + email=author_person.email(), + affiliation=None, + country=None, + ) + ], + ) + except IntegrityError as err: + self.fail('IntegrityError was raised: {}'.format(err)) + + self.assertEqual(len(events), 1) + self.assertEqual(events[0].type, 'edited_authors') + self.assertIn('cleared affiliation (was "Some Affiliation")', events[0].desc) + self.assertIn('cleared country (was "USA")', events[0].desc) + docauth = doc.documentauthor_set.first() + self.assertEqual(docauth.affiliation, '') + self.assertEqual(docauth.country, '') \ No newline at end of file diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 5854a6dcb..a78f7e5b2 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -535,7 +535,7 @@ def update_documentauthors(doc, new_docauthors, by=None, basis=None): setattr(auth, field, newval) was_empty = oldval is None or len(str(oldval)) == 0 - now_empty = newval is None or len(str(oldval)) == 0 + now_empty = newval is None or len(str(newval)) == 0 # describe the change if oldval == newval: @@ -566,8 +566,8 @@ def update_documentauthors(doc, new_docauthors, by=None, basis=None): author_changes = [] # Now fill in other author details author_changes.append(_change_field_and_describe(auth, 'email', docauthor.email)) - author_changes.append(_change_field_and_describe(auth, 'affiliation', docauthor.affiliation)) - author_changes.append(_change_field_and_describe(auth, 'country', docauthor.country)) + author_changes.append(_change_field_and_describe(auth, 'affiliation', docauthor.affiliation or '')) + author_changes.append(_change_field_and_describe(auth, 'country', docauthor.country or '')) author_changes.append(_change_field_and_describe(auth, 'order', order + 1)) auth.save() log.assertion('auth.email_id != "none"') diff --git a/ietf/submit/test_submission_no_org_or_address.txt b/ietf/submit/test_submission_no_org_or_address.txt new file mode 100644 index 000000000..9f948e2ff --- /dev/null +++ b/ietf/submit/test_submission_no_org_or_address.txt @@ -0,0 +1,243 @@ + + + + +Network Working Group %(initials)s %(surname)s +Internet-Draft +Intended status: Informational %(month)s %(year)s +Expires: %(expiration)s + + + %(title)s + %(name)s + +Abstract + + This document describes how to test tests. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at http://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on %(expiration)s. + +Copyright Notice + + Copyright (c) %(year)s IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + +Name Expires %(expiration)s [Page 1] + +Internet-Draft Testing Tests %(month)s %(year)s + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Yang . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 3. JSON example . . . . . . . . . . . . . . . . . . . . . . . . 2 + 4. Security Considerations . . . . . . . . . . . . . . . . . . . 2 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 2 + 6. References . . . . . . . . . . . . . . . . . . . . . . . . . 2 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 2 + +1. Introduction + + This document describes a protocol for testing tests. + +2. Yang + + file "ietf-yang-metadata@2016-08-05.yang" + + module ietf-yang-metadata { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata"; + + prefix "md"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + + WG List: + + WG Chair: Lou Berger + + + WG Chair: Kent Watsen + + + Editor: Ladislav Lhotka + "; + + description + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. + + Copyright (c) 2016 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; + + revision 2016-08-05 { + description + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; + } + + extension annotation { + argument name; + description + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). + + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. + + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. + + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. + + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. + + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; + } + } + + + +3. JSON example + + The JSON object should look like this: + + { + "test": 1234 + } + +4. Security Considerations + + There are none. + +5. IANA Considerations + + No new registrations for IANA. + + [RFC8175] is mentioned here in order to give the reference + classification code a chance to mess up. + + +6. References + +6.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + +6.2. Informative References + + [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for + Writing an IANA Considerations Section in RFCs", BCP 26, + RFC 8126, DOI 10.17487/RFC8126, June 2017, + . + + [RFC8175] Ratliff, S., Jury, S., Satterwhite, D., Taylor, R., and B. + Berry, "Dynamic Link Exchange Protocol (DLEP)", RFC 8175, + DOI 10.17487/RFC8175, June 2017, + . + +Author's Address + + %(author)s + + Email: %(email)s + + + +Appendix A. Comments + + [RFC8174] is mentioned here just to give the reference classification + code a chance to mess up. + + + + + + + + + + + + + + + + + + + + +Name Expires %(expiration)s [Page 2] diff --git a/ietf/submit/test_submission_no_org_or_address.xml b/ietf/submit/test_submission_no_org_or_address.xml new file mode 100644 index 000000000..e957ceed4 --- /dev/null +++ b/ietf/submit/test_submission_no_org_or_address.xml @@ -0,0 +1,143 @@ + + + + + + %(title)s + + +
+ %(email)s +
+
+ + %(group)s + + + This document describes how to test tests. + + +
+ +
+ Introduction + + This document describes a protocol for testing tests. + +
+
+ Yang + + + WG List: + + WG Chair: Lou Berger + + + WG Chair: Kent Watsen + + + Editor: Ladislav Lhotka + "; + + description + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. + + Copyright (c) 2016 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; + + revision 2016-08-05 { + description + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; + } + + extension annotation { + argument name; + description + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). + + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. + + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. + + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. + + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. + + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; + } +} + +]]> +
+
+ JSON example + + The JSON object should look like this: + + { + "test": 1234 + } + +
+
+ Security Considerations + + There are none. + +
+
+ IANA Considerations + + No new registrations for IANA. + +
+
+ +
diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index d04bc0cdb..210017796 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -164,12 +164,17 @@ class SubmitTests(TestCase): settings.SUBMIT_YANG_CATALOG_MODEL_DIR = self.saved_yang_catalog_model_dir - def create_and_post_submission(self, name, rev, author, group=None, formats=("txt",)): - """Helper to create and post a submission""" + def create_and_post_submission(self, name, rev, author, group=None, formats=("txt",), base_filename=None): + """Helper to create and post a submission + + If base_filename is None, defaults to 'test_submission' + """ url = urlreverse('ietf.submit.views.upload_submission') files = dict() + for format in formats: - files[format], __ = submission_file(name, rev, group, format, "test_submission.%s" % format, author=author) + fn = '.'.join((base_filename or 'test_submission', format)) + files[format], __ = submission_file(name, rev, group, format, fn, author=author) r = self.client.post(url, files) if r.status_code != 302: @@ -821,6 +826,42 @@ class SubmitTests(TestCase): def test_submit_new_individual_txt_xml(self): self.submit_new_individual(["txt", "xml"]) + def submit_new_draft_no_org_or_address(self, formats): + name = 'draft-testing-no-org-or-address' + + author = PersonFactory() + self.client.login(username='secretary', password='secretary+password') + r = self.create_and_post_submission( + name, '00', author, formats=formats, base_filename='test_submission_no_org_or_address' + ) + status_url = r['Location'] + r = self.supply_extra_metadata(name, status_url, 'Submitter name', 'submitter@example.com', replaces='') + self.assertEqual(r.status_code, 302) + + # force post of submission + r = self.client.get(status_url) + q = PyQuery(r.content) + force_post_button = q('[type=submit]:contains("Force post")') + self.assertEqual(len(force_post_button), 1) + action = force_post_button.parents("form").find('input[type=hidden][name="action"]').val() + r = self.client.post(status_url, dict(action=action)) + + doc = Document.objects.get(docalias__name=name) + self.assertEqual(doc.documentauthor_set.count(), 1) + docauth = doc.documentauthor_set.first() + self.assertEqual(docauth.person, author) + self.assertEqual(docauth.affiliation, '') + self.assertEqual(docauth.country, '') + + def test_submit_new_draft_no_org_or_address_txt(self): + self.submit_new_draft_no_org_or_address(['txt']) + + def test_submit_new_draft_no_org_or_address_xml(self): + self.submit_new_draft_no_org_or_address(['xml']) + + def test_submit_new_draft_no_org_or_address_txt_xml(self): + self.submit_new_draft_no_org_or_address(['txt', 'xml']) + def _assert_extresources_in_table(self, response, extresources, th_label=None): """Assert that external resources are properly shown on the submission_status table""" q = PyQuery(response.content)