* Added a new funtion in utils.py: split_form()

* Re-wrote the IPR declaration form using form.to_table()
   and the split_form() function in order to get sub-blocks
   of the form which could easily be used with the existing
   IPR detail display templates.

   How to merge forms from multiple models took some thinking;
   since the forms have a common ancestor, multiple inheritance
   doesn't preserve the form data.  In the end the merging
   didn't turn out too horrible.  See ipr.views.new().
 * Changed the IprDetail model; first to specify editable=False
   for all fieleds which shouldn't be shown in the form, but
   this has the drawback of also removing them from the admin
   page form.  Simply bagging them in an un-used sub block with
   split_form() works fine.
 * Changed the URLs for IPR by-date some again
 * Updated the ipr/new* templates to use the form sub-blocks
 - Legacy-Id: 97
This commit is contained in:
Henrik Levkowetz 2007-05-04 20:21:03 +00:00
parent 5872696834
commit c2c08c9edc
7 changed files with 149 additions and 97 deletions

View file

@ -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:

View file

@ -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<year>\d{4})/$', 'archive_year', archive),
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', archive),
)

View file

@ -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":

View file

@ -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; }
</style>
@ -113,7 +114,9 @@
</th>
</tr>
<tr>
{% block section1_data %}
<td class="fixwidth">Legal Name:</td> <td><b> {{ ipr.p_h_legal_name }} </b></td>
{% endblock %}
</tr>
</table>
</blockquote>
@ -128,6 +131,7 @@
Patent Holder's Contact for License Application
</th>
</tr>
{% block section2_data %}
<tr><td class="fixwidth">Name:</td> <td><b>{{ ipr.holder_contact.name }}</b></td></tr>
<tr><td class="fixwidth">Title:</td> <td><b>{{ ipr.holder_contact.title }}</b></td></tr>
<tr><td class="fixwidth">Department:</td> <td><b>{{ ipr.holder_contact.department }}</b></td></tr>
@ -136,13 +140,14 @@
<tr><td class="fixwidth">Telephone:</td> <td><b>{{ ipr.holder_contact.telephone }}</b></td></tr>
<tr><td class="fixwidth">Fax:</td> <td><b>{{ ipr.holder_contact.fax }}</b></td></tr>
<tr><td class="fixwidth">Email:</td> <td><b>{{ ipr.holder_contact.email }}</b></td></tr>
{% endblock %}
</table>
</blockquote>
{% endblock %}
{% block section3 %}
{% if ipr.unbound_form or not ipr.old_ipr_url %}
{% if not ipr.is_bound or not ipr.old_ipr_url %}
<blockquote class="{% cycle parity %}">
<table border="0" cellpadding="0" cellspacing="0" class="ipr person">
<tr>
@ -151,6 +156,7 @@
Contact Information for the IETF Participant Whose Personal Belief Triggered this Disclosure:
</th>
</tr>
{% block section3_data %}
{% if ipr.unbond_form or ipr.ietf_contact.name %}
<tr><td class="fixwidth">Name:</td> <td><b>{{ ipr.ietf_contact.name }}</b></td></tr>
<tr><td class="fixwidth">Title:</td> <td><b>{{ ipr.ietf_contact.title }}</b></td></tr>
@ -163,6 +169,7 @@
{% else %}
<tr><td colspan="2"><i>No information submitted</td></tr>
{% endif %}
{% endblock %}
</table>
</blockquote>
{% else %}
@ -180,29 +187,23 @@
IETF Document or Other Contribution to Which this IPR Disclosure Relates:
</th>
</tr>
{% if ipr.unbound_form %}
<tr><td class="fixwidth">RFC Number(s) (Numeric value only):</td><td>{{ ipr.rfclist }}</td></tr>
{% else %}
{% block section4_data %}
{% for rfc in ipr.rfcs.all %}
<tr><td class="fixwidth"><b>RFC {{ rfc.rfc_number.rfc_number }}:</b></td><td><b>"{{ rfc.rfc_number.rfc_name }}"</b></td></tr>
{% endfor %}
{% endif %}
<!-- XXX: Omitting code to display information from the rfc_number field of ipr here, as it's always NULL in the database today. -->
{% if ipr.unbound_form %}
<tr><td class="fixwidth">I-D filename(s) (draft-...):</td><td><b>{{ ipr.draftlist }}</b></td></tr>
{% else %}
<!-- XXX: Omitting code to display information from the rfc_number field of ipr here, as it's always NULL in the database today. -->
{% for draft in ipr.drafts.all %}
<tr><td class="fixwidth">Internet-Draft:</td><td><b>"{{ draft.document.id_document_name }}"<br />(<tt><big>{{ draft.document.filename }}-{{ draft.document.revision }}</big></tt>)</b></td></tr>
{% endfor %}
{% endif %}
{% if ipr.unbound_form or ipr.other_designations %}
{% if ipr.other_designations %}
<tr><td class="fixwidth">Designations for Other Contributions:</td><td><b>{{ ipr.other_designations }}</b></td></tr>
{% endif %}
{% endif %}
{% endblock %}
</table>
</blockquote>
{% endblock %}
{% if ipr.unbound_form or not ipr.old_ipr_url %}
{% if not ipr.is_bound or not ipr.old_ipr_url %}
{% block section5 %}
<blockquote class="{% cycle parity %}">
@ -214,34 +215,24 @@
applications required to be disclosed by Section 6 of RFC 3979)
</th>
</tr>
{% if ipr.unbound_form or ipr.p_applications or ipr.p_notes %}
<tr>
<td colspan="2"><i>
A. For granted patents or published pending patent applications,
please provide the following information:</i></td>
</tr>
<tr><td>Patent, Serial, Publication, Registration,
or Application/File number(s):</td><td><b>{{ ipr.p_applications }}</b></td></tr>
<tr><td>Date(s) granted or applied for: </td><td><b>{{ ipr.date_applied }}</b></td></tr>
<tr><td>Country: </td><td><b>{{ ipr.country }}</b></td></tr>
{% if ipr.unbound_form %}
<tr><td>Additional Notes: </td><td><b>{{ ipr.p_notes }}</b></td></tr>
{% else %}
<tr><td>Additional Notes: </td><td><b>{{ ipr.p_notes|escape|linebreaks }}</b></td></tr>
{% endif %}
<tr>
<td colspan="2"><i>
B. Does this disclosure relate to an unpublished pending patent
application?: </i>
<b>{{ ipr.get_selecttype_display }}</b>
</tr>
{% if ipr.unbound_form %}
<tr><td></td>
<td>
{{ ipr.selecttype }}
</td>
</tr>
{% endif %}
{% block section5_data %}
{% if ipr.p_applications or ipr.p_notes %}
<tr>
<td colspan="2"><i>
A. For granted patents or published pending patent applications,
please provide the following information:</i></td>
</tr>
<tr><td>Patent, Serial, Publication, Registration,
or Application/File number(s):</td><td><b>{{ ipr.p_applications }}</b></td></tr>
<tr><td>Date(s) granted or applied for: </td><td><b>{{ ipr.date_applied }}</b></td></tr>
<tr><td>Country: </td><td><b>{{ ipr.country }}</b></td></tr>
<tr><td>Additional Notes: </td><td><b>{{ ipr.p_notes|escape|linebreaks }}</b></td></tr>
<tr>
<td colspan="2"><i>
B. Does this disclosure relate to an unpublished pending patent
application?: </i>
<b>{{ ipr.get_selecttype_display }}</b>
</tr>
{% block clause5c %}
<tr>
<td colspan="2"><i>
@ -253,19 +244,16 @@
covered:</i>
</td>
</tr>
{% if ipr.unbound_form %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.discloser_identify }}</b></td></tr>
{% if ipr.discloser_identify %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.discloser_identify|escape|linebreaks }}</b></td></tr>
{% else %}
{% if ipr.discloser_identify %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.discloser_identify|escape|linebreaks }}</b></td></tr>
{% else %}
<tr><td class="fixwidth"> </td><td><i>No information submitted</i></td></tr>
{% endif %}
<tr><td class="fixwidth"> </td><td><i>No information submitted</i></td></tr>
{% endif %}
{% endblock %}
{% else %}
<tr><td class="fixwidth"></td><td><b>This disclosure relates to an unpublished pending patent application.</b></td></tr>
{% endif %}
{% endblock %}
</table>
</blockquote>
{% endblock %}
@ -290,18 +278,13 @@
specification, is as follows(select one licensing declaration option only):</i>
</td>
</tr>
{% block section6_data %}
<tr>
<td> </td><td>
{% if ipr.unbound_form %}
{{ ipr.licensing_option }}
{{ ipr.stdonly_license }}
This licensing declaration is limited solely to standards-track IETF documents.
{% else %}
<b>{{ ipr.get_licensing_option_display }}<br/>
{{ ipr.get_lic_opt_a_sub_display }}
{{ ipr.get_lic_opt_b_sub_display }}
{{ ipr.get_lic_opt_c_sub_display }}</b>
{% endif %}
</td>
</tr>
<tr>
@ -309,20 +292,15 @@
<i>Licensing information, comments, notes, or URL for further information:</i>
</td>
</tr>
{% if ipr.unbound_form %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.comments }}</b></td></tr>
{% if ipr.comments %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.comments|escape|linebreaks }}</b></td></tr>
{% else %}
{% if ipr.comments %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.comments|escape|linebreaks }}</b></td></tr>
{% else %}
<tr><td class="fixwidth"> </td><td><i>No information submitted</td></tr>
{% endif %}
<tr><td class="fixwidth"> </td><td><i>No information submitted</i></td></tr>
{% endif %}
{% if ipr.unbound_form or ipr.lic_checkbox %}
{% if ipr.lic_checkbox %}
<tr>
<td colspan="2">
{% 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 @@
</td>
</tr>
{% endif %}
{% endblock %}
<tr>
<td colspan="2">
<b><i>Note: The individual submitting this template represents and warrants
@ -352,7 +331,8 @@
IETF Participant in Section III above)
</th>
</tr>
{% if ipr.unbound_form or ipr.submitter.name %}
{% block section7_data %}
{% if ipr.submitter.name %}
<tr><td class="fixwidth">Name:</td> <td><b>{{ ipr.submitter.name }}</b></td></tr>
<tr><td class="fixwidth">Title:</td> <td><b>{{ ipr.submitter.title }}</b></td></tr>
<tr><td class="fixwidth">Department:</td> <td><b>{{ ipr.submitter.department }}</b></td></tr>
@ -364,6 +344,7 @@
{% else %}
<tr><td colspan="2"><i>No information submitted</td></tr>
{% endif %}
{% endblock %}
</table>
</blockquote>
{% endblock %}
@ -378,19 +359,20 @@
Other Notes:
</th>
</tr>
{% if ipr.unbound_form %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.other_notes }}</b></td></tr>
{% else %}
{% block section8_data %}
{% if ipr.other_notes %}
<tr><td> </td><td><b>{{ ipr.other_notes|escape|linebreaks }}</b></td></tr>
{% else %}
<tr><td colspan="2"><i>No information submitted</i></td></tr>
{% endif %}
{% endif %}
{% endblock %}
</table>
</blockquote>
{% endblock %}
{% endif %}
{{ debug }}
{% block bot_info %}
{% endblock %}
{% endblock %}

View file

@ -21,7 +21,7 @@
<h3>Archives by Year</h3>
<ul>
{% for year in date_list %}
<li><a href="{{ year|date:"Y" }}/">{{ year|date:"Y" }}</a>
<li><a href="/ipr/{{ year|date:"Y" }}/">{{ year|date:"Y" }}</a>
{% endfor %}
</ul>

View file

@ -53,4 +53,18 @@
</p>
</blockquote>
{% endif %}
<form>
{% 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 %}
<center><input type="submit" name="submit" value="Submit"></center>
</form>
{% endblock %}

View file

@ -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