1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """
25 This module contains wrappers for different parts of data forms (JEP 0004). For
26 information how to use them, read documentation
27 """
28
29 import xmpp
30 import helpers
31
32
33
34 -class Error(Exception): pass
35
37
39
42 @classmethod
44 if 'extend' not in b.keys() or not b['extend']:
45 return object.__new__(cls)
46
47 extend = b['extend']
48 assert issubclass(cls, extend.__class__)
49 extend.__class__ = cls
50 return extend
51
54 ret = f()
55 p = {'doc': f.__doc__}
56 for v in ('fget', 'fset', 'fdel', 'doc'):
57 if v in ret.keys(): p[v]=ret[v]
58 return property(**p)
59
60
61 -def Field(typ, **attrs):
62 ''' Helper function to create a field of given type. '''
63 f = {
64 'boolean': BooleanField,
65 'fixed': StringField,
66 'hidden': StringField,
67 'text-private': StringField,
68 'text-single': StringField,
69 'jid-multi': JidMultiField,
70 'jid-single': JidSingleField,
71 'list-multi': ListMultiField,
72 'list-single': ListSingleField,
73 'text-multi': TextMultiField,
74 }[typ](typ=typ, **attrs)
75 return f
76
78 """
79 Helper function to extend a node to field of appropriate type
80 """
81
82
83
84 typ=node.getAttr('type')
85 f = {
86 'boolean': BooleanField,
87 'fixed': StringField,
88 'hidden': StringField,
89 'text-private': StringField,
90 'text-single': StringField,
91 'jid-multi': JidMultiField,
92 'jid-single': JidSingleField,
93 'list-multi': ListMultiField,
94 'list-single': ListSingleField,
95 'text-multi': TextMultiField,
96 }
97 if typ not in f:
98 typ = 'text-single'
99 return f[typ](extend=node)
100
109
111 """
112 Keeps data about one field - var, field type, labels, instructions... Base
113 class for different kinds of fields. Use Field() function to construct one
114 of these
115 """
116
117 - def __init__(self, typ=None, var=None, value=None, label=None, desc=None,
118 required=False, options=None, extend=None):
133
134 @nested_property
136 """
137 Type of field. Recognized values are: 'boolean', 'fixed', 'hidden',
138 'jid-multi', 'jid-single', 'list-multi', 'list-single', 'text-multi',
139 'text-private', 'text-single'. If you set this to something different,
140 DataField will store given name, but treat all data as text-single
141 """
142 def fget(self):
143 t = self.getAttr('type')
144 if t is None:
145 return 'text-single'
146 return t
147
148 def fset(self, value):
149 assert isinstance(value, basestring)
150 self.setAttr('type', value)
151
152 return locals()
153
154 @nested_property
156 """
157 Field identifier
158 """
159 def fget(self):
160 return self.getAttr('var')
161
162 def fset(self, value):
163 assert isinstance(value, basestring)
164 self.setAttr('var', value)
165
166 def fdel(self):
167 self.delAttr('var')
168
169 return locals()
170
171 @nested_property
173 """
174 Human-readable field name
175 """
176 def fget(self):
177 l = self.getAttr('label')
178 if not l:
179 l = self.var
180 return l
181
182 def fset(self, value):
183 assert isinstance(value, basestring)
184 self.setAttr('label', value)
185
186 def fdel(self):
187 if self.getAttr('label'):
188 self.delAttr('label')
189
190 return locals()
191
192 @nested_property
194 """
195 Human-readable description of field meaning
196 """
197 def fget(self):
198 return self.getTagData('desc') or u''
199
200 def fset(self, value):
201 assert isinstance(value, basestring)
202 if value == '':
203 fdel(self)
204 else:
205 self.setTagData('desc', value)
206
207 def fdel(self):
208 t = self.getTag('desc')
209 if t is not None:
210 self.delChild(t)
211
212 return locals()
213
214 @nested_property
216 """
217 Controls whether this field required to fill. Boolean
218 """
219 def fget(self):
220 return bool(self.getTag('required'))
221
222 def fset(self, value):
223 t = self.getTag('required')
224 if t and not value:
225 self.delChild(t)
226 elif not t and value:
227 self.addChild('required')
228
229 return locals()
230
231 @nested_property
240
241 def fset(self, value):
242 fdel(self)
243 self.addChild(node=value)
244
245 def fdel(self):
246 t = self.getTag('media')
247 if t is not None:
248 self.delChild(t)
249
250 return locals()
251
254
255 -class Uri(xmpp.Node):
258
259 @nested_property
261 """
262 uri type
263 """
264 def fget(self):
265 return self.getAttr('type')
266
267 def fset(self, value):
268 self.setAttr('type', value)
269
270 def fdel(self):
271 self.delAttr('type')
272
273 return locals()
274
275 @nested_property
277 """
278 uri data
279 """
280 def fget(self):
281 return self.getData()
282
283 def fset(self, value):
284 self.setData(value)
285
286 def fdel(self):
287 self.setData(None)
288
289 return locals()
290
307
308 def fdel(self, value):
309 for element in self.getTags('uri'):
310 self.delChild(element)
311
312 return locals()
313
315 @nested_property
317 """
318 Value of field. May contain True, False or None
319 """
320 def fget(self):
321 v = self.getTagData('value')
322 if v in ('0', 'false'):
323 return False
324 if v in ('1', 'true'):
325 return True
326 if v is None:
327 return False
328 raise WrongFieldValue
329
330 def fset(self, value):
331 self.setTagData('value', value and '1' or '0')
332
333 def fdel(self, value):
334 t = self.getTag('value')
335 if t is not None:
336 self.delChild(t)
337
338 return locals()
339
341 """
342 Covers fields of types: fixed, hidden, text-private, text-single
343 """
344
345 @nested_property
347 """
348 Value of field. May be any unicode string
349 """
350 def fget(self):
351 return self.getTagData('value') or u''
352
353 def fset(self, value):
354 assert isinstance(value, basestring)
355 if value == '' and not self.required:
356 return fdel(self)
357 self.setTagData('value', value)
358
359 def fdel(self):
360 try:
361 self.delChild(self.getTag('value'))
362 except ValueError:
363 pass
364
365 return locals()
366
368 """
369 Covers fields of types: jid-multi, jid-single, list-multi, list-single
370 """
371
372 @nested_property
388
389 def fset(self, values):
390 fdel(self)
391 for value, label in values:
392 self.addChild('option', {'label': label}).setTagData('value', value)
393
394 def fdel(self):
395 for element in self.getTags('option'):
396 self.delChild(element)
397
398 return locals()
399
409
411 """
412 Covers list-single field
413 """
414 pass
415
417 """
418 Covers jid-single fields
419 """
430
432 """
433 Covers list-multi fields
434 """
435
436 @nested_property
438 """
439 Values held in field
440 """
441 def fget(self):
442 values = []
443 for element in self.getTags('value'):
444 values.append(element.getData())
445 return values
446
447 def fset(self, values):
448 fdel(self)
449 for value in values:
450 self.addChild('value').setData(value)
451
452 def fdel(self):
453 for element in self.getTags('value'):
454 self.delChild(element)
455
456 return locals()
457
461
463 """
464 Covers jid-multi fields
465 """
477
478 -class TextMultiField(DataField):
479 @nested_property
481 """
482 Value held in field
483 """
484 def fget(self):
485 value = u''
486 for element in self.iterTags('value'):
487 value += '\n' + element.getData()
488 return value[1:]
489
490 def fset(self, value):
491 fdel(self)
492 if value == '':
493 return
494 for line in value.split('\n'):
495 self.addChild('value').setData(line)
496
497 def fdel(self):
498 for element in self.getTags('value'):
499 self.delChild(element)
500
501 return locals()
502
504 """
505 The container for data fields - an xml element which has DataField elements
506 as children
507 """
508 - def __init__(self, fields=None, associated=None, extend=None):
529
530 @nested_property
532 """
533 List of fields in this record
534 """
535 def fget(self):
536 return self.getTags('field')
537
538 def fset(self, fields):
539 fdel(self)
540 for field in fields:
541 if not isinstance(field, DataField):
542 ExtendField(extend=field)
543 self.addChild(node=field)
544
545 def fdel(self):
546 for element in self.getTags('field'):
547 self.delChild(element)
548
549 return locals()
550
552 """
553 Iterate over fields in this record. Do not take associated into account
554 """
555 for field in self.iterTags('field'):
556 yield field
557
559 """
560 Iterate over associated, yielding both our field and associated one
561 together
562 """
563 for field in self.associated.iter_fields():
564 yield self[field.var], field
565
567 return self.vars[item]
568
574
601
602 return locals()
603
604 @nested_property
613
614 def fset(self, title):
615 self.setTagData('title', title)
616
617 def fdel(self):
618 try:
619 self.delChild('title')
620 except ValueError:
621 pass
622
623 return locals()
624
625 @nested_property
638
639 def fset(self, value):
640 fdel(self)
641 if value == '': return
642 for line in value.split('\n'):
643 self.addChild('instructions').setData(line)
644
645 def fdel(self):
646 for value in self.getTags('instructions'):
647 self.delChild(value)
648
649 return locals()
650
682
718
719 def fdel(self):
720 for record in self.getTags('item'):
721 self.delChild(record)
722
723 return locals()
724
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745