def number_extractor(widget, data): val = data.extracted if val is UNSET: return val if widget.attrs.get('datatype') == 'integer': convert = int elif widget.attrs.get('datatype') == 'float': convert = float else: raise ValueError, 'Output datatype must be integer or float' try: val = convert(val) except ValueError: raise ExtractionError(u'Input is not a valid number (%s).' % \ widget.attrs.get('datatype')) if widget.attrs.get('min') and val < widget.attrs.get('min'): raise ExtractionError(u'Value has to be at minimum %s.' % widget.attrs.get('min')) if widget.attrs.get('max') and val > widget.attrs.get('max'): raise ExtractionError(u'Value has to be at maximum %s.' % widget.attrs.get('max')) if widget.attrs.get('step') \ and (val - (widget.attrs.get('min') or 0)) % widget.attrs.get('step'): raise ExtractionError(u'Value has to be in stepping of %s.' % widget.attrs.get('step')) return val
def generic_required_extractor(widget, data): """Validate required. If required is set and some value was extracted, so ``data.extracted`` is not ``UNSET``, then we evaluate ``data.extracted`` to boolean. Raise ``ExtractionError`` if result is ``False``. Properties: ``required`` Define value is required ot not. Either basestring instance or callable returning basestring is expected. ``required_message`` Default required message as basestring instance. """ required = widget.attrs.get('required') if callable(required): required = required(widget, data) if not required \ or bool(data.extracted) \ or data.extracted is UNSET: return data.extracted if isinstance(required, basestring): raise ExtractionError(required) raise ExtractionError(widget.attrs['required_message'])
def test_datetime_without_time_input(self): # Widget without time input widget = factory( 'datetime', name='dt', props={ 'required': 'No date given', }) self.assertEqual(widget(), ( '<input class="dateinput datetime required" id="input-dt" ' 'name="dt" size="10" type="text" value="" />' )) # Widget extraction request = {'dt': ''} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, '', [ExtractionError('No date given')]] ) # Widget renders empty value self.assertEqual(widget(data), ( '<input class="dateinput datetime required" id="input-dt" ' 'name="dt" size="10" type="text" value="" />' )) # Widget extraction with non-date input request = {'dt': 'xyz'} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, 'xyz', [ExtractionError('Not a valid date input.')]] ) self.assertEqual(widget(data), ( '<input class="dateinput datetime required" id="input-dt" ' 'name="dt" size="10" type="text" value="xyz" />' )) # Valid widget extraction. Returns datetime instance request = {'dt': '2010.1.1'} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, datetime.datetime(2010, 1, 1, 0, 0), []] ) self.assertEqual(widget(data), ( '<input class="dateinput datetime required" id="input-dt" ' 'name="dt" size="10" type="text" value="2010.1.1" />' ))
def test_extractor3(widget, data): number = data.request[widget.__name__] try: return int(number) except Exception: raise ExtractionError('e3: Integer expected, got %s' % number) return number
def cron_extractor(widget, data): # instanciate subwidgets widget() # extract subwidgets compound_extractor(widget, data) minute = data['minute'] # if one subwidget is UNSET, whole widget not found on request if minute.extracted is UNSET: return UNSET minute = data['minute'].extracted hour = data['hour'].extracted dom = data['dom'].extracted month = data['month'].extracted dow = data['dow'].extracted year = data['year'].extracted # if all values missing, we have no cron rule if not minute and not hour and not dom \ and not month and not dow and not year: return attr_value('emptyvalue', widget, data, EMPTY_VALUE) # if one value missing, we have an invalid cron rule if not (minute and hour and dom and month and dow and year): raise ExtractionError( _('invalid_cron_rule', default=('Invalid cron rule. You must at least ' 'select one item for each criteria'))) return '{0} {1} {2} {3} {4} {5}'.format(minute, hour, dom, month, dow, year)
def validate_tpl(self, widget, data): if not data.extracted: return data.extracted state, msg = TEMPLATE.validate(data.extracted.decode('utf8')) if not state: raise ExtractionError(msg) return data.extracted
def test_GroupExistsExtractor(self): root = get_root() groups = root['groups'] add_model = BaseNode(parent=groups) extractor = GroupExistsExtractor(add_model) widget = factory( '*exists:text', name='group_id', custom={'exists': {'extractors': [extractor]}} ) # test already exists request = {'group_id': 'group_exists'} data = widget.extract(request=request) self.assertTrue(data.has_errors) self.assertEqual( data.errors, [ExtractionError('group_already_exists')] ) # test not already exists request = {'group_id': 'new_group_id'} data = widget.extract(request=request) self.assertFalse(data.has_errors) self.assertEqual(data.extracted, 'new_group_id')
def test_compound_blueprint_extraction(self): compound = factory('compound', name='COMPOUND') compound['inner'] = factory('text', value='value1') compound['inner2'] = factory('error:text', value='value2', props={'required': True}) # Extract Compound with empty request data = compound.extract({}) self.assertEqual(data.name, 'COMPOUND') self.assertEqual(data.value, UNSET) expected = odict() expected['inner'] = UNSET expected['inner2'] = UNSET self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) inner_data = data['inner'] self.assertEqual(inner_data.name, 'inner') self.assertEqual(inner_data.value, 'value1') self.assertEqual(inner_data.extracted, UNSET) self.assertEqual(inner_data.errors, []) # Extract with a value in request request = { 'COMPOUND.inner': 'newvalue', 'COMPOUND.inner2': '', } data = compound.extract(request) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'value1') self.assertEqual(data_inner.extracted, 'newvalue') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'value2') self.assertEqual(data_inner2.extracted, '') self.assertEqual(data_inner2.errors, [ExtractionError('Mandatory field was empty')]) expected = odict() expected['inner'] = 'newvalue' expected['inner2'] = '' self.assertEqual(data.extracted, expected) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="newvalue"/> <div class="error"> <div class="errormessage">Mandatory field was empty</div> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value=""/> </div> </div> """, fxml('<div>' + compound(data=data) + '</div>'))
def exists(self, widget, data): group_id = data.extracted if group_id is UNSET: return data.extracted if group_id in self.model.__parent__.ldap_groups: msg = "Group %s already exists." % (group_id,) raise ExtractionError(msg) return data.extracted
def login(self, widget, data): login = data.fetch('loginform.user').extracted password = data.fetch('loginform.password').extracted webob_req = data.request.request self.headers = authenticate(webob_req, login, password) if not self.headers: raise ExtractionError( _('invalid_credentials', default='Invalid Credentials'))
def exists(self, widget, data): id = data.extracted if id is UNSET: return data.extracted if id in self.model.__parent__.ldap_users: msg = "User %s already exists." % (id, ) raise ExtractionError(msg) return data.extracted
def from_before_to(self, widget, data): from_date = data.fetch('exportorders.from').extracted to_date = data.fetch('exportorders.to').extracted if to_date <= from_date: raise ExtractionError( _('from_date_before_to_date', default=u'From-date after to-date')) return to_date
def target_not_source(self, widget, data): """Check whether source and target are same. """ source = data.parent.parent.parent['source'].extracted if source == data.extracted: raise ExtractionError( _('localmanager_target_is_source_error', default='Target GID equates source GID')) return data.extracted
def required_if_users_portrait(self, widget, data): extracted = data.extracted if extracted is UNSET: return extracted if data.root['users_portrait'].extracted and not extracted: raise ExtractionError( _('required_if_users_portrait', default='Value is required if portrit support is enabled')) return extracted
def userpassanon_extractor(self, widget, data): if not data.extracted or data["anonymous"].extracted: return data.extracted has_error = False if not data["user"].extracted: error = ExtractionError( _("Username is required for non-anonymous connections.")) data["user"].errors.append(error) has_error = True if not data["password"].extracted and not data["password"].value: error = ExtractionError( _("Password is required for non-anonymous connections.")) data["password"].errors.append(error) has_error = True if has_error: raise ExtractionError( _("User/Password are required if not anonymous.")) return data.extracted
def test_time_extraction(self): widget = factory( 'time', name='t') # Invalid time input data = widget.extract({'t': 'abcdef'}) self.assertEqual( data.errors, [ExtractionError('Not a valid time input.')] ) # Parsing Failure data = widget.extract({'t': 'abc'}) self.assertEqual(data.errors, [ExtractionError('Failed to parse time input.')] ) # Hours not a number data = widget.extract({'t': 'aa00'}) self.assertEqual(data.errors, [ExtractionError('Hours not a number.')] ) # Minutes not a number data = widget.extract({'t': '00:aa'}) self.assertEqual(data.errors, [ExtractionError('Minutes not a number.')] ) # Extract hours and minute without delimiter. Only wotks for # 4-character values. Widget format is ``string`` by default data = widget.extract({'t': '0101'}) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['t', UNSET, '01:01', []] ) # Extract with delimiter data = widget.extract({'t': '1:2'}) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['t', UNSET, '01:02', []] )
def required_if_users_account_expiration(self, widget, data): extracted = data.extracted if extracted is UNSET: return extracted if data.root['users_account_expiration'].extracted and not extracted: raise ExtractionError( _('required_if_users_account_expiration', default='Value is required if account expiration is enabled') ) return extracted
def test_compound_blueprint_structural_children(self): # Compound with structural compound as child value = { 'inner': 'Value 1 from parent', 'inner2': 'Value 2 from parent', } compound = factory('compound', name='COMPOUND', value=value) structural = compound['STRUCTURAL'] = factory( 'compound', props={'structural': True}) structural['inner'] = factory('text') structural['inner2'] = factory('text', props={'required': True}) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="Value 1 from parent"/> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value="Value 2 from parent"/> </div> """, fxml(tag('div', compound()))) self.assertEqual(compound.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: COMPOUND", " <class 'yafowil.base.Widget'>: STRUCTURAL", " <class 'yafowil.base.Widget'>: inner", " <class 'yafowil.base.Widget'>: inner2", "" ]) data = compound.extract({ 'COMPOUND.inner': 'newvalue', 'COMPOUND.inner2': '', }) self.assertEqual(data.name, 'COMPOUND') self.assertEqual(data.value, { 'inner2': 'Value 2 from parent', 'inner': 'Value 1 from parent' }) expected = odict() expected['inner'] = 'newvalue' expected['inner2'] = '' self.assertEqual(data.extracted, expected) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'Value 1 from parent') self.assertEqual(data_inner.extracted, 'newvalue') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'Value 2 from parent') self.assertEqual(data_inner2.extracted, '') self.assertEqual(data_inner2.errors, [ExtractionError('Mandatory field was empty')])
def additional_aliases_extractor(self, widget, data): extracted = data.extracted if extracted is UNSET: return extracted for val in extracted.values(): if not val.strip(): raise ExtractionError(_( 'additional_aliases_empty_string', default='Additional aliases must not be empty' )) return extracted
def __call__(self, widget, data): """Check whether principal with ID already exists and raise extraction error if so. """ principal_id = data.extracted if principal_id is UNSET: return principal_id try: self.model.parent.backend[principal_id] raise ExtractionError(self.error_message(principal_id)) except KeyError: return data.extracted
def test_time_daytime_extraction(self): # Validate day time. triggers if ``daytime`` or ``timepicker`` # set to ``True`` widget = factory( 'time', name='t', value='02:02', props={ 'daytime': True }) data = widget.extract({'t': '25:1'}) self.assertEqual(data.errors, [ExtractionError('Hours must be in range 0..23.')] ) data = widget.extract({'t': '1:61'}) self.assertEqual(data.errors, [ExtractionError('Minutes must be in range 0..59.')] ) widget = factory( 'time', name='t', value='02:02', props={ 'timepicker': True }) data = widget.extract({'t': '26:1'}) self.assertEqual(data.errors, [ExtractionError('Hours must be in range 0..23.')] ) data = widget.extract({'t': '1:62'}) self.assertEqual(data.errors, [ExtractionError('Minutes must be in range 0..59.')] ) # Additional CSS class is rendered for timepicker if ``timepicker`` set self.assertEqual(widget(), ( '<input class="time timeinput timepicker" id="input-t" name="t" ' 'size="5" type="text" value="02:02" />' ))
def datetime_extractor(widget, data): time = None if attr_value('time', widget, data): time = data.request.get('{}.time'.format(widget.dottedpath)) required = attr_value('required', widget, data) if not required and not data.extracted and not time: return '' locale = attr_value('locale', widget, data) tzinfo = attr_value('tzinfo', widget, data) try: return convert(data.extracted, time=time, tzinfo=tzinfo, locale=locale) except DateTimeConversionError: message = _('input_not_valid_date', default=u'Not a valid date input.') raise ExtractionError(message)
def test_extraction(self): # Widget extraction widget = factory('multiselect', name='multi', props={'required': True}) request = {'multi': []} data = widget.extract(request) self.assertEqual(data.errors, [ExtractionError('Mandatory field was empty')]) self.assertEqual(data.extracted, []) request = {'multi': ['1']} data = widget.extract(request) self.assertEqual(data.errors, []) self.assertEqual(data.extracted, ['1'])
def test_extraction_required_value(self): widget = factory('cron', name='cronwidget', props={'required': True}) request = { 'cronwidget.month': '', 'cronwidget.dom': '', 'cronwidget.hour': '', 'cronwidget.minute': '', 'cronwidget.dow': '', 'cronwidget.year': '' } data = widget.extract(request) msg = 'Mandatory field was empty' self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['cronwidget', UNSET, EMPTY_VALUE, [ExtractionError(msg)]])
def test_extraction_invalid_value(self): widget = factory('cron', name='cronwidget') request = { 'cronwidget.month': '*', 'cronwidget.dom': '', 'cronwidget.hour': '', 'cronwidget.minute': '', 'cronwidget.dow': '', 'cronwidget.year': '' } data = widget.extract(request) msg = ('Invalid cron rule. You must at least ' 'select one item for each criteria') self.assertEqual([data.name, data.value, data.extracted, data.errors], ['cronwidget', UNSET, UNSET, [ExtractionError(msg)]])
def test_extract_required(self): widget = factory('select2', name='single', props={'required': True}) request = {} data = widget.extract(request) self.assertEqual(data.extracted, UNSET) request = {'single': ''} data = widget.extract(request) self.assertEqual(data.errors, [ExtractionError('Mandatory field was empty')]) self.assertEqual(data.extracted, '') request = {'single': '1'} data = widget.extract(request) self.assertEqual(data.errors, []) self.assertEqual(data.extracted, '1')
def duplicate_rule(self, widget, data): """Check for duplicate rules. """ source = data.extracted['source'] if not source: return data.extracted exists = [source] for val in data.parent.values(): if val.name == data.name: continue other = val.extracted['source'] if other in exists: raise ExtractionError( _('localmanager_duplicate_rule_error', default='Duplicate access rule')) exists.append(other) return data.extracted
def minlength_extractor(widget, data): """Validate minlength of a string input. Only perform if ``minlength`` property is set. Properties: ``minlength`` Minimum length of string as int. """ val = data.extracted if val is UNSET: return val minlength = widget.attrs.get('minlength', -1) if minlength != -1: if len(val) < minlength: message = u'Input must have at least %i characters.' % minlength raise ExtractionError(message) return val
def __call__(self, widget, data): """Check whether user login name already exists and raise extraction error if so. """ login = generic_extractor(widget, data) if not login: return login res = self.model.parent.backend.search( criteria={self.login_attr: login}) # no entries found with same login attribute set. if not res: return login # unchanged login attribute of current user if len(res) == 1 and res[0] == self.model.name: return login message = _('user_login_not_unique', default='User login ${login} not unique.', mapping={'login': data.extracted}) raise ExtractionError(message)
def ascii_extractor(widget, data): """Validate if a string is ASCII encoding. Only perform if ``ascii`` property evaludates to True. Properties: ``ascii`` Flag ascii check should perform. """ val = data.extracted if val is UNSET: return val if not widget.attrs.get('ascii', False): return val try: str(val) except UnicodeEncodeError: raise ExtractionError(u'Input contains illegal characters.') return val