| 43 | |
| 44 | 2006-02-24-23:14-ish |
| 45 | |
| 46 | While watching Firefly I've come up with this: |
| 47 | |
| 48 | {{{ |
| 49 | class FormPortField(formfields.TextField): |
| 50 | |
| 51 | requires_data_list = True |
| 52 | |
| 53 | def __init__(self, **kw): |
| 54 | formfields.TextField.__init__(self, **kw) |
| 55 | self.validator_list.append(self.isValidList) |
| 56 | |
| 57 | def isValidList(self, field_data, all_data): |
| 58 | for datum in field_data: |
| 59 | for port in datum.split(','): |
| 60 | if port.lower().strip() != 'icmp': |
| 61 | try: |
| 62 | no, proto = port.split(':') |
| 63 | except ValueError: |
| 64 | raise validators.ValidationError, _("Ports should be specified in the form 'number:protocol'. E.g. '80:tcp'") |
| 65 | try: |
| 66 | if int(no) < 1 or int(no) > 65355: |
| 67 | raise validators.ValidationError, _("Port number must be between 1 and 65355") |
| 68 | except ValueError: |
| 69 | raise validators.ValidationError, _("Port number must be between 1 and 65355") |
| 70 | if proto.lower().strip() not in ['tcp', 'udp']: |
| 71 | raise validators.ValidationError, _("Protocol must be either 'TCP' or 'UDP'") |
| 72 | |
| 73 | def render(self, data): |
| 74 | if data is None: |
| 75 | data = '' |
| 76 | if isinstance(data, unicode): |
| 77 | data = data.encode(DEFAULT_CHARSET) |
| 78 | tmp = [] |
| 79 | for datum in data: |
| 80 | try: |
| 81 | port = ports.get_object(id__exact=int(datum)) |
| 82 | if port.number: |
| 83 | tmp.append("%s:%s" % (port.number, port.protocol)) |
| 84 | else: |
| 85 | tmp.append("%s" % (port.protocol, )) |
| 86 | except ValueError: |
| 87 | # By catching this error we now assume that it's invalid data entered by the user and |
| 88 | # so should simply be returned in the 'raw' |
| 89 | return '<input type="text" id="%s" class="v%s%s" name="%s" size="%s" value="%s" />' % \ |
| 90 | (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', |
| 91 | data = ', '.join(tmp) |
| 92 | return '<input type="text" id="%s" class="v%s%s" name="%s" size="%s" value="%s" />' % \ |
| 93 | (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', |
| 94 | self.field_name, 40, escape(data)) |
| 95 | |
| 96 | def convert_post_data(self, new_data): |
| 97 | name = self.get_member_name() |
| 98 | if new_data.has_key(self.field_name): |
| 99 | d = new_data.getlist(self.field_name) |
| 100 | try: |
| 101 | self.isValidList(d, new_data) |
| 102 | except validators.ValidationError: |
| 103 | return |
| 104 | portlist=[] |
| 105 | for datum in d: |
| 106 | for n in datum.split(','): |
| 107 | n = n.strip() |
| 108 | if n: |
| 109 | if n.lower() == 'icmp': |
| 110 | portlist.append(ports.get_object(protocol__exact="icmp").id) |
| 111 | else: |
| 112 | port, proto = n.split(':') |
| 113 | port_ref = ports.get_object(number__exact=int(port), protocol__exact=proto.lower()) |
| 114 | portlist.append(port_ref.id) |
| 115 | new_data.setlist( name, portlist) |
| 116 | }}} |
| 117 | |
| 118 | Wow. What a mess. We end up validating the data three times over. What a pain. But it works. |