* Some code reorganization, moving the large new-disclosure functiality

into view_new.py
 * Added error indication of the top of the page, in case there are any
   errors further down.
 * Set more fields to required, matching the old perl code
 * Various other tweaks.
 - Legacy-Id: 140
This commit is contained in:
Henrik Levkowetz 2007-05-20 23:42:39 +00:00
parent b0f1f5d845
commit 64dc0f83c6
7 changed files with 258 additions and 214 deletions

View file

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

141
ietf/ipr/view_new.py Normal file
View file

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

36
ietf/ipr/view_sections.py Normal file
View file

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

View file

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

View file

@ -4,6 +4,7 @@
{% block content %}
{% include "ipr/style.html" %}
{% include "ipr/js.html" %}
<blockquote style="margin-bottom: 0px;">
{% if section_list.title %}
@ -26,14 +27,14 @@
</font><br>
{% 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.<br>
See the <a href="{{ ipr.old_ipr_url }}">content of the original IPR disclosure</a>.<br>
</font>
{% endif %}
{% if section_list.new_intro %}
<font size="3"> 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.</font><br>
{% endif %}
{% if section_list.new_intro or section_list.legacy_intro %}
@ -105,7 +106,7 @@
{% endif %}
{% if section_list.form_intro %}
<h4 class="ipr">The Patent Disclosure and Licensing Declaration Template for {{ ipr.disclosure_type }} IPR Disclosures</h4>
<h4 class="ipr">The Patent Disclosure and Licensing Declaration Template for {{ section_list.disclosure_type }} IPR Disclosures</h4>
<p class="ipr">
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.
</p>
{% if section_list.also_specific %}
<p class="ipr">
Note: According to Section 6.4.3 of<a
href="http://www.ietf.org/rfc/rfc3979.txt?number=3979"> RFC
3979</a>, "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.
</p>
{% endif %}
{% if section_list.per_rfc_disclosure %}
<p class="ipr">
Please complete and submit a
separate template for each IETF document or contribution to which the
disclosed patent information relates.
</p>
{% endif %}
<p class="ipr">
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 <a
href="http://www.ietf.org/rfc/rfc3979.txt?number=3979">RFC 3979</a>,
"Intellectual Property Rights in IETF Technology," will be posted, but
will be marked as "non-compliant."
will be marked as "non-compliant".
</p>
<hr />
@ -135,17 +155,15 @@
{% if ipr.errors %}
<table border="0" cellpadding="0" cellspacing="0" class="ipr">
{% for error in ipr.errors %}
<tr>
<td colspan="2">
<ul class="errorlist">
<li>{{ error }}</li>
</ul>
</td>
</tr>
{% endfor %}
</table>
<p class="errorlist">
There were errors in the submitted form -- see below. Please correct these and resubmit.
</p>
{% endif %}
{% if section_list.form_legend %}
<p class="formlegend">
Fields marked with <span class="required">*</span> are required.
</p>
{% endif %}
</blockquote>
@ -155,7 +173,7 @@
<tr>
<th colspan=2>
{% cycle I,II,III,IV,V,VI,VII,VIII as section %}.
{% ifequal ipr.disclosure_type "Third Party" %}Possible{% endifequal %}
{% ifequal section_list.disclosure_type "Third Party" %}Possible{% endifequal %}
Patent Holder/Applicant ("Patent Holder")
</th>
</tr>
@ -221,11 +239,11 @@
<table border="0" cellpadding="0" cellspacing="0" class="ipr">
<tr>
<th colspan="2" >
{% if section_list.form_legend %}<span class="required">*</span>{% endif %}
{% cycle section %}.
IETF Document or Other Contribution to Which this IPR Disclosure Relates:
</th>
</tr>
{% 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 %}
@ -236,7 +254,6 @@
{% if ipr.other_designations %}
<tr><td class="fixwidth">Designations for Other Contributions:</td><td><b>{{ ipr.other_designations }}</b></td></tr>
{% endif %}
{% endblock %}
</table>
</blockquote>
{% endif %}
@ -257,7 +274,7 @@
A. For granted patents or published pending patent applications,
please provide the following information:</i></td>
</tr>
<tr><td width="28%">Patent, Serial, Publication, Registration,
<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>

View file

@ -0,0 +1,34 @@
<script type="text/javascript">
function toggle_submitter_info () {
var checked = document.form1.ietf_contact_is_submitter.checked;
if (checked) {
document.form1.subm_name.value = document.form1.ietf_name.value;
document.form1.subm_title.value = document.form1.ietf_title.value;
document.form1.subm_department.value = document.form1.ietf_department.value;
document.form1.subm_telephone.value = document.form1.ietf_telephone.value;
document.form1.subm_fax.value = document.form1.ietf_fax.value;
document.form1.subm_email.value = document.form1.ietf_email.value;
document.form1.subm_address1.value = document.form1.ietf_address1.value;
document.form1.subm_address2.value = document.form1.ietf_address2.value;
} else {
document.form1.subm_name.value = "";
document.form1.subm_title.value = "";
document.form1.subm_department.value = "";
document.form1.subm_telephone.value = "";
document.form1.subm_fax.value = "";
document.form1.subm_email.value = "";
document.form1.subm_address1.value = "";
document.form1.subm_address2.value = "";
}
document.form1.subm_name.disabled = checked;
document.form1.subm_title.disabled = checked;
document.form1.subm_department.disabled = checked;
document.form1.subm_telephone.disabled = checked;
document.form1.subm_fax.disabled = checked;
document.form1.subm_email.disabled = checked;
document.form1.subm_address1.disabled = checked;
document.form1.subm_address2.disabled = checked;
return true;
}
</script>

View file

@ -24,40 +24,7 @@
textarea { width: 72ex; height: 5em; font-family: sans-serif; font-size: 11pt; font-weight: normal; }
.required { color: red; float: right; padding-top: 0.7ex; font-size: 130%; }
.errorlist { background: red; padding: 0 0 0 2px; border: 0px; margin: 0px; }
.formlegend { }
.formlegend .required { float: none; vertical-align: -0.5ex; padding: 0; }
/* baseline | sub | super | top | text-top | middle | bottom | text-bottom | <length> | <percentage> */
</style>
<script type="text/javascript">
function toggle_submitter_info () {
checked = document.form1.ietf_contact_is_submitter.checked;
if (checked) {
document.form1.subm_name.value = document.form1.ietf_name.value;
document.form1.subm_title.value = document.form1.ietf_title.value;
document.form1.subm_department.value = document.form1.ietf_department.value;
document.form1.subm_telephone.value = document.form1.ietf_telephone.value;
document.form1.subm_fax.value = document.form1.ietf_fax.value;
document.form1.subm_email.value = document.form1.ietf_email.value;
document.form1.subm_address1.value = document.form1.ietf_address1.value;
document.form1.subm_address2.value = document.form1.ietf_address2.value;
} else {
document.form1.subm_name.value = "";
document.form1.subm_title.value = "";
document.form1.subm_department.value = "";
document.form1.subm_telephone.value = "";
document.form1.subm_fax.value = "";
document.form1.subm_email.value = "";
document.form1.subm_address1.value = "";
document.form1.subm_address2.value = "";
}
document.form1.subm_name.disabled = checked;
document.form1.subm_title.disabled = checked;
document.form1.subm_department.disabled = checked;
document.form1.subm_telephone.disabled = checked;
document.form1.subm_fax.disabled = checked;
document.form1.subm_email.disabled = checked;
document.form1.subm_address1.disabled = checked;
document.form1.subm_address2.disabled = checked;
return true;
}
</script>