(specific|generic|general|third-party))/$', views.new),
+ url(r'^new-(?P<_type>(specific|generic|general|third-party))/$', views.new),
url(r'^search/$', views.search),
]
diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py
index 45fad9a2c..0347c4d78 100644
--- a/ietf/ipr/views.py
+++ b/ietf/ipr/views.py
@@ -475,28 +475,34 @@ def by_draft_recursive_txt(request):
return HttpResponse(content, content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET)
-def new(request, type, updates=None):
+def new(request, _type, updates=None):
"""Submit a new IPR Disclosure. If the updates field != None, this disclosure
updates one or more other disclosures."""
# Note that URL patterns won't ever send updates - updates is only non-null when called from code
# This odd construct flipping generic and general allows the URLs to say 'general' while having a minimal impact on the code.
# A cleanup to change the code to switch on type 'general' should follow.
- if type == 'generic' and updates: # Only happens when called directly from the updates view
+ if (
+ _type == "generic" and updates
+ ): # Only happens when called directly from the updates view
pass
- elif type == 'generic':
- return HttpResponseRedirect(urlreverse('ietf.ipr.views.new',kwargs=dict(type='general')))
- elif type == 'general':
- type = 'generic'
+ elif _type == "generic":
+ return HttpResponseRedirect(
+ urlreverse("ietf.ipr.views.new", kwargs=dict(_type="general"))
+ )
+ elif _type == "general":
+ _type = "generic"
else:
pass
# 1 to show initially + the template
- DraftFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=False, extra=1 + 1)
+ DraftFormset = inlineformset_factory(
+ IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=False, extra=1 + 1
+ )
- if request.method == 'POST':
- form = ipr_form_mapping[type](request.POST)
- if type != 'generic':
+ if request.method == "POST":
+ form = ipr_form_mapping[_type](request.POST)
+ if _type != "generic":
draft_formset = DraftFormset(request.POST, instance=IprDisclosureBase())
else:
draft_formset = None
@@ -505,72 +511,92 @@ def new(request, type, updates=None):
person = Person.objects.get(name="(System)")
else:
person = request.user.person
-
+
# check formset validity
- if type != 'generic':
+ if _type != "generic":
valid_formsets = draft_formset.is_valid()
else:
valid_formsets = True
-
+
if form.is_valid() and valid_formsets:
- if 'updates' in form.cleaned_data:
- updates = form.cleaned_data['updates']
- del form.cleaned_data['updates']
+ if "updates" in form.cleaned_data:
+ updates = form.cleaned_data["updates"]
+ del form.cleaned_data["updates"]
disclosure = form.save(commit=False)
disclosure.by = person
- disclosure.state = IprDisclosureStateName.objects.get(slug='pending')
+ disclosure.state = IprDisclosureStateName.objects.get(slug="pending")
disclosure.save()
-
- if type != 'generic':
+
+ if _type != "generic":
draft_formset = DraftFormset(request.POST, instance=disclosure)
draft_formset.save()
set_disclosure_title(disclosure)
disclosure.save()
-
+
if updates:
for ipr in updates:
- RelatedIpr.objects.create(source=disclosure,target=ipr,relationship_id='updates')
-
+ RelatedIpr.objects.create(
+ source=disclosure, target=ipr, relationship_id="updates"
+ )
+
# create IprEvent
IprEvent.objects.create(
- type_id='submitted',
+ type_id="submitted",
by=person,
disclosure=disclosure,
- desc="Disclosure Submitted")
+ desc="Disclosure Submitted",
+ )
# send email notification
- (to, cc) = gather_address_lists('ipr_disclosure_submitted')
- send_mail(request, to, ('IPR Submitter App', 'ietf-ipr@ietf.org'),
- 'New IPR Submission Notification',
+ (to, cc) = gather_address_lists("ipr_disclosure_submitted")
+ send_mail(
+ request,
+ to,
+ ("IPR Submitter App", "ietf-ipr@ietf.org"),
+ "New IPR Submission Notification",
"ipr/new_update_email.txt",
- {"ipr": disclosure,},
- cc=cc)
-
+ {
+ "ipr": disclosure,
+ },
+ cc=cc,
+ )
+
return render(request, "ipr/submitted.html")
else:
if updates:
original = IprDisclosureBase(id=updates).get_child()
initial = model_to_dict(original)
- initial.update({'updates':str(updates), })
- patent_info = text_to_dict(initial.get('patent_info', ''))
+ initial.update(
+ {
+ "updates": str(updates),
+ }
+ )
+ patent_info = text_to_dict(initial.get("patent_info", ""))
if list(patent_info.keys()):
- patent_dict = dict([ ('patent_'+k.lower(), v) for k,v in list(patent_info.items()) ])
+ patent_dict = dict(
+ [("patent_" + k.lower(), v) for k, v in list(patent_info.items())]
+ )
else:
- patent_dict = {'patent_notes': initial.get('patent_info', '')}
+ patent_dict = {"patent_notes": initial.get("patent_info", "")}
initial.update(patent_dict)
- form = ipr_form_mapping[type](initial=initial)
+ form = ipr_form_mapping[_type](initial=initial)
else:
- form = ipr_form_mapping[type]()
- disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
+ form = ipr_form_mapping[_type]()
+ disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
draft_formset = DraftFormset(instance=disclosure)
- return render(request, "ipr/details_edit.html", {
- 'form': form,
- 'draft_formset':draft_formset,
- 'type':type,
- })
+ return render(
+ request,
+ "ipr/details_edit.html",
+ {
+ "form": form,
+ "draft_formset": draft_formset,
+ "type": _type,
+ },
+ )
+
@role_required('Secretariat',)
def notify(request, id, type):
diff --git a/ietf/static/js/ipr-edit.js b/ietf/static/js/ipr-edit.js
index 9af5b0359..9d0750379 100644
--- a/ietf/static/js/ipr-edit.js
+++ b/ietf/static/js/ipr-edit.js
@@ -69,4 +69,69 @@ $(document)
form.find(".draft-row")
.each(updateRevisions);
}, 10);
- });
\ No newline at end of file
+
+ // Manage fields that depend on the Blanket IPR Disclosure choice
+ const blanketCheckbox = document.getElementById('id_is_blanket_disclosure')
+ if (blanketCheckbox) {
+ const patentDetailInputs = [
+ // The ids are from the HolderIprDisclosureForm and its base form class,
+ // intentionally excluding patent_notes because it's never required
+ 'id_patent_number',
+ 'id_patent_inventor',
+ 'id_patent_title',
+ 'id_patent_date'
+ ].map((id) => document.getElementById(id))
+ const patentDetailRowDivs = patentDetailInputs.map(
+ (elt) => elt.closest('div.row')
+ )
+ const royaltyFreeLicensingRadio = document.querySelector(
+ '#id_licensing input[value="royalty-free"]'
+ )
+ let lastSelectedLicensingRadio
+ const otherLicensingRadios = document.querySelectorAll(
+ '#id_licensing input:not([value="royalty-free"])'
+ )
+
+ const handleBlanketCheckboxChange = () => {
+ const isBlanket = blanketCheckbox.checked
+ // Update required fields
+ for (elt of patentDetailInputs) {
+ // disable the input element
+ elt.required = !isBlanket
+ }
+ for (elt of patentDetailRowDivs) {
+ // update the styling on the row that indicates required field
+ if (isBlanket) {
+ elt.classList.remove('required')
+ } else {
+ elt.classList.add('required')
+ }
+ }
+ // Update licensing selection
+ if (isBlanket) {
+ lastSelectedLicensingRadio = document.querySelector(
+ '#id_licensing input:checked'
+ )
+ royaltyFreeLicensingRadio.checked = true
+ otherLicensingRadios
+ .forEach(
+ (elt) => elt.setAttribute('disabled', '')
+ )
+ } else {
+ royaltyFreeLicensingRadio.checked = false
+ if (lastSelectedLicensingRadio) {
+ lastSelectedLicensingRadio.checked = true
+ }
+ otherLicensingRadios
+ .forEach(
+ (elt) => elt.removeAttribute('disabled')
+ )
+ }
+ }
+ handleBlanketCheckboxChange()
+ blanketCheckbox.addEventListener(
+ 'change',
+ (evt) => handleBlanketCheckboxChange()
+ )
+ }
+ });
diff --git a/ietf/templates/ipr/details_edit.html b/ietf/templates/ipr/details_edit.html
index 7caf28f1a..1aadb5bb3 100644
--- a/ietf/templates/ipr/details_edit.html
+++ b/ietf/templates/ipr/details_edit.html
@@ -32,7 +32,7 @@
regarding an IETF document or contribution when the person letting the
IETF know about the patent has no relationship with the patent owners.
Click
- here
+ here
if you want to disclose information about patents or patent
applications where you do have a relationship to the patent owners or
patent applicants.
@@ -121,12 +121,11 @@
{% endif %}
{% if type != "generic" %}
{% cycle section %}. IETF document or other contribution to which this IPR disclosure relates
-
+
If an Internet-Draft or RFC includes multiple parts and it is not
reasonably apparent which part of such Internet-Draft or RFC is alleged
- to be covered by the patent information disclosed in Section
- V(A) or V(B), please identify the sections of
- the Internet-Draft or RFC that are alleged to be so
+ to be covered by the patent information disclosed in Section V,
+ please identify the sections of the Internet-Draft or RFC that are alleged to be so
covered.
{{ draft_formset.management_form }}
@@ -154,6 +153,13 @@
i.e., patents or patent applications required to be disclosed by Section 5 of RFC8179
{% if form.patent_number %}
+ {% if form.is_blanket_disclosure %}
+
+ This IPR disclosure must either identify a specific patent or patents in sections V(A) and V(B)
+ below, or be made as a blanket IPR disclosure.
+
+ {% bootstrap_field form.is_blanket_disclosure layout='horizontal' %}
+ {% endif %}
A. For granted patents or published pending patent applications,
please provide the following information: