diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index cb387107b..27faf15d4 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -78,9 +78,9 @@ class IprDetail(models.Model): discloser_identify = models.TextField("Specific document sections covered", blank=True, maxlength=255, db_column='disclouser_identify') # Patent Information fieldset - p_applications = models.TextField("Patent Applications", blank=True, maxlength=255) - date_applied = models.CharField(blank=True, maxlength=255) - country = models.CharField(blank=True, maxlength=100) + p_applications = models.TextField("Patent Applications", maxlength=255) + date_applied = models.DateField(maxlength=255) + country = models.CharField(maxlength=100) p_notes = models.TextField("Additional notes", blank=True) selecttype = models.IntegerField("Unpublished Pending Patent Application", null=True, choices=SELECT_CHOICES) selectowned = models.IntegerField("Applies to all IPR owned by Submitter", null=True, blank=True, choices=SELECT_CHOICES) diff --git a/ietf/ipr/view_new.py b/ietf/ipr/view_new.py new file mode 100644 index 000000000..ca747177b --- /dev/null +++ b/ietf/ipr/view_new.py @@ -0,0 +1,141 @@ +import re +import models +import ietf.utils +import django.utils.html +import django.newforms as forms +from django.shortcuts import render_to_response as render +from ietf.utils import log +from ietf.ipr.view_sections import section_table + +# ---------------------------------------------------------------- +# Callback methods for special field cases. +# ---------------------------------------------------------------- + +def ipr_detail_form_callback(field, **kwargs): + if field.name == "licensing_option": + return forms.IntegerField(widget=forms.RadioSelect(choices=models.LICENSE_CHOICES), required=True) + if field.name in ["selecttype", "selectowned"]: + return forms.IntegerField(widget=forms.RadioSelect(choices=((1, "YES"), (2, "NO"))), required=False) + return field.formfield(**kwargs) + +def ipr_contact_form_callback(field, **kwargs): + phone_re = re.compile(r'^\+?[0-9 ]*(\([0-9]+\))?[0-9 -]+$') + error_message = """Phone numbers may have a leading "+", and otherwise only contain + numbers [0-9]; dash, period or space; parentheses, and an optional + extension number indicated by 'x'. """ + + if field.name == "telephone": + return forms.RegexField(phone_re, error_message=error_message, **kwargs) + if field.name == "fax": + return forms.RegexField(phone_re, error_message=error_message, required=False, **kwargs) + return field.formfield(**kwargs) + # TODO: + # Add rfc existence validation for RFC field + # Add draft existence validation for Drafts field + +# ---------------------------------------------------------------- +# Classes +# ---------------------------------------------------------------- + +# Get a form class which renders fields using a given template +CustomForm = ietf.utils.makeFormattingForm(template="ipr/formfield.html") + +# Get base form classes for our models +BaseIprForm = forms.form_for_model(models.IprDetail, form=CustomForm, formfield_callback=ipr_detail_form_callback) +BaseContactForm = forms.form_for_model(models.IprContact, form=CustomForm, formfield_callback=ipr_contact_form_callback) + +# Some subclassing: + +# The contact form will be part of the IprForm, so it needs a widget. +# Define one. +class MultiformWidget(forms.Widget): + def value_from_datadict(self, data, name): + return data + +class ContactForm(BaseContactForm): + widget = MultiformWidget() + + def add_prefix(self, field_name): + return self.prefix and ('%s_%s' % (self.prefix, field_name)) or field_name + def clean(self, *value): + if value: + return self.full_clean() + else: + return self.clean_data + + +# ---------------------------------------------------------------- +# Form processing +# ---------------------------------------------------------------- + +def new(request, type): + """Make a new IPR disclosure. + + This is a big function -- maybe too big. Things would be easier if we didn't have + one form containing fields from 4 tables -- don't build something like this again... + + """ + debug = "" + + section_list = section_table[type].copy() + section_list.update({"title":False, "new_intro":False, "form_intro":True, + "form_submit":True, "form_legend": True, }) + + class IprForm(BaseIprForm): + holder_contact = None + rfclist = forms.CharField(required=False) + draftlist = forms.CharField(required=False) + stdonly_license = forms.BooleanField(required=False) + ietf_contact_is_submitter = forms.BooleanField(required=False) + if "holder_contact" in section_list: + holder_contact = ContactForm(prefix="hold") + if "ietf_contact" in section_list: + ietf_contact = ContactForm(prefix="ietf") + if "submitter" in section_list: + submitter = ContactForm(prefix="subm") + def __init__(self, *args, **kw): + for contact in ["holder_contact", "ietf_contact", "submitter"]: + if contact in section_list: + self.base_fields[contact] = ContactForm(prefix=contact[:4], *args, **kw) + self.base_fields["ietf_contact_is_submitter"] = forms.BooleanField(required=False) + BaseIprForm.__init__(self, *args, **kw) + # Special validation code + def clean(self): + # Required: + # Submitter form filled in or 'same-as-ietf-contact' marked + # Only one of rfc, draft, and other info fields filled in + # RFC exists or draft exists and has right rev. or ... + + if self.ietf_contact_is_submitter: + self.submitter = self.ietf_contact + pass + if request.method == 'POST': + data = request.POST.copy() + if "ietf_contact_is_submitter" in data: + for subfield in ["name", "title", "department", "address1", "address2", "telephone", "fax", "email"]: + try: + data["subm_%s"%subfield] = data["ietf_%s"%subfield] + except Exception, e: + #log("Caught exception: %s"%e) + pass + form = IprForm(data) + if form.ietf_contact_is_submitter: + form.ietf_contact_is_submitter_checked = "checked" + if form.is_valid(): + #instance = form.save() + #return HttpResponseRedirect("/ipr/ipr-%s" % instance.ipr_id) + #return HttpResponseRedirect("/ipr/") + + pass + else: + for error in form.errors: + log("Form error for field: %s"%error) + # Fall through, and let the partially bound form, with error + # indications, be rendered again. + pass + else: + form = IprForm() + form.unbound_form = True + + # ietf.utils.log(dir(form.ietf_contact_is_submitter)) + return render("ipr/details.html", {"ipr": form, "section_list":section_list, "debug": debug}) diff --git a/ietf/ipr/view_sections.py b/ietf/ipr/view_sections.py new file mode 100644 index 000000000..22a3f2eb3 --- /dev/null +++ b/ietf/ipr/view_sections.py @@ -0,0 +1,36 @@ + +section_table = { + "index": { "index": True }, + "specific": { "index": False, "title": True, "specific": True, + "legacy_intro": False, "new_intro": True, "form_intro": False, + "holder": True, "holder_contact": True, "ietf_contact": True, + "ietf_doc": True, "patent_info": True, "licensing": True, + "submitter": True, "notes": True, "form_submit": False, + "disclosure_type": "Specific", "form_legend": False, + "per_rfc_disclosure": True, "also_specific": False, + }, + "generic": { "index": False, "title": True, "generic": True, + "legacy_intro": False, "new_intro": True, "form_intro": False, + "holder": True, "holder_contact": True, "ietf_contact": False, + "ietf_doc": False, "patent_info": True, "licensing": True, + "submitter": True, "notes": True, "form_submit": False, + "disclosure_type": "Generic", "form_legend": False, + "per_rfc_disclosure": False, "also_specific": True, + }, + "third_party": {"index": False, "title": True, "third_party": True, + "legacy_intro": False, "new_intro": True, "form_intro": False, + "holder": True, "holder_contact": False, "ietf_contact": True, + "ietf_doc": True, "patent_info": True, "licensing": False, + "submitter": False, "notes": False, "form_submit": False, + "disclosure_type": "Third Party", "form_legend": False, + "per_rfc_disclosure": False, "also_specific": False, + }, + "legacy": { "index": False, "title": True, "legacy": True, + "legacy_intro": True, "new_intro": False, "form_intro": False, + "holder": True, "holder_contact": True, "ietf_contact": False, + "ietf_doc": True, "patent_info": False, "licensing": False, + "submitter": False, "notes": False, "form_submit": False, + "disclosure_type": "Legacy", "form_legend": False, + "per_rfc_disclosure": False, "also_specific": False, + }, + } diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py index 224a6e671..5284c729a 100644 --- a/ietf/ipr/views.py +++ b/ietf/ipr/views.py @@ -1,12 +1,10 @@ import re import models -import ietf.utils import django.utils.html -import django.newforms as forms from django.shortcuts import render_to_response as render from django.utils.html import escape -from ietf.contrib.form_decorator import form_decorator -from ietf.utils import log as log +from ietf.ipr.view_new import new +from ietf.ipr.view_sections import section_table def linebreaks(value): if value: @@ -42,39 +40,10 @@ def list(request, template): # Details views -section_table = { - "index": { "index": True }, - "specific": { "index": False, "title": True, "specific": True, - "legacy_intro": False, "new_intro": True, "form_intro": False, - "holder": True, "holder_contact": True, "ietf_contact": True, - "ietf_doc": True, "patent_info": True, "licensing": True, - "submitter": True, "notes": True, "form_submit": False, - }, - "generic": { "index": False, "title": True, "generic": True, - "legacy_intro": False, "new_intro": True, "form_intro": False, - "holder": True, "holder_contact": True, "ietf_contact": False, - "ietf_doc": False, "patent_info": True, "licensing": True, - "submitter": True, "notes": True, "form_submit": False, - }, - "third_party": {"index": False, "title": True, "third_party": True, - "legacy_intro": False, "new_intro": True, "form_intro": False, - "holder": True, "holder_contact": False, "ietf_contact": True, - "ietf_doc": True, "patent_info": True, "licensing": False, - "submitter": False, "notes": False, "form_submit": False, - }, - "legacy": { "index": False, "title": True, "legacy": True, - "legacy_intro": True, "new_intro": False, "form_intro": False, - "holder": True, "holder_contact": True, "ietf_contact": False, - "ietf_doc": True, "patent_info": False, "licensing": False, - "submitter": False, "notes": False, "form_submit": False, - }, - } - def show(request, ipr_id=None): """Show a specific IPR disclosure""" assert ipr_id != None ipr = models.IprDetail.objects.filter(ipr_id=ipr_id)[0] - ipr.disclosure_type = get_disclosure_type(ipr) section_list = get_section_list(ipr) contacts = ipr.contact.all() for contact in contacts: @@ -105,130 +74,10 @@ def update(request, ipr_id=None): # TODO: replace the placeholder code with the appropriate update code return show(request, ipr_id) -def new(request, type): - """Make a new IPR disclosure""" - debug = "" - - # define callback methods for special field cases. - def ipr_detail_form_callback(field, **kwargs): - if field.name == "licensing_option": - return forms.IntegerField(widget=forms.RadioSelect(choices=models.LICENSE_CHOICES), required=False) - if field.name in ["selecttype", "selectowned"]: - return forms.IntegerField(widget=forms.RadioSelect(choices=((1, "YES"), (2, "NO"))), required=False) - return field.formfield(**kwargs) - - def ipr_contact_form_callback(field, **kwargs): - phone_re = re.compile(r'^\+?[0-9 ]*(\([0-9]+\))?[0-9 -]+$') - error_message = """Phone numbers may have a leading "+", and otherwise only contain - numbers [0-9]; dash, period or space; parentheses, and an optional - extension number indicated by 'x'. """ - - if field.name == "telephone": - return forms.RegexField(phone_re, error_message=error_message, **kwargs) - if field.name == "fax": - return forms.RegexField(phone_re, error_message=error_message, required=False, **kwargs) - return field.formfield(**kwargs) - - # Get a form class which renders fields using a given template - CustomForm = ietf.utils.makeFormattingForm(template="ipr/formfield.html") - - # Get base form classes for our models - BaseIprForm = forms.form_for_model(models.IprDetail, form=CustomForm, formfield_callback=ipr_detail_form_callback) - BaseContactForm = forms.form_for_model(models.IprContact, form=CustomForm, formfield_callback=ipr_contact_form_callback) - - section_list = section_table[type] - section_list.update({"title":False, "new_intro":False, "form_intro":True, "form_submit":True, }) - - # Some subclassing: - - # The contact form will be part of the IprForm, so it needs a widget. - # Define one. - class MultiformWidget(forms.Widget): - def value_from_datadict(self, data, name): - return data - - class ContactForm(BaseContactForm): - widget = MultiformWidget() - - def add_prefix(self, field_name): - return self.prefix and ('%s_%s' % (self.prefix, field_name)) or field_name - def clean(self, *value): - if value: - return self.full_clean() - else: - return self.clean_data - - class IprForm(BaseIprForm): - holder_contact = None - rfclist = forms.CharField(required=False) - draftlist = forms.CharField(required=False) - stdonly_license = forms.BooleanField(required=False) - ietf_contact_is_submitter = forms.BooleanField(required=False) - if "holder_contact" in section_list: - holder_contact = ContactForm(prefix="hold") - if "ietf_contact" in section_list: - ietf_contact = ContactForm(prefix="ietf") - if "submitter" in section_list: - submitter = ContactForm(prefix="subm") - def __init__(self, *args, **kw): - for contact in ["holder_contact", "ietf_contact", "submitter"]: - if contact in section_list: - self.base_fields[contact] = ContactForm(prefix=contact[:4], *args, **kw) - self.base_fields["ietf_contact_is_submitter"] = forms.BooleanField(required=False) - BaseIprForm.__init__(self, *args, **kw) - # Special validation code - def clean(self): - # Required: - # Submitter form filled in or 'same-as-ietf-contact' marked - # Only one of rfc, draft, and other info fields filled in - # RFC exists or draft exists and has right rev. or ... - if self.ietf_contact_is_submitter: - self.submitter = self.ietf_contact - pass - - if request.method == 'POST': - data = request.POST.copy() - if "ietf_contact_is_submitter" in data: - for subfield in ["name", "title", "department", "address1", "address2", "telephone", "fax", "email"]: - try: - data["subm_%s"%subfield] = data["ietf_%s"%subfield] - except Exception, e: - #log("Caught exception: %s"%e) - pass - form = IprForm(data) - if form.ietf_contact_is_submitter: - form.ietf_contact_is_submitter_checked = "checked" - if form.is_valid(): - #instance = form.save() - #return HttpResponseRedirect("/ipr/ipr-%s" % instance.ipr_id) - #return HttpResponseRedirect("/ipr/") - pass - else: - for error in form.errors: - log("Form error: %s"%error) - # Fall through, and let the partially bound form, with error - # indications, be rendered again. - pass - else: - form = IprForm() - form.unbound_form = True - - # ietf.utils.log(dir(form.ietf_contact_is_submitter)) - return render("ipr/details.html", {"ipr": form, "section_list":section_list, "debug": debug}) - # ---- Helper functions ------------------------------------------------------ -def get_disclosure_type(ipr): - if ipr.generic: - assert not ipr.third_party - return "Generic" - elif ipr.third_party: - return "Third Party" - else: - return "Specific" - def get_section_list(ipr): if ipr.old_ipr_url: return section_table["legacy"] diff --git a/ietf/templates/ipr/details.html b/ietf/templates/ipr/details.html index 56bb036af..0e035438e 100644 --- a/ietf/templates/ipr/details.html +++ b/ietf/templates/ipr/details.html @@ -4,6 +4,7 @@ {% block content %} {% include "ipr/style.html" %} +{% include "ipr/js.html" %}
{% if section_list.title %} @@ -26,14 +27,14 @@@@ -155,7 +173,7 @@
{% endif %} Sections {% block legacy_sections %}I, II, and IV{% endblock %} of "The Patent Disclosure and Licensing Declaration Template - for {{ ipr.disclosure_type }} IPR Disclosures" have been completed for this IPR disclosure. + for {{ section_list.disclosure_type }} IPR Disclosures" have been completed for this IPR disclosure. Additional information may be available in the original submission.
See the content of the original IPR disclosure.
{% endif %} {% if section_list.new_intro %} Only those sections of the "Patent Disclosure and Licensing Declaration - Template for {{ ipr.disclosure_type }} IPR Disclosures" where the submitter provided + Template for {{ section_list.disclosure_type }} IPR Disclosures" where the submitter provided information are displayed.
{% endif %} {% if section_list.new_intro or section_list.legacy_intro %} @@ -105,7 +106,7 @@ {% endif %} {% if section_list.form_intro %} -The Patent Disclosure and Licensing Declaration Template for {{ ipr.disclosure_type }} IPR Disclosures
+The Patent Disclosure and Licensing Declaration Template for {{ section_list.disclosure_type }} IPR Disclosures
This document is an IETF IPR Disclosure and Licensing Declaration @@ -113,11 +114,30 @@ application information regarding the IETF document or contribution listed in Section IV, and b) an IPR Holder's intention with respect to the licensing of its necessary patent claims. No actual license is - implied by submission of this template. Please complete and submit a - separate template for each IETF document or contribution to which the - disclosed patent information relates. + implied by submission of this template.
+ + {% if section_list.also_specific %} ++ + Note: According to Section 6.4.3 of RFC + 3979, "Intellectual Property Rights in IETF Technology," you + are still required to file specific disclosures on IPR unless your + generic disclosure satisfies certain conditions. Please see the + RFC for details. +
+ {% endif %} + + {% if section_list.per_rfc_disclosure %} ++ Please complete and submit a + separate template for each IETF document or contribution to which the + disclosed patent information relates. +
+ {% endif %} +If you wish to submit your IPR disclosure by e-mail, then please send @@ -126,7 +146,7 @@ requirements of Section 6, "IPR Disclosures," of RFC 3979, "Intellectual Property Rights in IETF Technology," will be posted, but - will be marked as "non-compliant." + will be marked as "non-compliant".
@@ -135,17 +155,15 @@ {% if ipr.errors %} -- {% for error in ipr.errors %} -
+- - {% endfor %} -- --
-- {{ error }}
-+ There were errors in the submitted form -- see below. Please correct these and resubmit. +
+ {% endif %} + + {% if section_list.form_legend %} ++ Fields marked with * are required. +
{% endif %}
+ {% if section_list.form_legend %}*{% endif %} {% cycle section %}. IETF Document or Other Contribution to Which this IPR Disclosure Relates: | |
---|---|
RFC {{ rfc.rfc_number.rfc_number }}: | "{{ rfc.rfc_number.rfc_name }}" |
Designations for Other Contributions: | {{ ipr.other_designations }} |