def __init__( self, *, payment_modes, empty_label=_("Choisissez votre moyen de paiement"), required=True, initial=None, label=_("Mode de paiement"), **kwargs, ): self._payment_modes = [ PAYMENT_MODES[p] if isinstance(p, str) else p for p in payment_modes ] if required: self.empty_label = None else: self.empty_label = empty_label # bypassing ChoiceField constructor, see ModelChoiceField implementation for reference Field.__init__(self, required=required, label=label, initial=initial, **kwargs) self.widget.choices = self.choices
def __init__(self, querysets, empty_label=_("Send to everyone"), required=True, widget=None, label=None, initial=None, help_text="", limit_choices_to=None, **kwargs): if required and (initial is not None): self.empty_label = None else: self.empty_label = empty_label # Call Field instead of ChoiceField __init__() because we don't need # ChoiceField.__init__(). Field.__init__(self, required=required, widget=widget, label=label, initial=initial, help_text=help_text, **kwargs) self._querysets = querysets
def __init__( self, *, payment_modes=None, empty_label=_("Choisissez votre moyen de paiement"), required=True, initial=None, label=_("Mode de paiement"), **kwargs ): if payment_modes == "ALL": self._payment_modes = settings.PAYMENT_MODES elif payment_modes is None: self._payment_modes = [PAYMENT_MODES["system_pay"], PAYMENT_MODES["check"]] else: self._payment_modes = payment_modes if required: self.empty_label = None else: self.empty_label = empty_label # bypassing ChoiceField constructor, see ModelChoiceField implementation for reference Field.__init__(self, required=required, label=label, initial=initial, **kwargs) self.widget.choices = self.choices
class PersonForm(BaseNestedModelForm): RESOLVE = ( ("", "-------"), ("IGNORE", "Ignore"), ("USE", "Use Existing"), ) check = BooleanField(required=False) resolve = Field(required=False, widget=HiddenInput()) existing = Field(required=False, widget=HiddenInput()) class Meta: model = Person def full_clean(self): self.cleaned_data = {} super(PersonForm, self).full_clean() check = self.cleaned_data.get("check", None) resolve = self.cleaned_data.get("resolve", None) existing = self.cleaned_data.get("existing", None) name = self.cleaned_data.get("name", None) surname = self.cleaned_data.get("surname", None) conflicting = Person.objects.filter(surname=surname).exclude( id=self.instance.id) if conflicting and (check or not self.instance.id): self.fields["resolve"] = ChoiceField(choices=PersonForm.RESOLVE, required=False, label="Resolve") self.fields["existing"] = ModelChoiceField(queryset=conflicting, required=False, label="Existing") msgs = [ u"Conflicting Person:", ] for c in conflicting: msgs.append("%s %s" % (": ".join(c.person_info()), c.identify())) if not resolve: # modify self._update_errors({ "resolve": ["Choose a way to resolve conflict!"], NON_FIELD_ERRORS: msgs, }) elif resolve == "IGNORE": pass elif resolve == "USE": if not existing: self._update_errors({ "existing": ["Choose an existing entry!"], NON_FIELD_ERRORS: msgs, }) else: self.instance.id = existing
def _get_field(self, field_name: T.Text, field: forms.Field) -> interact.PromptLoop: label = self._make_label(field_name, field.label) while True: value = yield self._input_for_field(label, field) try: field.clean(value) except forms.ValidationError as e: for error in walk_errors(e): yield interact.Error(message=error) else: return value
class WorkerForm(ModelForm): date_in = Field(widget=DateInputWidget, label=_('date in')) date_out = Field(widget=DateInputWidget, label=_('date out')) class Meta: model = Worker exclude = ('company',) def __init__(self, *args, **kwargs): super(WorkerForm, self).__init__(*args, **kwargs) _instance = kwargs.pop('instance', None) add_form_control_class(self.fields) self.fields['date_out'].required = False
class ContactForm(Form): locale = CharField(required=False) persone = Field(required=True) organisation = Field(required=False) def __init__(self, *args, **kwargs): super(ContactForm, self).__init__(*args, **kwargs) def clean(self): super(ContactForm, self).clean() data = self.cleaned_data if 'persone' in data: P_F = PersoneForm(data['persone']) if P_F.is_valid(): pass else: if 'address' in P_F.errors: self.add_error('persone', P_F.errors['address']) self.add_error('persone', str(Error(P_F.errors))) if data['organisation'] != None: O_F = OrganisationForm(data['organisation']) if O_F.is_valid(): pass else: self.add_error('organisation', str(Error(O_F.errors))) else: self.add_error('persone', str(Error(['persone']))) def save(self): contact_record = Contact() contact_record.save() if 'address' in self.data['persone']: address_data = self.data['persone'].pop('address') address_record = Address(**address_data) else: address_record = Address() address_record.save() self.data['persone']['address'] = address_record self.data['persone']['contact'] = contact_record persone_record = Person(**self.data['persone']).save() if 'organisation' in self.data: self.data['organisation']['contact'] == contact_record address_data = self.data['organisation'].pop('address') address_record = Address(**address_data) address_record.save() self.data['organisation']['address'] = address_record organisation_record = Organisation(**self.data['organisation']) organisation_record.save() return contact_record
class OrganisationForm(Form): name = Field(required=True) address = Field(required=True) def __init__(self, *args, **kwargs): super(OrganisationForm, self).__init__(*args, **kwargs) def clean(self): super(OrganisationForm, self).clean() data = self.cleaned_data A_F = AddressForm(data['address']) if A_F.is_valid(): pass else: self.add_error('address', str(Error(A_F.errors)))
def formfield_for_dbfield(self, db_field, request, obj=None, **kwargs): field = super().formfield_for_dbfield(db_field, request, **kwargs) if db_field.name == "payment": return Field( widget=PaymentWidget(obj=obj), initial=field.initial, required=False ) return field
class ProposalForm(AjaxModelForm): description = CharField(widget=MarkItUpWidget()) need = CharField(widget=HiddenInput()) contacts = CharField(required=False, widget=ContactsWidget()) tags = Field( widget=TaggitWidget(autocomplete_url="/proposal/search_tags/"), required=False) class Meta: model = Proposal fields = ('title', 'short_description', 'description', 'contacts', 'cost', 'need', 'tags') _field_labels = { 'title': _('Title'), 'description': _('Description'), 'short_description': _('Short description'), 'contacts': _('Contacts'), 'tags': _('Tags'), 'cost': _('Cost'), 'need': ' ' } def __init__(self, *a, **kw): # Crispy forms configuration self.helper = MooHelper(form_id="proposal_form") return super(ProposalForm, self).__init__(*a, **kw) @notify_on_update def save(self, *a, **kw): return super(ProposalForm, self).save(*a, **kw) def clean_need(self): return clean_autocomplete_field(self.cleaned_data['need'], Need)
def get_form(self, form_class=None): form = SectionBasedConfigurationForm( self.request.POST or None, initial={ "sections": global_preferences_registry.manager()["beachguard__sections"] }) form.fields = {"sections": Field(widget=HiddenInput, required=False)} return form
def bind_subform(*, subform: 'TypeSubform', field: Field): """Initializes field attributes thus linking them to a subform. :param subform: :param field: """ field.widget.form = subform field.form = subform
def formfield_for_dbfield(self, db_field, request, **kwargs): """Customise the formfields of event and member""" field = super().formfield_for_dbfield(db_field, request, **kwargs) if db_field.name in ("event", "member"): # Disable add/change/delete buttons field.widget.can_add_related = False field.widget.can_change_related = False field.widget.can_delete_related = False elif db_field.name == "payment": return Field(widget=PaymentWidget, initial=field.initial, required=False) return field
class PersoneForm(Form): firstName = CharField(max_length=150, required=True) lastName = CharField(max_length=150, required=True) email = EmailField(max_length=254, required=True) address = Field(required=False) def __init__(self, *args, **kwargs): super(PersoneForm, self).__init__(*args, **kwargs) def clean(self): super(PersoneForm, self).clean() data = self.cleaned_data if data['address'] != None: A_F = AddressForm(data['address']) if A_F.is_valid(): pass else: self.add_error('address', str(Error(A_F.errors)))
class ChapterForm(ModelForm): """ Форма добавления новой главы к рассказу """ textarea_dict = {'class': 'input-xxlarge chapter-textarea'} attrs_dict = {'class': 'input-xxlarge'} # Название title = CharField( required=True, widget=TextInput(attrs=dict( attrs_dict, maxlength=512, placeholder='Заголовок новой главы')), label='Название', max_length=512, error_messages={ 'required': 'Пожалуйста, назовите новую главу вашего рассказа' }, ) # Текст главы' text = CharField( widget=Textarea( attrs=dict(textarea_dict, placeholder='Текст новой главы')), label='Текст главы', required=False, ) # Заметки к главе notes = CharField( required=False, widget=Textarea(attrs=dict(attrs_dict, rows=4, cols=10, maxlength=4096, placeholder='Заметки к главе')), max_length=4096, label='Заметки', help_text='Заметки автора к главе', ) # Кнопка "Отправить" button_submit = Field( required=False, widget=ServiceButtonWidget(attrs={'class': 'btn btn-primary'}), ) # Метакласс class Meta: model = Chapter fields = ('title', 'text', 'notes')
def test_field_sets_widget_is_required(self): self.assertTrue(Field(required=True).widget.is_required) self.assertFalse(Field(required=False).widget.is_required)
def test_disabled_field_has_changed_always_false(self): disabled_field = Field(disabled=True) self.assertFalse(disabled_field.has_changed("x", "y"))
class MergeEntitiesBaseForm(CremeForm): entities_labels = Field(label='', required=False, widget=EntitiesHeaderWidget) class CanNotMergeError(Exception): pass def __init__(self, entity1, entity2, *args, **kwargs): # super(MergeEntitiesBaseForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs) self.entity1 = entity1 self.entity2 = entity2 user = self.user fields = self.fields build_initial = self._build_initial_dict entity1_initial = build_initial(entity1) entity2_initial = build_initial(entity2) # The older entity is preferred initial_index = 0 if entity1.modified <= entity2.modified else 1 for name, field in fields.items(): if name == 'entities_labels': field.initial = (str(entity1), str(entity2), _(u'Merged entity')) else: initial = [entity1_initial[name], entity2_initial[name]] # We try to initialize with preferred one, but we use the other if it is empty. initial.append(initial[initial_index] or initial[1 - initial_index]) field.initial = initial # Custom fields -------------------------------------------------------- # TODO: factorise (CremeEntityForm ? get_custom_fields_n_values ? ...) cfields = CustomField.objects.filter(content_type=entity1.entity_type) CremeEntity.populate_custom_values([entity1, entity2], cfields) self._customs = customs = [( cfield, entity1.get_custom_value(cfield), entity2.get_custom_value(cfield), ) for cfield in cfields] for i, (cfield, cvalue1, cvalue2) in enumerate(customs): formfield1 = cfield.get_formfield(cvalue1) # fields[_CUSTOM_NAME % i] = merge_field = MergeField(formfield1, fields[_CUSTOM_NAME.format(i)] = merge_field = MergeField( formfield1, model_field=None, label=cfield.name, user=user, ) initial = [ formfield1.initial, cfield.get_formfield(cvalue2).initial, ] initial.append(initial[initial_index] or initial[1 - initial_index]) merge_field.initial = initial def _build_initial_dict(self, entity): return model_to_dict(entity) def _post_entity1_update(self, entity1, entity2, cleaned_data): for i, (custom_field, cvalue1, cvalue2) in enumerate(self._customs): # value = cleaned_data[_CUSTOM_NAME % i] value = cleaned_data[_CUSTOM_NAME.format( i)] # TODO: factorize with __init__() ? CustomFieldValue.save_values_for_entities(custom_field, [entity1], value) if cvalue2 is not None: cvalue2.delete() def clean(self): # cdata = super(MergeEntitiesBaseForm, self).clean() cdata = super().clean() if not self._errors: entity1 = self.entity1 for name in self.fields: try: mfield = entity1._meta.get_field(name) except FieldDoesNotExist: pass else: if not getattr(mfield, 'many_to_many', False): setattr(entity1, name, cdata[name]) entity1.full_clean() return cdata @atomic def save(self, *args, **kwargs): # super(MergeEntitiesBaseForm, self).save(*args, **kwargs) super().save(*args, **kwargs) cdata = self.cleaned_data entity1 = self.entity1 entity2 = self.entity2 entity1.save() self._post_entity1_update(entity1, entity2, cdata) pre_merge_related.send_robust(sender=entity1, other_entity=entity2) replace_related_object(entity2, entity1) # ManyToManyFields for m2m_field in entity1._meta.many_to_many: name = m2m_field.name m2m_data = cdata.get(name) if m2m_data is not None: getattr(entity1, name).set(m2m_data) try: entity2.delete() except Exception as e: logger.error( 'Error when merging 2 entities : the old one "%s"(id=%s) cannot be deleted: %s', entity2, entity2.id, e)
def validate(self, value): return Field.validate(self, value)
def build_type_textfield(self, field): return Field(label=field.name)
class ParametersForm(Form): """Parameters forms.""" parameters = Field(label='Paramaters', required=False, initial={}) input = Field(label='Input', required=False, initial={}) def __init__(self, data=None, script=None, node=None): if script is not None: assert node is not None, "node must be passed with script!" data = { 'parameters': script.parameters, 'input': data, } else: data = {'parameters': data} super().__init__(data=data) self._node = node self._script = script def clean_parameters(self): """Validate the parameters set in the embedded YAML within the script. """ parameters = self.data.get('parameters') if not isinstance(parameters, dict): set_form_error(self, "parameters", "Must be a dictionary") return for param, fields in parameters.items(): # All parameter values should have a type defined. # Only currently supported parameter types are storage and runtime. param_type = fields.get('type') param_min = fields.get('min') param_max = fields.get('max') param_title = fields.get('title') param_description = fields.get('description') param_argument_format = fields.get('argument_format') param_default = fields.get('default') param_required = fields.get('required', True) # Check param data type. if not isinstance(param, str): set_form_error(self, "parameters", "%s: parameter must be a string" % param) # Check fields data types. if not isinstance(param_type, str): set_form_error(self, "parameters", "%s: type must be a string" % param_type) if param_min is not None and not isinstance(param_min, int): set_form_error(self, "parameters", "%s: min must be an integer" % param_min) if param_max is not None and not isinstance(param_max, int): set_form_error(self, "parameters", "%s: max must be an integer" % param_max) if param_title is not None and not isinstance(param_title, str): set_form_error(self, "parameters", "%s: title must be a string" % param_title) if param_description is not None and not isinstance( param_description, str): set_form_error( self, "parameters", "%s: description must be a string" % param_description) if param_argument_format is not None and not isinstance( param_argument_format, str): set_form_error( self, "parameters", "%s: argument_format must be a string" % param_argument_format) if param_default is not None and not isinstance( param_default, str): set_form_error(self, "parameters", "%s: default must be a string" % param_default) if param_required is not None and not isinstance( param_required, bool): set_form_error( self, "parameters", "%s: required must be a boolean" % param_required) # Check parameter type is supported and required. if param_type not in ('storage', 'runtime') and param_required: set_form_error( self, "parameters", "%s: type must be either storage or runtime" % param_type) if param_type == 'storage' and (param_min is not None or param_max is not None): set_form_error(self, "parameters", "storage type doesn't support min or max") if param_type == 'runtime' and isinstance(param_min, int): if param_min < 0: set_form_error( self, "parameters", "runtime minimum must be greater than zero") if isinstance(param_min, int) and isinstance(param_max, int): if param_min > param_max: set_form_error(self, "parameters", "min must be less than max") if isinstance(param_argument_format, str): if param_type == 'storage': if not any(format in param_argument_format for format in ('{input}', '{name}', '{path}', '{model}', '{serial}')): set_form_error( self, "parameters", "%s: argument_format must contain one of {input}, " "{name}, {path}, {model}, {serial}" % param_type) else: if '{input}' not in param_argument_format: set_form_error( self, "parameters", "%s: argument_format must contain {input}" % param_type) return parameters def _setup_input(self): """Split input result and multi_result categories and set defaults. The users may specify multiple storage devices for the storage parameter. This results in one ScriptResult per storage device to allow each storage device to have its own logs and results. Each ScriptResult needs to include values for all parameters. The two lists will be combined later so each ScriptResult has a complete set of parameters. Any parameter which was not defined will have its default value set, if available. """ parameters = self.data.get('parameters', {}) input = self.data.get('input', {}) if not isinstance(input, dict): set_form_error(self, 'input', 'Input must be a dictionary') return {}, {} # Paramaters which map to a single ScriptResult result_params = {} # Paramaters which may require multiple ScriptResults(storage) multi_result_params = {} # Split user input into params which need one ScriptResult per # param and one which may need multiple ScriptResults per param. for param_name, value in input.items(): if param_name not in parameters: set_form_error( self, 'input', "Unknown parameter '%s' for %s" % (param_name, self._script.name)) continue if parameters[param_name]['type'] == 'storage': multi_result_params[param_name] = copy.deepcopy( parameters[param_name]) multi_result_params[param_name]['value'] = value else: result_params[param_name] = copy.deepcopy( parameters[param_name]) result_params[param_name]['value'] = value # Check for any paramaters not given which have defaults. for param_name, param in parameters.items(): if (param['type'] == 'storage' and param_name not in multi_result_params): default = param.get('default', 'all') if not default and param.get('required', True): set_form_error(self, param_name, 'Field is required') elif default: multi_result_params[param_name] = copy.deepcopy(param) multi_result_params[param_name]['value'] = default elif (param['type'] == 'runtime' and param_name not in result_params): default = param.get('default', self._script.timeout.seconds) if (not isinstance(default, int) and param.get('required', True)): set_form_error(self, param_name, 'Field is required') elif isinstance(default, int): result_params[param_name] = copy.deepcopy(param) result_params[param_name]['value'] = default return result_params, multi_result_params def _validate_and_clean_runtime(self, param_name, param): """Validate and clean runtime input.""" value = param['value'] min_value = param.get('min', 0) max_value = param.get('max') if isinstance(value, str) and value.isdigit(): value = int(value) if not isinstance(value, int): set_form_error(self, param_name, 'Must be an int') return if value < min_value: set_form_error(self, param_name, "Must be greater than %s" % min_value) if max_value is not None and value > max_value: set_form_error(self, param_name, "Must be less than %s" % max_value) def _blockdevice_to_dict(self, block_device): """Convert a block device to a dictionary with limited fields.""" return { 'name': block_device.name, 'id_path': block_device.id_path, 'model': block_device.model, 'serial': block_device.serial, 'physical_blockdevice': block_device, } def _validate_and_clean_storage_all(self, param_name, param, result_params, ret): """Validate and clean storage input when set to all.""" if not self._node.physicalblockdevice_set.exists(): # Use 'all' as a place holder until the disks get added during # commissioning. clean_param = copy.deepcopy(result_params) clean_param[param_name] = param ret.append(clean_param) else: for bd in self._node.physicalblockdevice_set: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict( bd) ret.append(clean_param) def _validate_and_clean_storage_id(self, param_name, param, result_params, ret): """Validate and clean storage input when id.""" try: bd = self._node.physicalblockdevice_set.get(id=int(param['value'])) except ObjectDoesNotExist: set_form_error(self, param_name, 'Physical block id does not exist') else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict(bd) ret.append(clean_param) def _validate_and_clean_storage(self, param_name, param, result_params, ret): """Validate and clean storage input.""" value = param['value'] for i in value.split(','): if ':' in i: # Allow users to specify a disk using the model and serial. model, serial = i.split(':') try: bd = self._node.physicalblockdevice_set.get(model=model, serial=serial) except ObjectDoesNotExist: pass else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name][ 'value'] = self._blockdevice_to_dict(bd) ret.append(clean_param) continue qs = self._node.physicalblockdevice_set.filter( Q(name=i) | Q(name=os.path.basename(i)) | Q(model=i) | Q(serial=i) | Q(tags__overlap=[i])) if not qs.exists(): set_form_error( self, param_name, "Unknown storage device for %s(%s)" % (self._node.fqdn, self._node.system_id)) continue for bd in qs: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict( bd) ret.append(clean_param) def clean_input(self): """Validate and clean parameter input. Validate that input is correct per the parameter description. Storage input will be transformed into a dictionary representing the selected storage device from the PhysicalBlockDevice type. input will be cleaned to be a list of parameter dicts. Each item in the list represents one set of parameters for the script. This allows each storage device to be run seperately. """ ret = [] # Only validating the parameter description, not input. Do nothing. if None in (self._script, self._node): return ret result_params, multi_result_params = self._setup_input() # Validate input for single ScriptResult params for param_name, param in result_params.items(): if param['type'] == 'runtime': self._validate_and_clean_runtime(param_name, param) # Validate input for multi ScriptResult params for param_name, param in multi_result_params.items(): value = param['value'] if param['type'] == 'storage': if value == 'all': self._validate_and_clean_storage_all( param_name, param, result_params, ret) elif isinstance(value, int) or value.isdigit(): self._validate_and_clean_storage_id( param_name, param, result_params, ret) else: self._validate_and_clean_storage(param_name, param, result_params, ret) if ret == []: return [result_params] else: return ret
def test_disabled_field_has_changed_always_false(self): disabled_field = Field(disabled=True) self.assertFalse(disabled_field.has_changed('x', 'y'))
class BGFinProdRegForm(Form): issuer_full_name = CharField(required=False) issuer_short_name = CharField(required=False) issuer_legal_address = CharField(required=False) issuer_ogrn = CharField(required=False) issuer_inn = CharField(required=False) issuer_kpp = CharField(required=False) tender_gos_number = CharField(required=False) tender_placement_type = CharField(required=False) tender_exec_law = ChoiceField( required=False, choices=[ (consts.TENDER_EXEC_LAW_44_FZ, '44-ФЗ'), (consts.TENDER_EXEC_LAW_223_FZ, '223-ФЗ'), (consts.TENDER_EXEC_LAW_185_FZ, '185-ФЗ'), (consts.TENDER_EXEC_LAW_COMMERCIAL, 'Коммерческий'), (consts.TENDER_EXEC_LAW_CUSTOMS, 'Таможенная'), (consts.TENDER_EXEC_LAW_VAT, 'Возврат НДС'), ]) tender_publish_date = DateField(required=False) tender_start_cost = DecimalField(decimal_places=2, required=False, localize=True) tender_final_cost = DecimalField(decimal_places=2, required=False, localize=True) tender_responsible_full_name = CharField(required=False) tender_responsible_legal_address = CharField(required=False) tender_responsible_inn = CharField(required=False) tender_responsible_kpp = CharField(required=False) tender_responsible_ogrn = CharField(required=False) bg_commercial_contract_subject = CharField(required=False) bg_commercial_contract_place_of_work = CharField(required=False) bg_commercial_contract_sum = DecimalField(decimal_places=2, required=False, localize=True) bg_commercial_contract_sign_date = DateField(required=False) bg_commercial_contract_end_date = DateField(required=False) balance_code_2400_offset_1 = BalanceCodeDecimalField(decimal_places=2, required=False, localize=True) balance_code_2400_offset_0 = BalanceCodeDecimalField(decimal_places=2, required=False, localize=True) bg_sum = DecimalForcedThousandsGroupedField(decimal_places=2, required=False, localize=True) bg_currency = ChoiceField(required=False, choices=[ (consts.CURRENCY_RUR, 'Рубль'), (consts.CURRENCY_USD, 'Доллар'), (consts.CURRENCY_EUR, 'Евро'), ]) bg_start_date = DateField(required=False) bg_end_date = DateField(required=False) bg_deadline_date = DateField(required=False) bg_type = ChoiceField( required=False, choices=[ (consts.BG_TYPE_APPLICATION_ENSURE, 'Обеспечение заявки'), (consts.BG_TYPE_CONTRACT_EXECUTION, 'Исполнение контракта'), (consts.BG_TYPE_REFUND_OF_ADVANCE, 'Возврат аванса'), (consts.BG_TYPE_WARRANTY_ENSURE, 'Обеспечение гарантийных обязательств'), ]) bg_is_benefeciary_form = BooleanField(required=False, widget=Select( attrs={'class': 'form-control'}, choices=[ (True, 'Да'), (False, 'Нет'), ])) is_indisputable_charge_off = BooleanField( required=False, initial=True, widget=Select(attrs={'class': 'form-control'})) tender_contract_type = ChoiceField( required=False, choices=[ (consts.TENDER_CONTRACT_TYPE_SUPPLY_CONTRACT, 'Поставка товара'), (consts.TENDER_CONTRACT_TYPE_SERVICE_CONTRACT, 'Оказание услуг'), (consts.TENDER_CONTRACT_TYPE_WORKS_CONTRACT, 'Выполнение работ'), ]) tender_contract_subject = CharField(widget=Textarea(), required=False) stop_factors = Field(required=False) tender_has_prepayment = BooleanField(required=False) already_has_an_agent = Field(required=False) def clean(self): bg_sum_min = BankMinimalCommission.objects.order_by( 'sum_min').first().sum_min bg_sum_max = BankMinimalCommission.objects.order_by( '-sum_max').first().sum_max if not self.cleaned_data[ 'bg_sum'] or not bg_sum_min < self.cleaned_data[ 'bg_sum'] < bg_sum_max: self.add_error(None, 'Неверная сумма запрашиваемой гарантии') bg_start = self.cleaned_data['bg_start_date'] bg_end = self.cleaned_data['bg_end_date'] if bg_end and bg_start: bg_months_diff = 1 + (bg_end.year - bg_start.year ) * 12 + bg_end.month - bg_start.month else: bg_months_diff = 0 if not bg_start or not bg_end or not 0 < bg_months_diff < 30: self.add_error(None, 'Неверный срок действия запрашиваемой гарантии') balance_code_2400_offset_0 = self.cleaned_data[ 'balance_code_2400_offset_0'] balance_code_2400_offset_1 = self.cleaned_data[ 'balance_code_2400_offset_1'] if balance_code_2400_offset_0 < 0 or balance_code_2400_offset_1 < 0: self.add_error(None, 'Отрицательная прибыль')
def build_type_integerfield(self, field): return Field(label=field.name)
class StoryForm(ModelForm): attrs_dict = {'class': 'input-xxlarge'} img_attrs = { 'group_container_class': 'characters-group group-', 'data_attrs': { 'class': 'hidden' }, 'container_attrs': { 'class': 'character-item' } } radio_attrs = { 'btn_attrs': { 'type': 'button', 'class': 'btn' }, 'data_attrs': { 'class': 'hidden' }, 'btn_container_attrs': { 'class': 'btn-group buttons-visible', 'data-toggle': 'buttons-radio' }, 'data_container_attrs': { 'class': 'buttons-data' }, } checkbox_attrs = { 'btn_attrs': { 'type': 'button', 'class': 'btn' }, 'data_attrs': { 'class': 'hidden' }, 'btn_container_attrs': { 'class': 'btn-group buttons-visible', 'data-toggle': 'buttons-checkbox' }, 'data_container_attrs': { 'class': 'buttons-data' }, } # Персонажи characters = GroupedModelChoiceField( required=False, queryset=Character.objects.all(), group_by_field='group', widget=StoriesImgSelect(attrs=img_attrs), label='Персонажи', help_text= 'Следует выбрать персонажей, находящихся в гуще событий, а не всех пони, упомянутых в произведении.', ) # Жанры categories = ModelMultipleChoiceField( required=True, queryset=Category.objects.all(), widget=StoriesCheckboxSelectMultiple( attrs={ 'label_attrs': ['checkbox', 'inline', 'gen'], 'label_id_related_attr': 'gen-' }), label='Жанры', help_text='Выберите жанр вашего рассказа', error_messages={'required': 'Жанры - обязательное поле'}) # События classifications = ModelMultipleChoiceField( required=False, queryset=Classifier.objects.all(), widget=StoriesCheckboxSelectMultiple( attrs={'label_attrs': ['checkbox', 'inline']}), label='События', help_text='Ключевые события рассказа', ) # Закончен/не закончен finished = ChoiceField( required=True, choices=[(0, 'Не закончен'), (1, 'Закончен')], widget=StoriesRadioButtons(attrs=radio_attrs), label='Статус', help_text='Завершен ли рассказ', error_messages={ 'required': 'Нужно обязательно указать статус рассказа!' }, ) # Заморожен/активен freezed = ChoiceField( required=True, choices=[(0, 'Активен'), (1, 'Заморожен')], widget=StoriesRadioButtons(attrs=radio_attrs), label='Состояние', help_text='Активность рассказа (пишется ли он сейчас)', error_messages={ 'required': 'Нужно обязательно указать состояние рассказа!' }, ) # Оригинал/перевод original = ChoiceField( required=True, choices=[(1, 'Оригинал'), (0, 'Перевод')], widget=StoriesRadioButtons(attrs=radio_attrs), label='Происхождение', error_messages={ 'required': 'Нужно обязательно указать происхождение рассказа!' }, ) # Рейтинг rating = ModelChoiceField( required=True, empty_label=None, queryset=Rating.objects.order_by('-id'), widget=StoriesRadioButtons(attrs=radio_attrs), label='Рейтинг', error_messages={ 'required': 'Нужно обязательно указать рейтинг рассказа!' }, ) # Краткое описание рассказа summary = CharField( required=True, widget=Textarea( attrs=dict(attrs_dict, maxlength=4096, placeholder='Обязательное краткое описание рассказа')), max_length=4096, label='Краткое описание рассказа', error_messages={ 'required': 'Опишите вкратце содержание рассказа - это обязательное поле' }, ) # Заметки к рассказу notes = CharField( required=False, widget=Textarea(attrs=dict( attrs_dict, maxlength=4096, placeholder='Заметки к рассказу')), max_length=4096, label='Заметки', ) # Название title = CharField( required=True, widget=TextInput(attrs=dict(attrs_dict, maxlength=512, placeholder='Заголовок нового рассказа')), label='Название', max_length=512, error_messages={'required': 'Пожалуйста, назовите ваш рассказ'}, ) # Кнопка "Сохранить" button_submit = Field( required=False, widget=ServiceButtonWidget(attrs={'class': 'btn btn-primary'}), initial='Сохранить') # Метакласс class Meta: model = Story fields = ('characters', 'categories', 'classifications', 'finished', 'freezed', 'original', 'rating', 'summary', 'notes', 'title')
class ReservationForm(BaseNestedModelForm): RESOLVE = ( ("", "-------"), ("FORCE", "Force save"), ("SWAP", "Swap Appartments"), ) resolve = Field(label="Resolve", required=False, widget=HiddenInput()) period = ModelChoiceField(queryset=Period.objects.all(), required=False, label="Period") def __init__(self, *args, **kwargs): super(ReservationForm, self).__init__(*args, **kwargs) self.fields[ "owner"].queryset = MilitaryPerson.objects.prefetch_related( "rank").all().order_by("surname", "name") class Meta: model = Reservation fields = [ "res_type", "agent", "period", "check_in", "check_out", "owner", "appartment", "status", "persons", "book_ref", "telephone" ] def clean(self): super(ReservationForm, self).clean() def get_datetime(value): if value: y, m, d = map(int, value.split("-")) return datetime.date(y, m, d) period = self.cleaned_data.get("period", None) check_in = self.cleaned_data.get("check_in", None) check_out = self.cleaned_data.get("check_out", None) if period and (check_in or check_out): self._update_errors({ "period": ["You must provide either period or dates!"], }) if period: self.cleaned_data["check_in"] = period.start self.cleaned_data["check_out"] = period.end return self.cleaned_data def full_clean(self): self.cleaned_data = {} super(ReservationForm, self).full_clean() if self.instance.appartment: reservations = self.instance.appartment.reservations.filter( status__in=[RS_PENDING, RS_CONFIRM, RS_UNKNOWN]).exclude( id=self.instance.id) conflicting = [] for r in reservations: if (self.instance.status in (RS_PENDING, RS_CONFIRM, RS_UNKNOWN) and r.owner.id != self.instance.owner.id and r.inside( self.instance.check_in, self.instance.check_out)): conflicting.append(r) if conflicting: self.fields["resolve"] = ChoiceField( choices=ReservationForm.RESOLVE, required=False, label="Resolve") resolve = self.cleaned_data.get("resolve", None) print "resolving...." msgs = [ u"Conflicting Reservations:", ] if not resolve: self._update_errors({ "resolve": ["Choose a way to resolve conflict!"], NON_FIELD_ERRORS: msgs + [r.info for r in conflicting], }) if resolve == "FORCE": pass if resolve == "SWAP": if len(conflicting) > 1: self._update_errors({ "resolve": ["Swap is not supported for many conflicts!"], NON_FIELD_ERRORS: msgs + [r.info for r in conflicting], }) else: # TODO: find first available appartment appartment = None if self.instance.id: existing = Reservation.objects.get( id=self.instance.id) appartment = existing.appartment conflicting[0].appartment = appartment conflicting[0].save() msg = ( u"Conflicting Reservations:\n%s\nRESOLVE: %s\nChanged: %s\nNew/Updated: %s" % ("\n".join([c.info for c in conflicting]), resolve, conflicting[0].info, self.instance.info)) print msg.encode("utf-8")
def validate(self, value): if value == '-': return '-' return Field.validate(self, value)
class ParametersForm(Form): """Parameters forms.""" parameters = Field(label="Paramaters", required=False, initial={}) input = Field(label="Input", required=False, initial={}) def __init__(self, data=None, script=None, node=None): if script is not None: assert node is not None, "node must be passed with script!" data = {"parameters": script.parameters, "input": data} else: data = {"parameters": data} super().__init__(data=data) self._node = node self._script = script def _get_interfaces(self, *args, **kwargs): """Return a list of configured interfaces.""" ifaces = [ interface for interface in self._node.interface_set.filter( children_relationships=None, enabled=True, *args, **kwargs ).prefetch_related("ip_addresses") if interface.is_configured() ] if ( not ifaces and self._node.status == NODE_STATUS.COMMISSIONING and self._node.boot_interface ): # During commissioning no interface will have a configured IP # address if network information wasn't kept. The netplan # configuration will use DHCP on the boot_interface. Allow it # to be selected for a ScriptResult during commissioning so # regeneration works. ifaces = [self._node.boot_interface] return ifaces def clean_parameters(self): """Validate the parameters set in the embedded YAML within the script.""" parameters = self.data.get("parameters") if not isinstance(parameters, dict): set_form_error(self, "parameters", "Must be a dictionary") return for param, fields in parameters.items(): # All parameter values should have a type defined. # Only currently supported parameter types are storage and runtime. param_type = fields.get("type") param_min = fields.get("min") param_max = fields.get("max") param_title = fields.get("title") param_description = fields.get("description") param_argument_format = fields.get("argument_format") param_default = fields.get("default") param_required = fields.get("required", True) allow_list = fields.get("allow_list") choices = fields.get("choices") # Check param data type. if not isinstance(param, str): set_form_error( self, "parameters", "%s: parameter must be a string" % param, ) # Check fields data types. if not isinstance(param_type, str): set_form_error( self, "parameters", "%s: type must be a string" % param_type, ) if param_min is not None and not isinstance(param_min, int): set_form_error( self, "parameters", "%s: min must be an integer" % param_min, ) if param_max is not None and not isinstance(param_max, int): set_form_error( self, "parameters", "%s: max must be an integer" % param_max, ) if param_title is not None and not isinstance(param_title, str): set_form_error( self, "parameters", "%s: title must be a string" % param_title, ) if param_description is not None and not isinstance( param_description, str ): set_form_error( self, "parameters", "%s: description must be a string" % param_description, ) if param_argument_format is not None and not isinstance( param_argument_format, str ): set_form_error( self, "parameters", "%s: argument_format must be a string" % param_argument_format, ) if param_default is not None and not isinstance( param_default, str ): set_form_error( self, "parameters", "%s: default must be a string" % param_default, ) if param_required is not None and not isinstance( param_required, bool ): set_form_error( self, "parameters", "%s: required must be a boolean" % param_required, ) if allow_list is not None and not isinstance(allow_list, bool): set_form_error( self, "parameters", "%s: allow_list must be a boolean" % allow_list, ) if allow_list is not None and param_type != "url": set_form_error( self, "parameters", "allow_list only supported with the url type.", ) if choices is not None: if not isinstance(choices, list): set_form_error( self, "parameters", "choices must be a list", ) else: for choice in choices: if isinstance(choice, list) and not isinstance( choice, str ): if ( len(choice) != 2 or (not isinstance(choice[0], str)) or (not isinstance(choice[1], str)) ): set_form_error( self, "parameters", "choice must be a Django choice or string", ) if choices is not None and param_type != "choice": set_form_error( self, "parameters", "choices only supported with the choice type.", ) if param_type == "choice" and not choices: set_form_error( self, "parameters", 'choices must be given with a "choice" parameter type!', ) # Check parameter type is supported and required. if ( param_type not in ( "storage", "interface", "url", "runtime", "string", "password", "choice", ) and param_required ): set_form_error( self, "parameters", "%s: type must be either storage, interface, url, " "runtime, string, password, or choice" % param_type, ) if param_type in ("storage", "interface", "url", "choice") and ( param_min is not None or param_max is not None ): set_form_error( self, "parameters", "Type doesn't support min or max" ) if param_type == "runtime" and isinstance(param_min, int): if param_min < 0: set_form_error( self, "parameters", "runtime minimum must be greater than zero", ) if isinstance(param_min, int) and isinstance(param_max, int): if param_min > param_max: set_form_error( self, "parameters", "min must be less than max" ) if isinstance(param_argument_format, str): if param_type == "storage": if not any( format in param_argument_format for format in ( "{input}", "{name}", "{path}", "{model}", "{serial}", ) ): set_form_error( self, "parameters", "%s: argument_format must contain one of {input}, " "{name}, {path}, {model}, {serial}" % param_type, ) elif param_type == "interface": if not any( format in param_argument_format for format in ( "{input}", "{name}", "{mac}", "{vendor}", "{product}", ) ): set_form_error( self, "parameters", "%s: argument_format must contain one of {input}, " "{name}, {mac}, {vendor}, {product}" % param_type, ) else: if "{input}" not in param_argument_format: set_form_error( self, "parameters", "%s: argument_format must contain {input}" % param_type, ) return parameters def _setup_input(self): """Split input result and multi_result categories and set defaults. Users may specify multiple devices for the storage and interface parameters. This results in one ScriptResult per device to allow each each device to have its own logs and results. Each ScriptResult needs to include values for all parameters. The two lists will be combined later so each ScriptResult has a complete set of parameters. Any parameter which was not defined will have its default value set, if available. """ parameters = self.data.get("parameters", {}) input = self.data.get("input", {}) if not isinstance(input, dict): set_form_error(self, "input", "Input must be a dictionary") return {}, {} # Paramaters which map to a single ScriptResult result_params = {} # Paramaters which may require multiple ScriptResults(storage) multi_result_params = {} default_from_maas_config = DEFAULTS_FROM_MAAS_CONFIG.union( input.keys() ) default_defaults = ( Config.objects.get_configs(default_from_maas_config) if default_from_maas_config else {} ) # Split user input into params which need one ScriptResult per # param and one which may need multiple ScriptResults per param. for param_name, value in input.items(): if param_name not in parameters: set_form_error( self, "input", "Unknown parameter '%s' for %s" % (param_name, self._script.name), ) continue if parameters[param_name]["type"] in ("storage", "interface"): multi_result_params[param_name] = copy.deepcopy( parameters[param_name] ) multi_result_params[param_name]["value"] = value else: result_params[param_name] = copy.deepcopy( parameters[param_name] ) result_params[param_name]["value"] = value # Check for any paramaters not given which have defaults. for param_name, param in parameters.items(): if ( param["type"] in ("storage", "interface") and param_name not in multi_result_params ): default = param.get("default", "all") if not default and param.get("required", True): set_form_error(self, param_name, "Field is required") elif default: multi_result_params[param_name] = copy.deepcopy(param) multi_result_params[param_name]["value"] = default elif param_name not in result_params: if param["type"] == "runtime": default = param.get( "default", self._script.timeout.seconds ) if not isinstance(default, int) and param.get( "required", True ): set_form_error(self, param_name, "Field is required") elif isinstance(default, int): result_params[param_name] = copy.deepcopy(param) result_params[param_name]["value"] = default else: default = param.get( "default", default_defaults.get(param_name, "") ) if not default and param.get("required", False): set_form_error(self, param_name, "Field is required") elif default: result_params[param_name] = copy.deepcopy(param) result_params[param_name]["value"] = default return result_params, multi_result_params def _validate_and_clean_runtime(self, param_name, param): """Validate and clean runtime input.""" value = param["value"] min_value = param.get("min", 0) max_value = param.get("max") if isinstance(value, str) and value.isdigit(): value = int(value) if not isinstance(value, int): set_form_error(self, param_name, "Must be an int") return if value < min_value: set_form_error( self, param_name, "Must be greater than %s" % min_value ) if max_value is not None and value > max_value: set_form_error( self, param_name, "Must be less than %s" % max_value ) def _blockdevice_to_dict(self, block_device): """Convert a block device to a dictionary with limited fields.""" return { "name": block_device.name, "id_path": block_device.id_path, "model": block_device.model, "serial": block_device.serial, "physical_blockdevice": block_device, } def _validate_and_clean_storage_all( self, param_name, param, result_params, ret ): """Validate and clean storage input when set to all.""" if len(self._node.physicalblockdevice_set) == 0: # Use 'all' as a place holder until the disks get added during # commissioning. clean_param = copy.deepcopy(result_params) clean_param[param_name] = param ret.append(clean_param) else: for bd in self._node.physicalblockdevice_set: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._blockdevice_to_dict( bd ) ret.append(clean_param) def _validate_and_clean_storage_id( self, param_name, param, result_params, ret ): """Validate and clean storage input when id.""" try: bd = self._node.physicalblockdevice_set.get(id=int(param["value"])) except ObjectDoesNotExist: set_form_error( self, param_name, "Physical block id does not exist" ) else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._blockdevice_to_dict(bd) ret.append(clean_param) def _validate_and_clean_storage( self, param_name, param, result_params, ret ): """Validate and clean storage input.""" value = param["value"] for i in value.split(","): if ":" in i: # Allow users to specify a disk using the model and serial. model, serial = i.split(":") try: bd = self._node.physicalblockdevice_set.get( model=model, serial=serial ) except ObjectDoesNotExist: pass else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name][ "value" ] = self._blockdevice_to_dict(bd) ret.append(clean_param) continue qs = self._node.physicalblockdevice_set.filter( Q(name=i) | Q(name=os.path.basename(i)) | Q(model=i) | Q(serial=i) | Q(tags__overlap=[i]) ) if len(qs) == 0: set_form_error( self, param_name, "Unknown storage device for %s(%s)" % (self._node.fqdn, self._node.system_id), ) continue for bd in qs: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._blockdevice_to_dict( bd ) ret.append(clean_param) def _interface_to_dict(self, interface): """Convert an interface to a dictionary with limited fields.""" return { "name": interface.name, "mac_address": str(interface.mac_address), "vendor": interface.vendor, "product": interface.product, "interface": interface, } def _validate_and_clean_interface_all( self, param_name, param, result_params, ret ): """Validate and clean interface input when set to all.""" interfaces = self._get_interfaces() if len(interfaces) == 0: # Use 'all' as a place holder until the Interfaces get added during # commissioning. clean_param = copy.deepcopy(result_params) clean_param[param_name] = param ret.append(clean_param) else: for interface in interfaces: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._interface_to_dict( interface ) ret.append(clean_param) def _validate_and_clean_interface_id( self, param_name, param, result_params, ret ): """Validate and clean interface input when id.""" interfaces = self._get_interfaces(id=int(param["value"])) if len(interfaces) != 1: set_form_error(self, param_name, "Interface id does not exist") else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._interface_to_dict( interfaces[0] ) ret.append(clean_param) def _validate_and_clean_interface( self, param_name, param, result_params, ret ): """Validate and clean interface input.""" value = param["value"] for i in value.split(","): if ":" in i: # Allow users to specify an Interface using the vendor and # product. vendor, product = i.split(":") interfaces = self._get_interfaces( vendor=vendor, product=product ) if len(interfaces) != 0: for interface in interfaces: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name][ "value" ] = self._interface_to_dict(interface) ret.append(clean_param) continue if is_mac(i): interfaces = self._get_interfaces(mac_address=i) else: interfaces = self._get_interfaces( Q(name=i) | Q(vendor=i) | Q(product=i) | Q(tags__overlap=[i]) ) if len(interfaces) == 0: set_form_error( self, param_name, "Unknown interface for %s(%s)" % (self._node.fqdn, self._node.system_id), ) continue for interface in interfaces: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]["value"] = self._interface_to_dict( interface ) ret.append(clean_param) def _validate_and_clean_url(self, param_name, param): """Validate and clean URL input.""" if param.get("allow_list", False): value = param["value"].split(",") else: value = [param["value"]] for url in value: # Django's validator requires a protocol but we accept just a # hostname or IP address. try: ip = ip_address(url) except ValueError: if "://" not in url: url = "http://%s" % url else: if ip.version == 4: url = "http://%s" % url else: url = "http://[%s]" % url # Allow all schemes supported by curl(used with the network # validation test) + icmp. try: validate_url( url, schemes=[ "icmp", "file", "ftp", "ftps", "gopher", "http", "https", "imap", "imaps", "ldap", "ldaps", "pop3", "pop3s", "rtmp", "rtsp", "scp", "sftp", "smb", "smbs", "smtp", "smtps", "telnet", "tftp", ], ) except ValidationError: set_form_error(self, param_name, "Invalid URL") def _validate_and_clean_string(self, param_name, param): """Validate and clean string and password input.""" if "min" in param and len(param["value"]) < param["min"]: set_form_error(self, param_name, "Input too short") if "max" in param and len(param["value"]) > param["max"]: set_form_error(self, param_name, "Input too long") def _validate_and_clean_choices(self, param_name, param): # Support a Django choice list or a string list choices = [ choice if isinstance(choice, str) else choice[0] for choice in param["choices"] ] if param["value"] not in choices: set_form_error( self, param_name, f"Invalid choice \"{param['value']}\"" ) def clean_input(self): """Validate and clean parameter input. Validate that input is correct per the parameter description. Storage input will be transformed into a dictionary representing the selected storage device from the PhysicalBlockDevice type. input will be cleaned to be a list of parameter dicts. Each item in the list represents one set of parameters for the script. This allows each storage device to be run seperately. """ ret = [] # Only validating the parameter description, not input. Do nothing. if None in (self._script, self._node): return ret result_params, multi_result_params = self._setup_input() # Validate input for single ScriptResult params for param_name, param in result_params.items(): if param["type"] == "runtime": self._validate_and_clean_runtime(param_name, param) elif param["type"] == "url": self._validate_and_clean_url(param_name, param) elif param["type"] in ["string", "password"]: self._validate_and_clean_string(param_name, param) elif param["type"] == "choice": self._validate_and_clean_choices(param_name, param) # Validate input for multi ScriptResult params for param_name, param in multi_result_params.items(): value = param["value"] if param["type"] == "storage": if value == "all": self._validate_and_clean_storage_all( param_name, param, result_params, ret ) elif isinstance(value, int) or value.isdigit(): self._validate_and_clean_storage_id( param_name, param, result_params, ret ) else: self._validate_and_clean_storage( param_name, param, result_params, ret ) elif param["type"] == "interface": if value == "all": self._validate_and_clean_interface_all( param_name, param, result_params, ret ) elif isinstance(value, int) or value.isdigit(): self._validate_and_clean_interface_id( param_name, param, result_params, ret ) else: self._validate_and_clean_interface( param_name, param, result_params, ret ) if ret == []: return [result_params] else: return ret
class ParametersForm(Form): """Parameters forms.""" parameters = Field(label='Paramaters', required=False, initial={}) input = Field(label='Input', required=False, initial={}) def __init__(self, data=None, script=None, node=None): if script is not None: assert node is not None, "node must be passed with script!" data = { 'parameters': script.parameters, 'input': data, } else: data = {'parameters': data} super().__init__(data=data) self._node = node self._script = script def _get_interfaces(self): """Return a queryset of the Interfaces that can be used.""" interfaces = self._node.interface_set.filter( children_relationships=None, enabled=True) interfaces = interfaces.exclude( ip_addresses__alloc_type=IPADDRESS_TYPE.DISCOVERED) # Exclude all IPAddresses of type DISCOVERED before checking if an # Interface doesn't have IPAddresses. If done as one excludes # DISCOVERED IPAddresses won't be filtered out before isnull is # checked. return interfaces.exclude( ip_addresses__isnull=True, ip_addresses__ip=None) def clean_parameters(self): """Validate the parameters set in the embedded YAML within the script. """ parameters = self.data.get('parameters') if not isinstance(parameters, dict): set_form_error(self, "parameters", "Must be a dictionary") return for param, fields in parameters.items(): # All parameter values should have a type defined. # Only currently supported parameter types are storage and runtime. param_type = fields.get('type') param_min = fields.get('min') param_max = fields.get('max') param_title = fields.get('title') param_description = fields.get('description') param_argument_format = fields.get('argument_format') param_default = fields.get('default') param_required = fields.get('required', True) allow_list = fields.get('allow_list') # Check param data type. if not isinstance(param, str): set_form_error( self, "parameters", "%s: parameter must be a string" % param) # Check fields data types. if not isinstance(param_type, str): set_form_error( self, "parameters", "%s: type must be a string" % param_type) if param_min is not None and not isinstance(param_min, int): set_form_error( self, "parameters", "%s: min must be an integer" % param_min) if param_max is not None and not isinstance(param_max, int): set_form_error( self, "parameters", "%s: max must be an integer" % param_max) if param_title is not None and not isinstance(param_title, str): set_form_error( self, "parameters", "%s: title must be a string" % param_title) if param_description is not None and not isinstance( param_description, str): set_form_error( self, "parameters", "%s: description must be a string" % param_description) if param_argument_format is not None and not isinstance( param_argument_format, str): set_form_error( self, "parameters", "%s: argument_format must be a string" % param_argument_format) if param_default is not None and not isinstance( param_default, str): set_form_error( self, "parameters", "%s: default must be a string" % param_default) if param_required is not None and not isinstance( param_required, bool): set_form_error( self, "parameters", "%s: required must be a boolean" % param_required) if allow_list is not None and not isinstance(allow_list, bool): set_form_error( self, "parameters", "%s: allow_list must be a boolean" % allow_list) if allow_list is not None and param_type != 'url': set_form_error( self, "parameters", "allow_list only supported with the url type.") # Check parameter type is supported and required. if (param_type not in ( 'storage', 'interface', 'url', 'runtime') and param_required): set_form_error( self, "parameters", "%s: type must be either storage, interface, url, or " "runtime" % param_type) if param_type in ('storage', 'interface', 'url') and ( param_min is not None or param_max is not None): set_form_error( self, "parameters", "Type doesn't support min or max") if param_type == 'runtime' and isinstance(param_min, int): if param_min < 0: set_form_error( self, "parameters", "runtime minimum must be greater than zero") if isinstance(param_min, int) and isinstance(param_max, int): if param_min > param_max: set_form_error( self, "parameters", "min must be less than max") if isinstance(param_argument_format, str): if param_type == 'storage': if not any( format in param_argument_format for format in ('{input}', '{name}', '{path}', '{model}', '{serial}')): set_form_error( self, "parameters", "%s: argument_format must contain one of {input}, " "{name}, {path}, {model}, {serial}" % param_type) elif param_type == 'interface': if not any( format in param_argument_format for format in ('{input}', '{name}', '{mac}', '{vendor}', '{product}')): set_form_error( self, "parameters", "%s: argument_format must contain one of {input}, " "{name}, {mac}, {vendor}, {product}" % param_type) else: if '{input}' not in param_argument_format: set_form_error( self, "parameters", "%s: argument_format must contain {input}" % param_type) return parameters def _setup_input(self): """Split input result and multi_result categories and set defaults. Users may specify multiple devices for the storage and interface parameters. This results in one ScriptResult per device to allow each each device to have its own logs and results. Each ScriptResult needs to include values for all parameters. The two lists will be combined later so each ScriptResult has a complete set of parameters. Any parameter which was not defined will have its default value set, if available. """ parameters = self.data.get('parameters', {}) input = self.data.get('input', {}) if not isinstance(input, dict): set_form_error(self, 'input', 'Input must be a dictionary') return {}, {} # Paramaters which map to a single ScriptResult result_params = {} # Paramaters which may require multiple ScriptResults(storage) multi_result_params = {} # Split user input into params which need one ScriptResult per # param and one which may need multiple ScriptResults per param. for param_name, value in input.items(): if param_name not in parameters: set_form_error( self, 'input', "Unknown parameter '%s' for %s" % ( param_name, self._script.name)) continue if parameters[param_name]['type'] in ('storage', 'interface'): multi_result_params[param_name] = copy.deepcopy( parameters[param_name]) multi_result_params[param_name]['value'] = value else: result_params[param_name] = copy.deepcopy( parameters[param_name]) result_params[param_name]['value'] = value # Check for any paramaters not given which have defaults. for param_name, param in parameters.items(): if (param['type'] in ('storage', 'interface') and param_name not in multi_result_params): default = param.get('default', 'all') if not default and param.get('required', True): set_form_error(self, param_name, 'Field is required') elif default: multi_result_params[param_name] = copy.deepcopy(param) multi_result_params[param_name]['value'] = default elif param_name not in result_params: if param['type'] == 'runtime': default = param.get( 'default', self._script.timeout.seconds) if (not isinstance(default, int) and param.get('required', True)): set_form_error(self, param_name, 'Field is required') elif isinstance(default, int): result_params[param_name] = copy.deepcopy(param) result_params[param_name]['value'] = default else: default = param.get('default', '') if not default and param.get('required', False): set_form_error(self, param_name, 'Field is required') elif default: result_params[param_name] = copy.deepcopy(param) result_params[param_name]['value'] = default return result_params, multi_result_params def _validate_and_clean_runtime(self, param_name, param): """Validate and clean runtime input.""" value = param['value'] min_value = param.get('min', 0) max_value = param.get('max') if isinstance(value, str) and value.isdigit(): value = int(value) if not isinstance(value, int): set_form_error(self, param_name, 'Must be an int') return if value < min_value: set_form_error( self, param_name, "Must be greater than %s" % min_value) if max_value is not None and value > max_value: set_form_error( self, param_name, "Must be less than %s" % max_value) def _blockdevice_to_dict(self, block_device): """Convert a block device to a dictionary with limited fields.""" return { 'name': block_device.name, 'id_path': block_device.id_path, 'model': block_device.model, 'serial': block_device.serial, 'physical_blockdevice': block_device, } def _validate_and_clean_storage_all( self, param_name, param, result_params, ret): """Validate and clean storage input when set to all.""" if len(self._node.physicalblockdevice_set) == 0: # Use 'all' as a place holder until the disks get added during # commissioning. clean_param = copy.deepcopy(result_params) clean_param[param_name] = param ret.append(clean_param) else: for bd in self._node.physicalblockdevice_set: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict( bd) ret.append(clean_param) def _validate_and_clean_storage_id( self, param_name, param, result_params, ret): """Validate and clean storage input when id.""" try: bd = self._node.physicalblockdevice_set.get(id=int(param['value'])) except ObjectDoesNotExist: set_form_error( self, param_name, 'Physical block id does not exist') else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict(bd) ret.append(clean_param) def _validate_and_clean_storage( self, param_name, param, result_params, ret): """Validate and clean storage input.""" value = param['value'] for i in value.split(','): if ':' in i: # Allow users to specify a disk using the model and serial. model, serial = i.split(':') try: bd = self._node.physicalblockdevice_set.get( model=model, serial=serial) except ObjectDoesNotExist: pass else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name][ 'value'] = self._blockdevice_to_dict(bd) ret.append(clean_param) continue qs = self._node.physicalblockdevice_set.filter( Q(name=i) | Q(name=os.path.basename(i)) | Q(model=i) | Q(serial=i) | Q(tags__overlap=[i])) if len(qs) == 0: set_form_error( self, param_name, "Unknown storage device for %s(%s)" % ( self._node.fqdn, self._node.system_id)) continue for bd in qs: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._blockdevice_to_dict( bd) ret.append(clean_param) def _interface_to_dict(self, interface): """Convert an interface to a dictionary with limited fields.""" return { 'name': interface.name, 'mac_address': str(interface.mac_address), 'vendor': interface.vendor, 'product': interface.product, 'interface': interface, } def _validate_and_clean_interface_all( self, param_name, param, result_params, ret): """Validate and clean interface input when set to all.""" interfaces = self._get_interfaces() if len(interfaces) == 0: # Use 'all' as a place holder until the Interfaces get added during # commissioning. clean_param = copy.deepcopy(result_params) clean_param[param_name] = param ret.append(clean_param) else: for interface in interfaces: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._interface_to_dict( interface) ret.append(clean_param) def _validate_and_clean_interface_id( self, param_name, param, result_params, ret): """Validate and clean interface input when id.""" try: interface = self._get_interfaces().get(id=int(param['value'])) except ObjectDoesNotExist: set_form_error( self, param_name, 'Interface id does not exist') else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._interface_to_dict( interface) ret.append(clean_param) def _validate_and_clean_interface( self, param_name, param, result_params, ret): """Validate and clean interface input.""" value = param['value'] for i in value.split(','): if ':' in i: # Allow users to specify an Interface using the vendor and # product. vendor, product = i.split(':') try: interface = self._get_interfaces().get( vendor=vendor, product=product) except ObjectDoesNotExist: pass else: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._interface_to_dict( interface) ret.append(clean_param) continue if is_mac(i): qs = self._get_interfaces().filter(mac_address=i) else: qs = self._get_interfaces().filter( Q(name=i) | Q(vendor=i) | Q(product=i) | Q(tags__overlap=[i])) if len(qs) == 0: set_form_error( self, param_name, "Unknown interface for %s(%s)" % ( self._node.fqdn, self._node.system_id)) continue for interface in qs: clean_param = copy.deepcopy(result_params) clean_param[param_name] = copy.deepcopy(param) clean_param[param_name]['value'] = self._interface_to_dict( interface) ret.append(clean_param) def _validate_and_clean_url(self, param_name, param): """Validate and clean URL input.""" if param.get('allow_list', False): value = param['value'].split(',') else: value = [param['value']] for url in value: # Django's validator requires a protocol but we accept just a # hostname or IP address. try: ip = ip_address(url) except ValueError: if '://' not in url: url = 'http://%s' % url else: if ip.version == 4: url = 'http://%s' % url else: url = 'http://[%s]' % url # Allow all schemes supported by curl(used with the network # validation test) + icmp. try: validate_url(url, schemes=[ 'icmp', 'file', 'ftp', 'ftps', 'gopher', 'http', 'https', 'imap', 'imaps', 'ldap', 'ldaps', 'pop3', 'pop3s', 'rtmp', 'rtsp', 'scp', 'sftp', 'smb', 'smbs', 'smtp', 'smtps', 'telnet', 'tftp']) except ValidationError: set_form_error(self, param_name, 'Invalid URL') def clean_input(self): """Validate and clean parameter input. Validate that input is correct per the parameter description. Storage input will be transformed into a dictionary representing the selected storage device from the PhysicalBlockDevice type. input will be cleaned to be a list of parameter dicts. Each item in the list represents one set of parameters for the script. This allows each storage device to be run seperately. """ ret = [] # Only validating the parameter description, not input. Do nothing. if None in (self._script, self._node): return ret result_params, multi_result_params = self._setup_input() # Validate input for single ScriptResult params for param_name, param in result_params.items(): if param['type'] == 'runtime': self._validate_and_clean_runtime(param_name, param) elif param['type'] == 'url': self._validate_and_clean_url(param_name, param) # Validate input for multi ScriptResult params for param_name, param in multi_result_params.items(): value = param['value'] if param['type'] == 'storage': if value == 'all': self._validate_and_clean_storage_all( param_name, param, result_params, ret) elif isinstance(value, int) or value.isdigit(): self._validate_and_clean_storage_id( param_name, param, result_params, ret) else: self._validate_and_clean_storage( param_name, param, result_params, ret) elif param['type'] == 'interface': if value == 'all': self._validate_and_clean_interface_all( param_name, param, result_params, ret) elif isinstance(value, int) or value.isdigit(): self._validate_and_clean_interface_id( param_name, param, result_params, ret) else: self._validate_and_clean_interface( param_name, param, result_params, ret) if ret == []: return [result_params] else: return ret
def clean(self, value): value = self.to_python(value) return Field.clean(self,value)
def get_form(self, form_class=None): form = super().get_form(form_class) form.fields[self.operation_mark_field] = Field(initial=self.operation, widget=HiddenInput) if self.csrf_token_for_form is not None: form.fields['csrfmiddlewaretoken'] = Field(initial=self.csrf_token_for_form, widget=HiddenInput) return form
class SearchForm(Form): checkbox_attrs = { 'btn_attrs': {'type': 'button', 'class': 'btn'}, 'data_attrs': {'class': 'hidden'}, 'btn_container_attrs': {'class': 'btn-group buttons-visible', 'data-toggle': 'buttons-checkbox'}, 'data_container_attrs': {'class': 'buttons-data'}, } radio_attrs = { 'btn_attrs': {'type': 'button', 'class': 'btn'}, 'data_attrs': {'class': 'hidden'}, 'btn_container_attrs': {'class': 'btn-group buttons-visible', 'data-toggle': 'buttons-radio'}, 'data_container_attrs': {'class': 'buttons-data'}, } img_attrs = { 'group_container_class': 'characters-group group-', 'data_attrs': {'class': 'hidden'}, 'container_attrs': {'class': 'character-item'} } # Строка поиска search_query = CharField( required=False, widget=TextInput( attrs={ 'size': 32, 'placeholder': 'Пинки-поиск', 'id': 'appendedInputButtons', 'class': 'span3', 'maxlength': 128, } ), max_length=128, ) # Минимальный размер search_min_size = IntegerField( required=False, widget=NumberInput( attrs={ 'size': 8, 'placeholder': 'От', 'class': 'span3', 'maxlength': 8, 'min': 0, 'max': 99999000, 'step': 1000, } ), ) # Максимальный размер search_max_size = IntegerField( required=False, widget=NumberInput( attrs={ 'size': 8, 'placeholder': 'До', 'class': 'span3', 'maxlength': 8, 'min': 0, 'max': 99999000, 'step': 1000, } ), ) # Жанры categories_select = ModelMultipleChoiceField( queryset=Category.objects.all(), required=False, widget=StoriesCheckboxSelectMultiple( attrs={ 'label_attrs': ['checkbox', 'inline', 'gen'], 'label_id_related_attr': 'gen-', }, ), ) # Персонажи characters_select = GroupedModelChoiceField( required=False, queryset=Character.objects.all(), group_by_field='group', widget=StoriesImgSelect(attrs=img_attrs), ) # Оригинал/перевод originals_select = MultipleChoiceField( choices=[(0, 'Перевод'), (1, 'Оригинал')], required=False, widget=StoriesButtons(attrs=checkbox_attrs), ) # Статус рассказа finished_select = MultipleChoiceField( choices=[(0, 'Не завершен'), (1, 'Завершен')], required=False, widget=StoriesButtons(attrs=checkbox_attrs), ) # Активность рассказа freezed_select = MultipleChoiceField( choices=[(0, 'Активен'), (1, 'Заморожен')], required=False, widget=StoriesButtons(attrs=checkbox_attrs), ) # Рейтинги ratings_select = ModelMultipleChoiceField( queryset=Rating.objects.all(), required=False, widget=StoriesButtons(attrs=checkbox_attrs), ) # События classifications_select = ModelMultipleChoiceField( queryset=Classifier.objects.all(), required=False, widget=StoriesCheckboxSelectMultiple(attrs={'label_attrs': ['checkbox', 'inline']}), ) # Кнопка "Развернуть тонкие настройки поиска" button_advanced = Field( required=False, widget=ButtonWidget( attrs={ 'type': 'button', 'class': 'btn btn-collapse', 'data-toggle': 'collapse', 'data-target': '#more-info', 'text': 'Еще более тонкий поиск' } ), ) # Кнопка "Развернуть фильтры" button_filters = Field( required=False, widget=ButtonWidget( attrs={ 'type': 'button', 'class': 'btn btn-collapse', 'data-toggle': 'collapse', 'data-target': '#more-filters', 'text': 'Фильтры поиска' } ), ) # Кнопка "Развернуть сортировку" button_sort = Field( required=False, widget=ButtonWidget( attrs={ 'type': 'button', 'class': 'btn btn-collapse', 'data-toggle': 'collapse', 'data-target': '#more-sort', 'text': 'Сортировка результатов' } ), ) # Сортировка sort_type = MultipleChoiceField( choices=[(1, 'По дате'), (2, 'По размеру'), (3, 'По рейтингу'), (4, 'По комментам')], required=False, widget=StoriesButtons(attrs=checkbox_attrs), ) # bla button_submit = Field( required=False, widget=ServiceButtonWidget(attrs={'class': 'btn btn-primary'}), initial='Искать!', ) button_reset = Field( required=False, widget=StoriesServiceInput( attrs={ 'type': 'reset', 'class': 'btn', 'id': 'reset_search', 'value': 'Очистить', } ), ) # Тип поиска search_type = ChoiceField( choices=[(0, 'Быстрый'), (1, 'Полный')], required=True, widget=StoriesRadioButtons(attrs=radio_attrs), )