Skip to content

Commit 717868c

Browse files
committed
Rewrote text_to_dict() and dict_to_text() to support unicode without RFC2822 encoding issues. Added initial values in IPR update forms, from the original disclosure, in order to make updates easier. Addresses issue ietf-tools#2413.
- Legacy-Id: 14531
1 parent d7e1d25 commit 717868c

5 files changed

Lines changed: 65 additions & 15 deletions

File tree

ietf/ipr/forms.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
IprLicenseTypeName, IprDisclosureStateName)
1818
from ietf.message.models import Message
1919
from ietf.utils.fields import DatepickerDateField
20+
from ietf.utils.text import dict_to_text
2021

2122
# ----------------------------------------------------------------
2223
# Globals
@@ -178,8 +179,9 @@ def clean(self):
178179
raise forms.ValidationError("A generic IPR disclosure cannot have any patent-specific information, "
179180
"but a patent-specific disclosure must provide full patent information.")
180181

181-
patent_values = [str(v) for v in patent_values if v ] + [ cleaned_data['patent_notes'] ]
182-
cleaned_data['patent_info'] = ('\n'.join(patent_values)).strip()
182+
patent_fields += ['patent_notes']
183+
patent_info = dict([ (k.replace('patent_','').capitalize(), cleaned_data.get(k)) for k in patent_fields if cleaned_data.get(k) ] )
184+
cleaned_data['patent_info'] = dict_to_text(patent_info).strip()
183185
cleaned_data['patent_fields'] = patent_fields
184186

185187
return cleaned_data
@@ -189,7 +191,7 @@ def save(self, *args, **kwargs):
189191
same_as_ii_above = nargs.get('same_as_ii_above')
190192
del nargs['same_as_ii_above']
191193

192-
for k in self.cleaned_data['patent_fields'] + ['patent_fields', 'patent_notes']:
194+
for k in self.cleaned_data['patent_fields'] + ['patent_fields',]:
193195
del nargs[k]
194196

195197
if self.cleaned_data.get('patent_info'):
@@ -261,9 +263,9 @@ def clean(self):
261263
raise forms.ValidationError('Submitter information must be provided in section VII')
262264

263265
patent_fields = [ 'patent_'+k for k in ['number', 'inventor', 'title', 'date', 'notes'] ]
264-
patent_values = [ cleaned_data.get(k) for k in patent_fields ]
265-
patent_values = [ str(v) for v in patent_values if v ]
266-
cleaned_data['patent_info'] = ('\n'.join(patent_values)).strip()
266+
267+
patent_info = dict([ (k.replace('patent_','').capitalize(), cleaned_data.get(k)) for k in patent_fields if cleaned_data.get(k) ] )
268+
cleaned_data['patent_info'] = dict_to_text(patent_info).strip()
267269
cleaned_data['patent_fields'] = patent_fields
268270

269271
return cleaned_data

ietf/ipr/tests.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_get_holders(self):
3939
title="Statement regarding rights Update",
4040
holder_legal_name="Native Martians United",
4141
state_id='pending',
42-
patent_info='US12345',
42+
patent_info='Number: US12345\nTitle: A method of transfering bits\nInventor: A. Nonymous\nDate: 2000-01-01',
4343
holder_contact_name='Update Holder',
4444
holder_contact_email='update_holder@acme.com',
4545
licensing_id='royalty-free',
@@ -383,8 +383,13 @@ def test_new_thirdparty(self):
383383
def test_update(self):
384384
draft = make_test_data()
385385
original_ipr = IprDisclosureBase.objects.get(title='Statement regarding rights')
386-
url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "specific" })
387386

387+
# get
388+
url = urlreverse("ietf.ipr.views.update", kwargs={ "id": original_ipr.id })
389+
r = self.client.get(url)
390+
self.assertContains(r, "Statement regarding rights")
391+
392+
#url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "specific" })
388393
# successful post
389394
empty_outbox()
390395
r = self.client.post(url, {

ietf/ipr/views.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.contrib import messages
88
from django.urls import reverse as urlreverse
99
from django.db.models import Q
10-
from django.forms.models import inlineformset_factory
10+
from django.forms.models import inlineformset_factory, model_to_dict
1111
from django.forms.formsets import formset_factory
1212
from django.http import HttpResponse, Http404, HttpResponseRedirect
1313
from django.shortcuts import render, get_object_or_404, redirect
@@ -30,14 +30,15 @@
3030
RelatedIpr,IprEvent)
3131
from ietf.ipr.utils import (get_genitive, get_ipr_summary,
3232
iprs_from_docs, related_docs)
33+
from ietf.mailtrigger.utils import gather_address_lists
3334
from ietf.message.models import Message
3435
from ietf.message.utils import infer_message
3536
from ietf.name.models import IprLicenseTypeName
3637
from ietf.person.models import Person
3738
from ietf.secr.utils.document import get_rfc_num, is_draft
3839
from ietf.utils.draft_search import normalize_draftname
3940
from ietf.utils.mail import send_mail, send_mail_message
40-
from ietf.mailtrigger.utils import gather_address_lists
41+
from ietf.utils.text import text_to_dict
4142

4243
# ----------------------------------------------------------------
4344
# Globals
@@ -531,7 +532,16 @@ def new(request, type, updates=None):
531532

532533
else:
533534
if updates:
534-
form = ipr_form_mapping[type](initial={'updates':str(updates)})
535+
original = IprDisclosureBase(id=updates).get_child()
536+
initial = model_to_dict(original)
537+
initial.update({'updates':str(updates), })
538+
patent_info = text_to_dict(initial['patent_info'])
539+
if patent_info.keys():
540+
patent_dict = dict([ ('patent_'+k.lower(), v) for k,v in patent_info.items() ])
541+
else:
542+
patent_dict = {'patent_notes': initial['patent_info']}
543+
initial.update(patent_dict)
544+
form = ipr_form_mapping[type](initial=initial)
535545
else:
536546
form = ipr_form_mapping[type]()
537547
disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
@@ -764,8 +774,8 @@ def show(request, id):
764774
'in_force_ipr_rfc': ipr_rfc_number(ipr.time, ipr.is_thirdparty),
765775
'tabs': get_details_tabs(ipr, 'Disclosure'),
766776
'choices_abc': [ i.desc for i in IprLicenseTypeName.objects.filter(slug__in=['no-license', 'royalty-free', 'reasonable', ]) ],
767-
'updates_iprs': ipr.relatedipr_source_set.all(),
768-
'updated_by_iprs': ipr.relatedipr_target_set.filter(source__state="posted")
777+
'updates_iprs': ipr.relatedipr_source_set.all().order_by('source__time'),
778+
'updated_by_iprs': ipr.relatedipr_target_set.filter(source__state="posted").order_by('target__time')
769779
})
770780

771781
def showlist(request):

ietf/utils/test_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def make_test_data():
331331
title="Statement regarding rights",
332332
holder_legal_name="Native Martians United",
333333
state=IprDisclosureStateName.objects.get(slug='posted'),
334-
patent_info='US12345',
334+
patent_info='Number: US12345\nTitle: A method of transfering bits\nInventor: A. Nonymous\nDate: 2000-01-01',
335335
holder_contact_name='George',
336336
holder_contact_email='george@acme.com',
337337
holder_contact_info='14 Main Street\nEarth',

ietf/utils/text.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,37 @@ def decode(raw):
140140
text = raw.decode('latin-1')
141141
#
142142
return text
143-
143+
144+
def text_to_dict(t):
145+
"Converts text with RFC2822-formatted header fields into a dictionary-like object."
146+
# ensure we're handed a unicode parameter
147+
assert isinstance(t, six.text_type)
148+
d = {}
149+
# Return {} for malformed input
150+
if not len(t.lstrip()) == len(t):
151+
return {}
152+
lines = t.splitlines()
153+
items = []
154+
# unfold folded lines
155+
for l in lines:
156+
if l[0].isspace():
157+
if items:
158+
items[-1] += l
159+
else:
160+
return {}
161+
else:
162+
items.append(l)
163+
for i in items:
164+
if re.match('^[A-Za-z0-9-]+: ', i):
165+
k, v = i.split(': ', 1)
166+
d[k] = v
167+
else:
168+
return {}
169+
return d
170+
171+
def dict_to_text(d):
172+
"Convert a dictionary to RFC2822-formatted text"
173+
t = ""
174+
for k, v in d.items():
175+
t += "%s: %s\n" % (k, v)
176+
return t

0 commit comments

Comments
 (0)