diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index 8aef976d6..86257abdc 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -46,10 +46,10 @@ class IprLicensing(models.Model): class IprDetail(models.Model): ipr_id = models.AutoField(primary_key=True) - p_h_legal_name = models.CharField("Patent Holder's Legal Name", blank=True, maxlength=255) + p_h_legal_name = models.CharField("Legal Name", blank=True, maxlength=255) document_title = models.CharField(blank=True, maxlength=255) - rfc_number = models.IntegerField(null=True, blank=True) # always NULL - id_document_tag = models.IntegerField(null=True, blank=True) # always NULL + rfc_number = models.IntegerField(null=True, editable=False, blank=True) # always NULL + id_document_tag = models.IntegerField(null=True, editable=False, blank=True) # always NULL other_designations = models.CharField(blank=True, maxlength=255) p_applications = models.TextField(blank=True, maxlength=255) date_applied = models.CharField(blank=True, maxlength=255) @@ -69,14 +69,13 @@ class IprDetail(models.Model): additional_old_url2 = models.CharField(blank=True, maxlength=255) country = models.CharField(blank=True, maxlength=100) p_notes = models.TextField(blank=True) - third_party = models.BooleanField() - lic_opt_a_sub = models.IntegerField(choices=STDONLY_CHOICES) - lic_opt_b_sub = models.IntegerField(choices=STDONLY_CHOICES) - lic_opt_c_sub = models.IntegerField(choices=STDONLY_CHOICES) - generic = models.BooleanField() - # I don't understand selectowned, it looks like it should be a boolean field. + third_party = models.BooleanField(editable=False) + lic_opt_a_sub = models.IntegerField(editable=False, choices=STDONLY_CHOICES) + lic_opt_b_sub = models.IntegerField(editable=False, choices=STDONLY_CHOICES) + lic_opt_c_sub = models.IntegerField(editable=False, choices=STDONLY_CHOICES) + generic = models.BooleanField(editable=False) selectowned = models.IntegerField(null=True, blank=True, choices=SELECT_CHOICES) - comply = models.BooleanField() + comply = models.BooleanField(editable=False) lic_checkbox = models.BooleanField() update_notified_date = models.DateField(null=True, blank=True) def __str__(self): @@ -103,16 +102,16 @@ class IprContact(models.Model): ('3', 'Submitter Contact'), ) contact_id = models.AutoField(primary_key=True) - ipr = models.ForeignKey(IprDetail, raw_id_admin=True, related_name="contact") - contact_type = models.IntegerField(choices=TYPE_CHOICES) + ipr = models.ForeignKey(IprDetail, raw_id_admin=True, editable=False, related_name="contact") + contact_type = models.IntegerField(editable=False, choices=TYPE_CHOICES) name = models.CharField(maxlength=255) title = models.CharField(blank=True, maxlength=255) department = models.CharField(blank=True, maxlength=255) + address1 = models.CharField(blank=True, maxlength=255) + address2 = models.CharField(blank=True, maxlength=255) telephone = models.CharField(maxlength=25) fax = models.CharField(blank=True, maxlength=25) email = models.CharField(maxlength=255) - address1 = models.CharField(blank=True, maxlength=255) - address2 = models.CharField(blank=True, maxlength=255) def __str__(self): return self.name class Meta: diff --git a/ietf/ipr/urls.py b/ietf/ipr/urls.py index 6cf1caccb..f58bc0223 100644 --- a/ietf/ipr/urls.py +++ b/ietf/ipr/urls.py @@ -14,6 +14,7 @@ queryset = models.IprDetail.objects.all() archive = {'queryset':queryset, 'date_field': 'submitted_date', 'allow_empty':True } urlpatterns += patterns('django.views.generic.date_based', + (r'^by-date/$', 'archive_index', archive), (r'^(?P\d{4})/$', 'archive_year', archive), (r'^(?P\d{4})/(?P[a-z]{3})/$', 'archive_month', archive), ) diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py index 2e34240cd..53d5eda12 100644 --- a/ietf/ipr/views.py +++ b/ietf/ipr/views.py @@ -1,6 +1,7 @@ import models from django.shortcuts import render_to_response as render import django.newforms as forms +import ietf.utils def default(request): """Default page, with links to sub-pages""" @@ -62,35 +63,45 @@ def update(request, ipr_id=None): def new(request, type): """Form to make a new IPR disclosure""" debug = "" - + sections = { + "section1": "p_h_legal_name ", + "section2": "ph_name ph_title ph_department ph_address1 ph_address2 ph_telephone ph_fax ph_email", + "section3": "ietf_name ietf_title ietf_department ietf_address1 ietf_address2 ietf_telephone ietf_fax ietf_email", + "section4": "rfclist draftlist other_designations", + "section5": "p_applications date_applied country selecttype p_notes discloser_identify", + "section6": "licensing_option stdonly_license comments lic_checkbox selectowned", + "section7": "sub_name sub_title sub_department sub_address1 sub_address2 sub_telephone sub_fax sub_email", + "section8": "other_notes", + "ignore" : "document_title rfc_number id_document_tag submitted_date status " + + "old_ipr_url additional_old_title1 additional_old_title2 " + + "additional_old_url1 additional_old_url2 update_notified_date", + } IprForm = forms.form_for_model(models.IprDetail, formfield_callback=detail_field_fixup) + ContactForm = forms.form_for_model(models.IprContact) + + # It would be nicer if we could use mixin subclassing, but that won't + # work with multiple classes with the same elements. + for prefix in ["ph", "ietf", "sub"]: + for field in ContactForm.base_fields: + IprForm.base_fields[prefix + "_" + field] = ContactForm.base_fields[field] + # Some extra fields which will get post-processing to generate the IprRfcs # and IprDrafts entries which go into the database: IprForm.base_fields["rfclist"] = forms.CharField(required=False) IprForm.base_fields["draftlist"] = forms.CharField(required=False) IprForm.base_fields["stdonly_license"] = forms.BooleanField(required=False) - ContactForm = forms.form_for_model(models.IprContact) - if request.method == 'POST': form = IprForm(request.POST) - - form.holder_contact = ContactForm(request.POST, prefix="ph") - form.ietf_contact = ContactForm(request.POST, prefix="ietf") - form.submitter = ContactForm(request.POST, prefix="sub") - if form.is_valid(): form.save() return HttpResponseRedirect("/ipr/") else: form = IprForm() - form.holder_contact = ContactForm(prefix="ph") - form.ietf_contact = ContactForm(prefix="ietf") - form.submitter = ContactForm(prefix="sub") - form.unbound_form = not form.is_bound - form.disclosure_type = type.capitalize() - return render("ipr/new_%s.html" % type, {"ipr": form, "debug": debug, }) + blocks = ietf.utils.split_form(form.as_table(), sections ) + + return render("ipr/new_%s.html" % type, {"ipr": form, "form": blocks}) def detail_field_fixup(field): if field.name == "licensing_option": diff --git a/ietf/templates/ipr/details.html b/ietf/templates/ipr/details.html index eb4a40a78..b5f9ddffe 100644 --- a/ietf/templates/ipr/details.html +++ b/ietf/templates/ipr/details.html @@ -24,6 +24,7 @@ input { width: 72ex; font-family: sans-serif; font-size: 11pt; font-weight: normal; } input[type="radio"] { width: auto; } input[type="checkbox"] { width: auto; } + input[type="submit"] { width: auto; } textarea { width: 72ex; height: 5em; font-family: sans-serif; font-size: 11pt; font-weight: normal; } .required { color: red; } @@ -113,7 +114,9 @@ + {% block section1_data %} Legal Name: {{ ipr.p_h_legal_name }} + {% endblock %} @@ -128,6 +131,7 @@ Patent Holder's Contact for License Application + {% block section2_data %} Name: {{ ipr.holder_contact.name }} Title: {{ ipr.holder_contact.title }} Department: {{ ipr.holder_contact.department }} @@ -136,13 +140,14 @@ Telephone: {{ ipr.holder_contact.telephone }} Fax: {{ ipr.holder_contact.fax }} Email: {{ ipr.holder_contact.email }} + {% endblock %} {% endblock %} {% block section3 %} - {% if ipr.unbound_form or not ipr.old_ipr_url %} + {% if not ipr.is_bound or not ipr.old_ipr_url %}
@@ -151,6 +156,7 @@ Contact Information for the IETF Participant Whose Personal Belief Triggered this Disclosure: + {% block section3_data %} {% if ipr.unbond_form or ipr.ietf_contact.name %} @@ -163,6 +169,7 @@ {% else %} {% endif %} + {% endblock %}
Name: {{ ipr.ietf_contact.name }}
Title: {{ ipr.ietf_contact.title }}
No information submitted
{% else %} @@ -180,29 +187,23 @@ IETF Document or Other Contribution to Which this IPR Disclosure Relates: - {% if ipr.unbound_form %} - RFC Number(s) (Numeric value only):{{ ipr.rfclist }} - {% else %} + {% block section4_data %} {% for rfc in ipr.rfcs.all %} RFC {{ rfc.rfc_number.rfc_number }}:"{{ rfc.rfc_number.rfc_name }}" {% endfor %} - {% endif %} - - {% if ipr.unbound_form %} - I-D filename(s) (draft-...):{{ ipr.draftlist }} - {% else %} + {% for draft in ipr.drafts.all %} Internet-Draft:"{{ draft.document.id_document_name }}"
({{ draft.document.filename }}-{{ draft.document.revision }})
{% endfor %} - {% endif %} - {% if ipr.unbound_form or ipr.other_designations %} + {% if ipr.other_designations %} Designations for Other Contributions:{{ ipr.other_designations }} - {% endif %} + {% endif %} + {% endblock %} {% endblock %} - {% if ipr.unbound_form or not ipr.old_ipr_url %} + {% if not ipr.is_bound or not ipr.old_ipr_url %} {% block section5 %}
@@ -214,34 +215,24 @@ applications required to be disclosed by Section 6 of RFC 3979) - {% if ipr.unbound_form or ipr.p_applications or ipr.p_notes %} - - - A. For granted patents or published pending patent applications, - please provide the following information: - - Patent, Serial, Publication, Registration, - or Application/File number(s):{{ ipr.p_applications }} - Date(s) granted or applied for: {{ ipr.date_applied }} - Country: {{ ipr.country }} - {% if ipr.unbound_form %} - Additional Notes: {{ ipr.p_notes }} - {% else %} - Additional Notes: {{ ipr.p_notes|escape|linebreaks }} - {% endif %} - - - B. Does this disclosure relate to an unpublished pending patent - application?: - {{ ipr.get_selecttype_display }} - - {% if ipr.unbound_form %} - - - {{ ipr.selecttype }} - - - {% endif %} + {% block section5_data %} + {% if ipr.p_applications or ipr.p_notes %} + + + A. For granted patents or published pending patent applications, + please provide the following information: + + Patent, Serial, Publication, Registration, + or Application/File number(s):{{ ipr.p_applications }} + Date(s) granted or applied for: {{ ipr.date_applied }} + Country: {{ ipr.country }} + Additional Notes: {{ ipr.p_notes|escape|linebreaks }} + + + B. Does this disclosure relate to an unpublished pending patent + application?: + {{ ipr.get_selecttype_display }} + {% block clause5c %} @@ -253,19 +244,16 @@ covered: - {% if ipr.unbound_form %} - {{ ipr.discloser_identify }} + {% if ipr.discloser_identify %} + {{ ipr.discloser_identify|escape|linebreaks }} {% else %} - {% if ipr.discloser_identify %} - {{ ipr.discloser_identify|escape|linebreaks }} - {% else %} - No information submitted - {% endif %} + No information submitted {% endif %} {% endblock %} {% else %} This disclosure relates to an unpublished pending patent application. {% endif %} + {% endblock %}
{% endblock %} @@ -290,18 +278,13 @@ specification, is as follows(select one licensing declaration option only): + {% block section6_data %} - {% if ipr.unbound_form %} - {{ ipr.licensing_option }} - {{ ipr.stdonly_license }} - This licensing declaration is limited solely to standards-track IETF documents. - {% else %} {{ ipr.get_licensing_option_display }}
{{ ipr.get_lic_opt_a_sub_display }} {{ ipr.get_lic_opt_b_sub_display }} {{ ipr.get_lic_opt_c_sub_display }}
- {% endif %} @@ -309,20 +292,15 @@ Licensing information, comments, notes, or URL for further information: - {% if ipr.unbound_form %} - {{ ipr.comments }} + {% if ipr.comments %} + {{ ipr.comments|escape|linebreaks }} {% else %} - {% if ipr.comments %} - {{ ipr.comments|escape|linebreaks }} - {% else %} - No information submitted - {% endif %} + No information submitted {% endif %} - {% if ipr.unbound_form or ipr.lic_checkbox %} + {% if ipr.lic_checkbox %} - {% if ipr.unbound_form %} {{ ipr.lic_checkbox }} {% endif %} The individual submitting this template represents and warrants that all terms and conditions that must be satisfied for implementers of any covered IETF specification to obtain a license have been disclosed in this @@ -330,6 +308,7 @@ {% endif %} + {% endblock %} Note: The individual submitting this template represents and warrants @@ -352,7 +331,8 @@ IETF Participant in Section III above) - {% if ipr.unbound_form or ipr.submitter.name %} + {% block section7_data %} + {% if ipr.submitter.name %} Name: {{ ipr.submitter.name }} Title: {{ ipr.submitter.title }} Department: {{ ipr.submitter.department }} @@ -364,6 +344,7 @@ {% else %} No information submitted {% endif %} + {% endblock %} {% endblock %} @@ -378,19 +359,20 @@ Other Notes: - {% if ipr.unbound_form %} - {{ ipr.other_notes }} - {% else %} + {% block section8_data %} {% if ipr.other_notes %} {{ ipr.other_notes|escape|linebreaks }} {% else %} No information submitted {% endif %} - {% endif %} + {% endblock %} {% endblock %} {% endif %} {{ debug }} + + {% block bot_info %} + {% endblock %} {% endblock %} diff --git a/ietf/templates/ipr/iprdetail_archive.html b/ietf/templates/ipr/iprdetail_archive.html index a2de8b86a..7319bd588 100644 --- a/ietf/templates/ipr/iprdetail_archive.html +++ b/ietf/templates/ipr/iprdetail_archive.html @@ -21,7 +21,7 @@

Archives by Year

diff --git a/ietf/templates/ipr/new.html b/ietf/templates/ipr/new.html index 1dd825f1c..19fbc2ff8 100644 --- a/ietf/templates/ipr/new.html +++ b/ietf/templates/ipr/new.html @@ -53,4 +53,18 @@

{% endif %} +
{% endblock %} + +{% block section1_data %}{{ form.section1 }}{% endblock %} +{% block section2_data %}{{ form.section2 }}{% endblock %} +{% block section3_data %}{{ form.section3 }}{% endblock %} +{% block section4_data %}{{ form.section4 }}{% endblock %} +{% block section5_data %}{{ form.section5 }}{% endblock %} +{% block section6_data %}{{ form.section6 }}{% endblock %} +{% block section7_data %}{{ form.section7 }}{% endblock %} +{% block section8_data %}{{ form.section8 }}{% endblock %} +{% block bot_info %} +
+
+{% endblock %} \ No newline at end of file diff --git a/ietf/utils.py b/ietf/utils.py index d361425cb..05e34c4a7 100644 --- a/ietf/utils.py +++ b/ietf/utils.py @@ -131,3 +131,48 @@ def flattenl(list): [ 'a', 'b', 'c', 'd' ] """ return reduce(operator.__concat__, list) + + +def split_form(html, blocks): + """Split the rendering of a form into a dictionary of named blocks. + + Takes the html of the rendered form as the first argument. + + Expects a dictionary as the second argument, with desired block + name and a field specification as key:value pairs. + + The field specification can be either a list of field names, or + a string with the field names separated by whitespace. + + The return value is a new dictionary, with the same keys as the + block specification dictionary, and the form rendering matching + the specified keys as the value. + + Any line in the rendered form which doesn't match any block's + field list will cause an exception to be raised. + """ + import re + output = dict([(block,[]) for block in blocks]) + # handle field lists in string form + for block in blocks: + if type(blocks[block]) == type(""): + blocks[block] = blocks[block].split() + + # collapse radio button html to one line + html = re.sub('\n(.*type="radio".*\n)', "\g<1>", html) + html = re.sub('(?m)^(.*type="radio".*)\n', "\g<1>", html) + + for line in html.split('\n'): + found = False + for block in blocks: + for field in blocks[block]: + if ('name="%s"' % field) in line: + output[block].append(line) + found = True + if not found: + raise LookupError("Could not place line in any section: '%s'" % line) + + for block in output: + output[block] = "\n".join(output[block]) + + return output