11import datetime
22import email
33
4- from django . utils . safestring import mark_safe
4+
55from django import forms
6+ from django .core .validators import RegexValidator
7+ from django .utils .safestring import mark_safe
8+
9+ import debug # pyflakes:ignore
610
711from ietf .group .models import Group
812from ietf .doc .fields import SearchableDocAliasField
@@ -101,6 +105,31 @@ class Meta:
101105 }
102106 help_texts = { 'sections' : 'Sections' }
103107
108+ validate_patent_number = RegexValidator (
109+ regex = "^(([A-Z][A-Z]\d{6,12}|[A-Z][A-Z]\d{4}(\w{1,2}\d{5,7})?)[, ]*)+$" ,
110+ message = "Please enter one or more patent publication or application numbers as country code and serial number, e.g.: WO2017123456." )
111+
112+ def validate_string (s , letter_min , digit_min , space_min , message ):
113+ letter_count = 0
114+ space_count = 0
115+ digit_count = 0
116+ s = s .strip ()
117+ for c in s :
118+ if c .isalpha ():
119+ letter_count += 1
120+ if c .isspace ():
121+ space_count += 1
122+ if not (letter_count >= letter_min and digit_count >= digit_min and space_count >= space_min ):
123+ raise forms .ValidationError (message )
124+
125+ def validate_name (name ):
126+ return validate_string (name , letter_min = 3 , space_min = 1 , digit_min = 0 ,
127+ message = "This doesn't look like a name. Please enter the actual inventor name." )
128+
129+ def validate_title (title ):
130+ return validate_string (title , letter_min = 15 , space_min = 2 , digit_min = 0 ,
131+ message = "This doesn't look like a patent title. Please enter the actual patent title." )
132+
104133class GenericDisclosureForm (forms .Form ):
105134 """Custom ModelForm-like form to use for new Generic or NonDocSpecific Iprs.
106135 If patent_info is submitted create a NonDocSpecificIprDisclosure object
@@ -114,7 +143,14 @@ class GenericDisclosureForm(forms.Form):
114143 holder_contact_info = forms .CharField (label = "Other Info (address, phone, etc.)" , max_length = 255 ,widget = forms .Textarea ,required = False , strip = False )
115144 submitter_name = forms .CharField (max_length = 255 ,required = False )
116145 submitter_email = forms .EmailField (required = False )
117- patent_info = forms .CharField (max_length = 255 ,widget = forms .Textarea , required = False , help_text = "Patent, Serial, Publication, Registration, or Application/File number(s), Date(s) granted or applied for, Country, and any additional notes." , strip = False )
146+ #patent_info = forms.CharField(max_length=255,widget=forms.Textarea, required=False, help_text="Patent, Serial, Publication, Registration, or Application/File number(s), Date(s) granted or applied for, Country, and any additional notes.", strip=False)
147+ patent_number = forms .CharField (max_length = 127 , required = False , validators = [ validate_patent_number ],
148+ help_text = "Patent publication or application number (2-letter country code followed by serial number)" )
149+ patent_inventor = forms .CharField (max_length = 63 , required = False , validators = [ validate_name ], help_text = "Inventor name" )
150+ patent_title = forms .CharField (max_length = 63 , required = False , validators = [ validate_title ], help_text = "Title of invention" )
151+ patent_date = forms .DateField (required = False , help_text = "Date granted or applied for" )
152+ patent_notes = forms .CharField (max_length = 127 , required = False , widget = forms .Textarea )
153+
118154 has_patent_pending = forms .BooleanField (required = False )
119155 statement = forms .CharField (max_length = 255 ,widget = forms .Textarea ,required = False , strip = False )
120156 updates = SearchableIprDisclosuresField (required = False , help_text = "If this disclosure <strong>updates</strong> other disclosures identify here which ones. Leave this field blank if this disclosure does not update any prior disclosures. <strong>Note</strong>: Updates to IPR disclosures must only be made by authorized representatives of the original submitters. Updates will automatically be forwarded to the current Patent Holder's Contact and to the Submitter of the original IPR disclosure." )
@@ -132,14 +168,30 @@ def clean(self):
132168 if not self .cleaned_data .get ('same_as_ii_above' ):
133169 if not ( self .cleaned_data .get ('submitter_name' ) and self .cleaned_data .get ('submitter_email' ) ):
134170 raise forms .ValidationError ('Submitter information must be provided in section VII' )
135-
171+
172+ patent_fields = [ 'patent_' + k for k in ['number' , 'inventor' , 'title' , 'date' , ] ]
173+ patent_values = [ cleaned_data .get (k ) for k in patent_fields ]
174+ if any (patent_values ) and not all (patent_values ):
175+ for k in patent_fields :
176+ if not cleaned_data .get (k ):
177+ self .add_error (k , "This field is required if you are filing a patent-specific disclosure." )
178+ raise forms .ValidationError ("A generic IPR disclosure cannot have any patent-specific information, "
179+ "but a patent-specific disclosure must provide full patent information." )
180+
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 ()
183+ cleaned_data ['patent_fields' ] = patent_fields
184+
136185 return cleaned_data
137186
138187 def save (self , * args , ** kwargs ):
139188 nargs = self .cleaned_data .copy ()
140189 same_as_ii_above = nargs .get ('same_as_ii_above' )
141190 del nargs ['same_as_ii_above' ]
142191
192+ for k in self .cleaned_data ['patent_fields' ] + ['patent_fields' , 'patent_notes' ]:
193+ del nargs [k ]
194+
143195 if self .cleaned_data .get ('patent_info' ):
144196 obj = NonDocSpecificIprDisclosure (** nargs )
145197 else :
@@ -160,13 +212,20 @@ class IprDisclosureFormBase(forms.ModelForm):
160212 """Base form for Holder and ThirdParty disclosures"""
161213 updates = SearchableIprDisclosuresField (required = False , help_text = mark_safe ("If this disclosure <strong>updates</strong> other disclosures identify here which ones. Leave this field blank if this disclosure does not update any prior disclosures. Note: Updates to IPR disclosures must only be made by authorized representatives of the original submitters. Updates will automatically be forwarded to the current Patent Holder's Contact and to the Submitter of the original IPR disclosure." ))
162214 same_as_ii_above = forms .BooleanField (required = False )
215+ patent_number = forms .CharField (max_length = 127 , required = True , validators = [ validate_patent_number ],
216+ help_text = "Patent publication or application number (2-letter country code followed by serial number)" )
217+ patent_inventor = forms .CharField (max_length = 63 , required = True , validators = [ validate_name ], help_text = "Inventor name" )
218+ patent_title = forms .CharField (max_length = 63 , required = True , validators = [ validate_title ], help_text = "Title of invention" )
219+ patent_date = forms .DateField (required = True , help_text = "Date granted or applied for" )
220+ patent_notes = forms .CharField (max_length = 127 , required = False , widget = forms .Textarea )
163221
164222 def __init__ (self ,* args ,** kwargs ):
165223 super (IprDisclosureFormBase , self ).__init__ (* args ,** kwargs )
166224 self .fields ['submitter_name' ].required = False
167225 self .fields ['submitter_email' ].required = False
168226 self .fields ['compliant' ].initial = True
169227 self .fields ['compliant' ].label = "This disclosure complies with RFC 3979"
228+ patent_fields = [ 'patent_' + k for k in ['number' , 'inventor' , 'title' , 'date' , ] ]
170229 if "ietfer_name" in self .fields :
171230 self .fields ["ietfer_name" ].label = "Name"
172231 if "ietfer_contact_email" in self .fields :
@@ -175,7 +234,10 @@ def __init__(self,*args,**kwargs):
175234 self .fields ["ietfer_contact_info" ].label = "Other info"
176235 self .fields ["ietfer_contact_info" ].help_text = "Address, phone, etc."
177236 if "patent_info" in self .fields :
178- self .fields ["patent_info" ].help_text = "Patent, Serial, Publication, Registration, or Application/File number(s), Date(s) granted or applied for, Country, and any additional notes"
237+ self .fields ['patent_info' ].required = False
238+ else :
239+ for f in patent_fields :
240+ del self .fields [f ]
179241 if "licensing" in self .fields :
180242 self .fields ["licensing_comments" ].label = "Licensing information, comments, notes, or URL for further information"
181243 if "submitter_claims_all_terms_disclosed" in self .fields :
@@ -187,7 +249,7 @@ class Meta:
187249 """This will be overridden"""
188250 model = IprDisclosureBase
189251 fields = '__all__'
190-
252+
191253 def clean (self ):
192254 super (IprDisclosureFormBase , self ).clean ()
193255 cleaned_data = self .cleaned_data
@@ -198,6 +260,12 @@ def clean(self):
198260 if not ( self .cleaned_data .get ('submitter_name' ) and self .cleaned_data .get ('submitter_email' ) ):
199261 raise forms .ValidationError ('Submitter information must be provided in section VII' )
200262
263+ 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 ()
267+ cleaned_data ['patent_fields' ] = patent_fields
268+
201269 return cleaned_data
202270
203271class HolderIprDisclosureForm (IprDisclosureFormBase ):
@@ -220,8 +288,7 @@ def __init__(self, *args, **kwargs):
220288 self .fields ['licensing' ].queryset = IprLicenseTypeName .objects .exclude (slug = 'none-selected' )
221289
222290 def clean (self ):
223- super (HolderIprDisclosureForm , self ).clean ()
224- cleaned_data = self .cleaned_data
291+ cleaned_data = super (HolderIprDisclosureForm , self ).clean ()
225292 if not self .data .get ('iprdocrel_set-0-document' ) and not cleaned_data .get ('other_designations' ):
226293 raise forms .ValidationError ('You need to specify a contribution in Section IV' )
227294 return cleaned_data
@@ -270,8 +337,7 @@ class Meta:
270337 exclude = [ 'by' ,'docs' ,'state' ,'rel' ]
271338
272339 def clean (self ):
273- super (ThirdPartyIprDisclosureForm , self ).clean ()
274- cleaned_data = self .cleaned_data
340+ cleaned_data = super (ThirdPartyIprDisclosureForm , self ).clean ()
275341 if not self .data .get ('iprdocrel_set-0-document' ) and not cleaned_data .get ('other_designations' ):
276342 raise forms .ValidationError ('You need to specify a contribution in Section III' )
277343 return cleaned_data
0 commit comments