stages/prompt: add prompt order field
This commit is contained in:
		@ -38,13 +38,13 @@ class IdentificationStageView(FormView, StageView):
 | 
			
		||||
        enrollment_flow = self.executor.flow.related_flow(FlowDesignation.ENROLLMENT)
 | 
			
		||||
        if enrollment_flow:
 | 
			
		||||
            kwargs["enroll_url"] = reverse(
 | 
			
		||||
                "passbook_flows:flow-executor",
 | 
			
		||||
                "passbook_flows:flow-executor-shell",
 | 
			
		||||
                kwargs={"flow_slug": enrollment_flow.slug},
 | 
			
		||||
            )
 | 
			
		||||
        recovery_flow = self.executor.flow.related_flow(FlowDesignation.RECOVERY)
 | 
			
		||||
        if recovery_flow:
 | 
			
		||||
            kwargs["recovery_url"] = reverse(
 | 
			
		||||
                "passbook_flows:flow-executor",
 | 
			
		||||
                "passbook_flows:flow-executor-shell",
 | 
			
		||||
                kwargs={"flow_slug": recovery_flow.slug},
 | 
			
		||||
            )
 | 
			
		||||
        kwargs["primary_action"] = _("Log in")
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,7 @@ class PromptSerializer(ModelSerializer):
 | 
			
		||||
            "type",
 | 
			
		||||
            "required",
 | 
			
		||||
            "placeholder",
 | 
			
		||||
            "order",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ class PromptAdminForm(forms.ModelForm):
 | 
			
		||||
            "type",
 | 
			
		||||
            "required",
 | 
			
		||||
            "placeholder",
 | 
			
		||||
            "order",
 | 
			
		||||
        ]
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "label": forms.TextInput(),
 | 
			
		||||
@ -48,9 +49,12 @@ class PromptForm(forms.Form):
 | 
			
		||||
        self.stage = stage
 | 
			
		||||
        self.plan = plan
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        for field in self.stage.fields.all():
 | 
			
		||||
        # list() is called so we only load the fields once
 | 
			
		||||
        fields = list(self.stage.fields.all())
 | 
			
		||||
        for field in fields:
 | 
			
		||||
            field: Prompt
 | 
			
		||||
            self.fields[field.field_key] = field.field
 | 
			
		||||
        self.field_order = sorted(fields, key=lambda x: x.order)
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        cleaned_data = super().clean()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										35
									
								
								passbook/stages/prompt/migrations/0002_auto_20200528_2059.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								passbook/stages/prompt/migrations/0002_auto_20200528_2059.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
# Generated by Django 3.0.6 on 2020-05-28 20:59
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("passbook_stages_prompt", "0001_initial"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name="prompt", name="order", field=models.IntegerField(default=0),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="prompt",
 | 
			
		||||
            name="type",
 | 
			
		||||
            field=models.CharField(
 | 
			
		||||
                choices=[
 | 
			
		||||
                    ("text", "Text"),
 | 
			
		||||
                    ("e-mail", "Email"),
 | 
			
		||||
                    ("password", "Password"),
 | 
			
		||||
                    ("number", "Number"),
 | 
			
		||||
                    ("checkbox", "Checkbox"),
 | 
			
		||||
                    ("data", "Date"),
 | 
			
		||||
                    ("data-time", "Date Time"),
 | 
			
		||||
                    ("separator", "Separator"),
 | 
			
		||||
                    ("hidden", "Hidden"),
 | 
			
		||||
                    ("static", "Static"),
 | 
			
		||||
                ],
 | 
			
		||||
                max_length=100,
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@ -16,7 +16,13 @@ class FieldTypes(models.TextChoices):
 | 
			
		||||
    EMAIL = "e-mail"
 | 
			
		||||
    PASSWORD = "password"  # noqa # nosec
 | 
			
		||||
    NUMBER = "number"
 | 
			
		||||
    CHECKBOX = "checkbox"
 | 
			
		||||
    DATE = "data"
 | 
			
		||||
    DATE_TIME = "data-time"
 | 
			
		||||
 | 
			
		||||
    SEPARATOR = "separator"
 | 
			
		||||
    HIDDEN = "hidden"
 | 
			
		||||
    STATIC = "static"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Prompt(models.Model):
 | 
			
		||||
@ -32,41 +38,37 @@ class Prompt(models.Model):
 | 
			
		||||
    required = models.BooleanField(default=True)
 | 
			
		||||
    placeholder = models.TextField()
 | 
			
		||||
 | 
			
		||||
    order = models.IntegerField(default=0)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def field(self):
 | 
			
		||||
        """Return instantiated form input field"""
 | 
			
		||||
        attrs = {"placeholder": _(self.placeholder)}
 | 
			
		||||
        if self.type == FieldTypes.TEXT:
 | 
			
		||||
            return forms.CharField(
 | 
			
		||||
                label=_(self.label),
 | 
			
		||||
                widget=forms.TextInput(attrs=attrs),
 | 
			
		||||
                required=self.required,
 | 
			
		||||
            )
 | 
			
		||||
        field_class = forms.CharField
 | 
			
		||||
        widget = forms.TextInput(attrs=attrs)
 | 
			
		||||
        kwargs = {
 | 
			
		||||
            "label": _(self.label),
 | 
			
		||||
            "required": self.required,
 | 
			
		||||
        }
 | 
			
		||||
        if self.type == FieldTypes.EMAIL:
 | 
			
		||||
            return forms.EmailField(
 | 
			
		||||
                label=_(self.label),
 | 
			
		||||
                widget=forms.TextInput(attrs=attrs),
 | 
			
		||||
                required=self.required,
 | 
			
		||||
            )
 | 
			
		||||
            field_class = forms.EmailField
 | 
			
		||||
        if self.type == FieldTypes.PASSWORD:
 | 
			
		||||
            return forms.CharField(
 | 
			
		||||
                label=_(self.label),
 | 
			
		||||
                widget=forms.PasswordInput(attrs=attrs),
 | 
			
		||||
                required=self.required,
 | 
			
		||||
            )
 | 
			
		||||
            widget = forms.PasswordInput(attrs=attrs)
 | 
			
		||||
        if self.type == FieldTypes.NUMBER:
 | 
			
		||||
            return forms.IntegerField(
 | 
			
		||||
                label=_(self.label),
 | 
			
		||||
                widget=forms.NumberInput(attrs=attrs),
 | 
			
		||||
                required=self.required,
 | 
			
		||||
            )
 | 
			
		||||
            field_class = forms.IntegerField
 | 
			
		||||
            widget = forms.NumberInput(attrs=attrs)
 | 
			
		||||
        if self.type == FieldTypes.HIDDEN:
 | 
			
		||||
            return forms.CharField(
 | 
			
		||||
                widget=forms.HiddenInput(attrs=attrs),
 | 
			
		||||
                required=False,
 | 
			
		||||
                initial=self.placeholder,
 | 
			
		||||
            )
 | 
			
		||||
        raise ValueError("field_type is not valid, not one of FieldTypes.")
 | 
			
		||||
            widget = forms.HiddenInput(attrs=attrs)
 | 
			
		||||
            kwargs["required"] = False
 | 
			
		||||
            kwargs["initial"] = self.placeholder
 | 
			
		||||
        if self.type == FieldTypes.CHECKBOX:
 | 
			
		||||
            field_class = forms.CheckboxInput
 | 
			
		||||
            kwargs["required"] = False
 | 
			
		||||
 | 
			
		||||
        # TODO: Implement static
 | 
			
		||||
        # TODO: Implement separator
 | 
			
		||||
        kwargs["widget"] = widget
 | 
			
		||||
        return field_class(**kwargs)
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        if self.type not in FieldTypes:
 | 
			
		||||
 | 
			
		||||
@ -93,25 +93,6 @@ class TestPromptStage(TestCase):
 | 
			
		||||
 | 
			
		||||
        FlowStageBinding.objects.create(flow=self.flow, stage=self.stage, order=2)
 | 
			
		||||
 | 
			
		||||
    def test_invalid_type(self):
 | 
			
		||||
        """Test that invalid form type raises an error"""
 | 
			
		||||
        with self.assertRaises(ValueError):
 | 
			
		||||
            _ = Prompt.objects.create(
 | 
			
		||||
                field_key="hidden_prompt",
 | 
			
		||||
                type="invalid",
 | 
			
		||||
                required=True,
 | 
			
		||||
                placeholder="HIDDEN_PLACEHOLDER",
 | 
			
		||||
            )
 | 
			
		||||
        with self.assertRaises(ValueError):
 | 
			
		||||
            prompt = Prompt.objects.create(
 | 
			
		||||
                field_key="hidden_prompt",
 | 
			
		||||
                type=FieldTypes.HIDDEN,
 | 
			
		||||
                required=True,
 | 
			
		||||
                placeholder="HIDDEN_PLACEHOLDER",
 | 
			
		||||
            )
 | 
			
		||||
            with patch.object(prompt, "type", MagicMock(return_value="invalid")):
 | 
			
		||||
                _ = prompt.field
 | 
			
		||||
 | 
			
		||||
    def test_render(self):
 | 
			
		||||
        """Test render of form, check if all prompts are rendered correctly"""
 | 
			
		||||
        plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user