Exemple #1
0
class StudyBuildForm(forms.ModelForm):
    structure = forms.CharField(
        label='Build Study - Add JSON',
        widget=AceOverlayWidget(mode='json',
                                wordwrap=True,
                                theme='textmate',
                                width='100%',
                                height='100%',
                                showprintmargin=False),
        required=False,
        help_text=
        'Add the frames of your study as well as the sequence of those frames.'
    )

    def clean_structure(self):
        structure = self.cleaned_data['structure']
        try:
            json_data = json.loads(structure)  #loads string as json
        except:
            raise forms.ValidationError("Invalid JSON")
        return json_data

    class Meta:
        model = Study
        fields = ['structure']
Exemple #2
0
class StudyForm(StudyEditForm):
    structure = forms.CharField(
        label='Build Study - Add JSON',
        widget=AceOverlayWidget(mode='json',
                                wordwrap=True,
                                theme='textmate',
                                width='100%',
                                height='100%',
                                showprintmargin=False),
        required=False,
        help_text=
        'Add the frames of your study as well as the sequence of those frames.  This can be added later.'
    )

    def clean_structure(self):
        structure = self.cleaned_data['structure']
        try:
            json_data = json.loads(structure)  #loads string as json
        except:
            raise forms.ValidationError("Invalid JSON")
        return json_data

    class Meta(StudyEditForm.Meta):
        fields = StudyEditForm.Meta.fields + ['structure', 'study_type']

        labels = StudyEditForm.Meta.labels.copy()
        labels['study_type'] = 'Study Type'

        help_texts = StudyEditForm.Meta.help_texts.copy()
        help_texts[
            'study_type'] = "Specify the build process as well as the parameters needed by the experiment builder. If you don't know what this is, just select the default."
Exemple #3
0
class ResponseForm(forms.ModelForm):
    results = forms.CharField(widget=AceOverlayWidget(mode='json',
                                                      wordwrap=True,
                                                      theme='textmate',
                                                      width='100%',
                                                      height='100%',
                                                      showprintmargin=False),
                              required=False)

    class Meta:
        fields = ('study', 'child', 'demographic_snapshot', 'results')
        model = Response
Exemple #4
0
class EditAdminForm(forms.ModelForm):
    text = forms.CharField(widget=AceOverlayWidget(mode='html',
                                                   wordwrap=False,
                                                   theme='twilight',
                                                   width="850px",
                                                   height="800px",
                                                   showprintmargin=True),
                           required=False)

    class Meta:
        model = Edit
        fields = '__all__'
Exemple #5
0
class StudyForm(forms.ModelForm):
    blocks = forms.CharField(widget=AceOverlayWidget(mode='json',
                                                     wordwrap=True,
                                                     theme='textmate',
                                                     width="100%",
                                                     height="100%",
                                                     showprintmargin=False),
                             required=False)

    class Meta:
        fields = ('name', 'organization', 'blocks')
        model = Study
class PythonCodeFunctionDefinitionAdminForm(forms.ModelForm):
    if 'ace_overlay' in settings.INSTALLED_APPS:
        code = forms.CharField(widget=AceOverlayWidget(mode='python',
                                                       wordwrap=False,
                                                       theme='solarized_light',
                                                       width="850px",
                                                       height="800px",
                                                       showprintmargin=True),
                               required=True)

    class Meta:
        model = PythonCodeFunctionDefinition
        fields = ('title', 'description', 'is_returns_value',
                  'is_context_required', 'code')
Exemple #7
0
class ResponseForm(ModelForm):
    results = forms.CharField(
        widget=AceOverlayWidget(
            mode="json",
            wordwrap=True,
            theme="textmate",
            width="100%",
            height="100%",
            showprintmargin=False,
        ),
        required=False,
    )

    class Meta:
        fields = ("study", "child", "demographic_snapshot", "results")
        model = Response
Exemple #8
0
class StudyForm(ModelForm):
    """Base form for creating or editing a study"""

    # Eventually when we support other experiment runner types (labjs, jspsych, etc.)
    # we may do one of the following:
    # - separate the 'study protocol specification' fields into their own
    # form which collects various information and cleans it and sets a single 'structure' object,
    # with the selected
    # - creating a model to represent each study type, likely such that each study has a nullable
    # relation for lookit_runner_protocol, jspsych_runner_protocol, etc.

    structure = forms.CharField(
        label="Protocol configuration",
        widget=AceOverlayWidget(
            mode="json",
            wordwrap=True,
            theme="textmate",
            width="100%",
            height="100%",
            showprintmargin=False,
        ),
        required=False,
    )

    # Define initial value here rather than providing actual default so that any updates don't
    # require migrations: this isn't a true "default" value that would ever be used, but rather
    # a helpful skeleton to guide the user
    generator = forms.CharField(
        label="Protocol generator",
        widget=AceOverlayWidget(
            mode="javascript",
            wordwrap=True,
            theme="textmate",
            width="100%",
            height="100%",
            showprintmargin=False,
        ),
        required=False,
        help_text=
        ("Write a Javascript function that returns a study protocol object with 'frames' and "
         "'sequence' keys. This allows more flexible randomization and dependence on past sessions in "
         f"complex cases. See <a href={PROTOCOL_GENERATOR_HELP_LINK}>documentation</a> for details."
         ),
        initial=DEFAULT_GENERATOR,
    )

    def clean(self):
        cleaned_data = super().clean()
        min_age_days = self.cleaned_data.get("min_age_days")
        min_age_months = self.cleaned_data.get("min_age_months")
        min_age_years = self.cleaned_data.get("min_age_years")
        max_age_days = self.cleaned_data.get("max_age_days")
        max_age_months = self.cleaned_data.get("max_age_months")
        max_age_years = self.cleaned_data.get("max_age_years")
        if (min_age_years * 365 + min_age_months * 30 + min_age_days) > (
                max_age_years * 365 + max_age_months * 30 + max_age_days):
            raise forms.ValidationError(
                "The maximum age must be greater than the minimum age.")
        return cleaned_data

    def clean_structure(self):
        structure_text = self.cleaned_data["structure"]

        # Parse edited text representation of structure object, and additionally store the
        # exact text (so user can organize frames, parameters, etc. for readability)
        try:
            json_data = json.loads(structure_text)  # loads string as json
            json_data["exact_text"] = structure_text
        except:
            raise forms.ValidationError(
                "Saving protocol configuration failed due to invalid JSON! Please use valid JSON and save again. If you reload this page, all changes will be lost."
            )

        # Store the object which includes the exact text (not just the text)
        return json_data

    def clean_criteria_expression(self):
        criteria_expression = self.cleaned_data["criteria_expression"]
        try:
            compile_expression(criteria_expression)
        except Exception as e:
            raise forms.ValidationError(
                f"Invalid criteria expression:\n{e.args[0]}")

        return criteria_expression

    class Meta:
        model = Study
        fields = [
            "name",
            "lab",
            "image",
            "short_description",
            "long_description",
            "compensation_description",
            "exit_url",
            "criteria",
            "min_age_days",
            "min_age_months",
            "min_age_years",
            "max_age_days",
            "max_age_months",
            "max_age_years",
            "duration",
            "contact_info",
            "public",
            "shared_preview",
            "structure",
            "generator",
            "use_generator",
            "criteria_expression",
            "study_type",
        ]
        labels = {
            "short_description": "Short Description",
            "long_description": "Purpose",
            "exit_url": "Exit URL",
            "criteria": "Participant Eligibility Description",
            "contact_info": "Researcher Contact Information",
            "public":
            "Discoverable - List this study on the 'Studies' page once you start it?",
            "shared_preview":
            "Share preview - Allow other Lookit researchers to preview your study and give feedback?",
            "study_type": "Experiment Runner Type",
            "compensation_description": "Compensation",
            "use_generator": "Use protocol generator (advanced)",
        }
        widgets = {
            "short_description":
            Textarea(attrs={"rows": 2}),
            "long_description":
            Textarea(attrs={"rows": 2}),
            "compensation_description":
            Textarea(attrs={"rows": 2}),
            "exit_url":
            Textarea(attrs={"rows": 1}),
            "criteria":
            Textarea(attrs={
                "rows": 1,
                "placeholder": "For 4-year-olds who love dinosaurs"
            }),
            "duration":
            Textarea(attrs={
                "rows": 1,
                "placeholder": "15 minutes"
            }),
            "contact_info":
            Textarea(
                attrs={
                    "rows": 1,
                    "placeholder": "Jane Smith (contact: [email protected])",
                }),
            "criteria_expression":
            Textarea(
                attrs={
                    "rows":
                    3,
                    "placeholder": (
                        "ex: ((deaf OR hearing_impairment) OR NOT speaks_en) "
                        "AND "
                        "(age_in_days >= 365 AND age_in_days <= 1095)"),
                }),
        }

        help_texts = {
            "lab":
            "Which lab this study will be affiliated with",
            "image":
            "Please keep your file size less than 1 MB",
            "exit_url":
            "Specify the page where you want to send your participants after they've completed the study. (The 'Past studies' page on Lookit is a good default option.)",
            "short_description":
            "Describe what happens during your study here. This should give families a concrete idea of what they will be doing - e.g., reading a story together and answering questions, watching a short video, playing a game about numbers.",
            "long_description":
            "Explain the purpose of your study here. This should address what question this study answers AND why that is an interesting or important question, in layperson-friendly terms.",
            "contact_info":
            "This should give the name of the PI for your study, and an email address where the PI or study staff can be reached with questions. Format: PIs Name (contact: [email protected])",
            "criteria":
            "Text shown to families - this is not used to actually verify eligibility.",
            "compensation_description":
            "Provide a description of any compensation for participation, including when and how participants will receive it and any limitations or eligibility criteria (e.g., only one gift card per participant, being in age range for study, child being visible in consent video). Please see the Terms of Use for details on allowable compensation and restrictions. If this field is left blank it will not be displayed to participants.",
            "criteria_expression":
            ("Provide a relational expression indicating any criteria for eligibility besides the age range specified below."
             "For more information on how to structure criteria expressions, please visit our "
             f"<a href={CRITERIA_EXPRESSION_HELP_LINK}>documentation</a>."),
        }
Exemple #9
0
class TemplateAdminForm(forms.ModelForm):
    custom_template = forms.CharField(widget=AceOverlayWidget(mode='html', wordwrap=True, theme='github', width="850px", height="700px", showprintmargin=True), required=False)
Exemple #10
0
class JSResourceAdminForm(forms.ModelForm):
    custom_source = forms.CharField(widget=AceOverlayWidget(mode='javascript', wordwrap=True, theme='github', width="850px", height="800px", showprintmargin=True), required=False)
Exemple #11
0
class StudyForm(ModelForm):
    """Base form for creating or editing a study"""

    structure = forms.CharField(
        label="Protocol configuration",
        widget=AceOverlayWidget(
            mode="json",
            wordwrap=True,
            theme="textmate",
            width="100%",
            height="100%",
            showprintmargin=False,
        ),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        # Limit lab options to labs this user is a member of
        user = kwargs.pop("user")
        super().__init__(*args, **kwargs)
        self.fields["lab"].queryset = user.labs.filter(
            id__in=user.labs_user_can_create_study_in())

    def clean(self):
        cleaned_data = super().clean()
        min_age_days = self.cleaned_data.get("min_age_days")
        min_age_months = self.cleaned_data.get("min_age_months")
        min_age_years = self.cleaned_data.get("min_age_years")
        max_age_days = self.cleaned_data.get("max_age_days")
        max_age_months = self.cleaned_data.get("max_age_months")
        max_age_years = self.cleaned_data.get("max_age_years")
        if (min_age_years + min_age_months / 12 + min_age_days / 365) > (
                max_age_years + max_age_months / 12 + max_age_days / 365):
            raise forms.ValidationError(
                "The maximum age must be greater than the minimum age.")
        return cleaned_data

    def clean_structure(self):
        structure = self.cleaned_data["structure"]

        try:
            json_data = json.loads(structure)  # loads string as json
        except:
            raise forms.ValidationError(
                "Saving protocol configuration failed due to invalid JSON! Please use valid JSON and save again. If you reload this page, all changes will be lost."
            )

        return json_data

    def clean_criteria_expression(self):
        criteria_expression = self.cleaned_data["criteria_expression"]
        try:
            compile_expression(criteria_expression)
        except Exception as e:
            raise forms.ValidationError(
                f"Invalid criteria expression:\n{e.args[0]}")

        return criteria_expression

    class Meta:
        model = Study
        fields = [
            "name",
            "lab",
            "image",
            "short_description",
            "long_description",
            "compensation_description",
            "exit_url",
            "criteria",
            "min_age_days",
            "min_age_months",
            "min_age_years",
            "max_age_days",
            "max_age_months",
            "max_age_years",
            "duration",
            "contact_info",
            "public",
            "shared_preview",
            "structure",
            "criteria_expression",
            "study_type",
        ]
        labels = {
            "short_description": "Short Description",
            "long_description": "Purpose",
            "exit_url": "Exit URL",
            "criteria": "Participant Eligibility Description",
            "contact_info": "Researcher Contact Information",
            "public":
            "Discoverable - List this study on the 'Studies' page once you start it?",
            "shared_preview":
            "Share preview - Allow other Lookit researchers to preview your study and give feedback?",
            "study_type": "Experiment Runner Type",
            "compensation_description": "Compensation",
        }
        widgets = {
            "short_description":
            Textarea(attrs={"rows": 2}),
            "long_description":
            Textarea(attrs={"rows": 2}),
            "compensation_description":
            Textarea(attrs={"rows": 2}),
            "exit_url":
            Textarea(attrs={"rows": 1}),
            "criteria":
            Textarea(attrs={
                "rows": 1,
                "placeholder": "For 4-year-olds who love dinosaurs"
            }),
            "duration":
            Textarea(attrs={
                "rows": 1,
                "placeholder": "15 minutes"
            }),
            "contact_info":
            Textarea(
                attrs={
                    "rows": 1,
                    "placeholder": "Jane Smith (contact: [email protected])",
                }),
            "criteria_expression":
            Textarea(
                attrs={
                    "rows":
                    3,
                    "placeholder": (
                        "ex: ((deaf OR hearing_impairment) OR NOT speaks_en) "
                        "AND "
                        "(age_in_days >= 365 AND age_in_days <= 1095)"),
                }),
        }

        help_texts = {
            "lab":
            "Which lab this study will be affiliated with",
            "image":
            "Please keep your file size less than 1 MB",
            "exit_url":
            "Specify the page where you want to send your participants after they've completed the study. (The 'Past studies' page on Lookit is a good default option.)",
            "short_description":
            "Describe what happens during your study here. This should give families a concrete idea of what they will be doing - e.g., reading a story together and answering questions, watching a short video, playing a game about numbers.",
            "long_description":
            "Explain the purpose of your study here. This should address what question this study answers AND why that is an interesting or important question, in layperson-friendly terms.",
            "contact_info":
            "This should give the name of the PI for your study, and an email address where the PI or study staff can be reached with questions. Format: PIs Name (contact: [email protected])",
            "criteria":
            "Text shown to families - this is not used to actually verify eligibility.",
            "compensation_description":
            "Provide a description of any compensation for participation, including when and how participants will receive it and any limitations or eligibility criteria (e.g., only one gift card per participant, being in age range for study, child being visible in consent video). Please see the Terms of Use for details on allowable compensation and restrictions. If this field is left blank it will not be displayed to participants.",
            "criteria_expression":
            ("Provide a relational expression indicating any criteria for eligibility besides the age range specified below."
             "For more information on how to structure criteria expressions, please visit our "
             f"<a href={CRITERIA_EXPRESSION_HELP_LINK}>documentation</a>."),
        }