Example #1
0
class TextTrial(BaseSettingBlock):
    """
    This model encapsulates a link to a .html django template (or raw html) that lives in the experiment directory
    I could have used a nifty tool like django-forms-builder but I need more than just labels and input, also text.
    
    These form builders are also much too complex and focused on managing and saving data server-side when I just want to show the form and let jsPsych get the value of input fields
    All WYSISWYG editors for html do not support creating forms. So really no choice but raw html here.
    """

    #TODO: so this poses a problem for internationalization, figure out later, no time
    text = MarkdownField(help_text=l_(
        "path to your html file inside your experiment directory, probably just its name and extension."
    ))
    cont_btn = models.PositiveSmallIntegerField(
        null=True,
        blank=True,
        help_text=l_(
            "If given, this is the key code a key to advance to the next trial"
        ))
    cont_btn = models.CharField(
        blank=True,
        null=True,
        max_length=24,
        help_text=l_(
            "The ID of a clickable element in the <form> you just created. When the element is clicked, the trial will advance."
        ))
Example #2
0
class SignUpForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput(),
                               label=l_("Password"))
    confirm_password = forms.CharField(widget=forms.PasswordInput(),
                                       label=l_("Confirm your password"))
    email = forms.CharField(required=True)

    class Meta:
        model = User
        exclude = ['last_login', 'date_joined']

    def __init__(self, *args, **kwargs):
        super(SignUpForm, self).__init__(*args, **kwargs)
        self.fields['username'].validators.append(ForbiddenUsernamesValidator)
        self.fields['username'].validators.append(InvalidUsernameValidator)
        self.fields['username'].validators.append(
            UniqueUsernameIgnoreCaseValidator)
        self.fields['email'].validators.append(UniqueEmailValidator)

    def clean(self):
        super(SignUpForm, self).clean()
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if password and password != confirm_password:
            self._errors['password'] = self.error_class(
                [l_("Passwords don\'t match")])
        return self.cleaned_data
Example #3
0
class LinkedStimulus(models.Model):
    """
    Model used to implemented Generic many to many relations between a setting object and a stimuli object
    
    Since djPsych is heavily centered around the django admin, we need to be able to add stimuli objects to stuff as Inlines
    Both librairies adressing generic m2m relationships that I found are poor and, critically, offer no admin integration.
    """
    # First the link to the setting object
    setting_type = models.ForeignKey(ContentType, related_name="stimlinks")
    setting_id = models.PositiveIntegerField()
    setting = GenericForeignKey('setting_type', 'setting_id')

    # now the link to the simuli object
    stim_type = models.ForeignKey(ContentType, related_name='blocklinks')
    stim_id = models.PositiveIntegerField()
    stimulus = GenericForeignKey('stim_type', 'stim_id')
    #TODO: maybe use grappelli's inline ordering feature instead of asking users to directly enter an index number... someone (not me!) should look into that
    index = models.PositiveSmallIntegerField(
        blank=True,
        null=True,
        help_text=l_(
            "Youn can give a number to indicate the order among the pairs that point to the same block. They will be given in asceding order."
        ))
    is_practice = models.BooleanField(
        default=False,
        help_text=l_(
            "Check this if this stimuli should be in the practice set"))

    # TODO: There is a redundance between setting stimuli as practice and the ability to set blocks as practice blocks. What to do?

    def get_experiment(self):
        if hasattr(self.setting, 'experiment'):
            return self.setting.experiment
        else:
            return self.setting.part_of.experiment
Example #4
0
class Question(BaseStimuli):
    question_label = models.CharField( max_length = 1024, help_text=l_("Question:"))
    answer_options = models.CharField(null = True, blank = True, max_length = 1024, help_text=l_("Only for likert and multi-choices surveys!!! Choose the labels for the possibles answers for each question. You have separate them with a coma and no spaces. ex: yes,no,maybe. Leaving a space using the likert survey will put a blank in the scale. Ex: 1,,,4"))
    required = models.BooleanField(help_text=l_("If the question is required. If so, put true, else put false."), default=False)
    
    
    def __str__(self):
        return self.question_label
Example #5
0
class AudioCatBlock(BaseSettingBlock):
    type = 'audio-categorization'
    choices = models.CharField(
        blank=True,
        max_length=1024,
        help_text=l_(
            "Choose the keys associated for all categories. You have separate them with a coma and non spaces."
        ))
    timing_response = models.IntegerField(help_text=l_(
        "time limit for the participant before the trial automatically advances"
    ),
                                          default=-1)
    prompt = models.CharField(
        max_length=256,
        blank=True,
        help_text=l_(
            "Any content here will be displayed below the stimulus, as a reminder to the participant"
        ))
    timing_feedback = models.IntegerField(help_text=l_(
        "How long to show the feedback message for in milliseconds."))
    correct_feedback = models.CharField(
        max_length=64,
        blank=True,
        help_text=l_(
            "Any content here will be displayed as a feedback given to the participants when he hits the correct category"
        ))
    incorrect_feedback = models.CharField(
        max_length=64,
        blank=True,
        help_text=l_(
            "Any content here will be displayed as a feedback given to the participants when he doesn't hit the correct category"
        ))
    timeout_feedback = models.CharField(
        max_length=64,
        blank=True,
        help_text=l_(
            "Any content here will be displayed as a feedback given to the participants when he takes too long to answer the question if there is a timeout"
        ))
    show_icon = models.BooleanField(
        default=False,
        help_text=l_(
            'Check this box to have a speaker icon presented in the same time as the sound.'
        ))
    forced_listening = models.BooleanField(
        default=False,
        help_text=l_(
            'Check this box if you want to force the subject to listen to the whole sound before answering'
        ))

    def toDict(self):
        initial = super(AudioCatBlock, self).toDict()
        initial['choices'] = self.choices.split(',')
        initial['prompt'] = "<p class=\"prompt\"> {} </p>".format(self.prompt)
        initial['correct_feedback'] = self.correct_feedback
        initial['incorrect_feedback'] = self.incorrect_feedback
        initial['timeout_feedback'] = self.timeout_feedback
        return initial
Example #6
0
class SandboxForm(forms.Form):
    
    prefix='sandbox'
    def __init__(self, versions, *args, **kwargs):
        super(SandboxForm, self).__init__(*args, **kwargs)
        self.fields['version'].choices=versions
        
    version = forms.ChoiceField(label=l_("Which configuration would you like to try?"))
    
    format_choices =(
        ('json', 'JSON'),
        ('csv', 'CSV')
    )
    format = forms.ChoiceField(label=l_("Display data in format"), choices=format_choices)
Example #7
0
class GenericBlockAdmin(TranslationAdmin):
    
    class Media:
        js = (
            'modeltranslation/js/force_jquery.js',
            'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js',
            'modeltranslation/js/tabbed_translation_fields.js',
        )
        css = {
            'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
        }
    
    
    formfield_overrides = {MarkdownField: {'widget': AdminMarkdownWidget}}
    fieldsets=(
        (l_("Experimental structure options"), {'fields': (('global_settings_type', 'global_settings_id'), 'position_in_timeline', 'reprise')}),
        (l_("General parameters"), {'fields':('name', 'length', 'has_practice', 'extra_params')}),
        (l_("Saving & processing options"), {'fields':(('save_with',),)})
    )
    
    related_lookup_fields = {
        'generic' :[['global_settings_type', 'global_settings_id']]
    }
    
    def get_exp(self, obj):
        return obj.part_of.experiment.verbose_name
    
    
    list_display = ('name', 'get_parent_name', 'get_exp','position_in_timeline', 'has_practice')
    
    inlines = [ InstructionInline,]
    
    def get_form(self, request, obj=None, **kwargs):
        normal_form=  super(GenericBlockAdmin, self).get_form(request, obj=obj, **kwargs)
        normal_form.base_fields['global_settings_type'].queryset = ContentType.objects.filter(pk__in=get_subclass_ct_pk(BaseGlobalSetting))
        normal_form.base_fields['save_with'].queryset = ContentType.objects.filter(pk__in=get_subclass_ct_pk(BaseTrial))
        return normal_form

    def get_queryset(self, request):
        qs = super(GenericBlockAdmin, self).get_queryset(request)
        exps = get_allowed_exp_for_user(request)
        exps_ids = [exp.pk for exp in exps]
        allowed_ids = []
        # we need to deal with potentially invalid part_of generic relations, since they are not updated on related object deletion
        for block in qs:
            if block.part_of and block.part_of.experiment.pk in exps_ids:
                allowed_ids.append(block.pk)
        
        return qs.filter(pk__in=allowed_ids)
Example #8
0
class GenericGlobalSettingAdmin(admin.ModelAdmin):
    
    fieldsets=(
        (l_("Identification settings"), {'fields':(('name', 'experiment'))}),
        (l_("Basic parameters"), {'fields': ('max_consecutive_timeouts', 'max_total_timeouts', 'fixation_cross')}),
        (l_("Additional parameters"), {'fields':("extra_parameters",)})
    )
    
    list_display = ('name', 'experiment')
    
    def get_queryset(self, request):
        qs = super(GenericGlobalSettingAdmin, self).get_queryset(request)
        return qs.filter(experiment__in=get_allowed_exp_for_user(request))
    
    inlines = [ LinkedStimulusInline, ]
Example #9
0
class SurveyLikertAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Survey Likert parameters"), {'fields':(
            'preamble',
        )}),                               
    )
    inlines = [QuestionAdminInline]
Example #10
0
class SurveyTextAdmin(GenericBlockAdmin):
    inlines = [QuestionAdminInline]
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Survey Text task parameters"), {'fields':(
            'preamble',
        )}),                               
    )
Example #11
0
class BibServeProcess(Process):
    class Meta:
        verbose_name = l_('BibServe аккаунт')
        verbose_name_plural = l_('BibServe аккаунты')

    proposal = models.OneToOneField(ProposalProcess, verbose_name=l_('Заявка'))
    login = models.CharField(l_('Login'),
                             max_length=255,
                             null=True,
                             blank=True)
    password = models.CharField(l_('Password'),
                                max_length=255,
                                null=True,
                                blank=True)
    is_allowed_to_activate = models.BooleanField(l_('Is allowed to activate'),
                                                 default=False)
Example #12
0
 def clean(self):
     super(SignUpForm, self).clean()
     password = self.cleaned_data.get('password')
     confirm_password = self.cleaned_data.get('confirm_password')
     if password and password != confirm_password:
         self._errors['password'] = self.error_class(
             [l_("Passwords don\'t match")])
     return self.cleaned_data
Example #13
0
class SurveyMultiChoiceAdmin(GenericBlockAdmin):
    inlines = [QuestionAdminInline]
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Survey Multi Choice task parameters"), {'fields':(
            'preamble',
            'horizontal'
        )}),                               
    )
Example #14
0
class ReconstructionBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Reconstruction task parameters"), {'fields':(
            'starting_value',
            'step_size',
            'key_increase',
            'key_decrease'
        )}),                            
    )
Example #15
0
class AudioSimilarityBlock(BaseSettingBlock):
    type = 'audio-similarity'

    intervals = models.IntegerField(help_text=l_(
        "How many different choices are available on the slider. For example, 5 will limit the options to 5 different places on the slider"
    ))
    show_ticks = models.BooleanField(help_text=l_(
        "If true, then the slider will have tick marks indicating where the response options lie on the slider."
    ))
    timing_first_stim = models.IntegerField(
        help_text=l_("How long to play the first sound for in milliseconds."))
    timing_second_stim = models.IntegerField(help_text=l_(
        "How long to play the second sound for in milliseconds. -1 will show the stimulus until a response is made by the subject."
    ))
    timing_gap = models.IntegerField(
        help_text=l_("How long is the gap between the two sounds"),
        blank=True,
        null=True)

    timeout = models.IntegerField(help_text=l_(
        "time limit for the participant before the trial automatically advances"
    ),
                                  default=-1)
    timeout_message = models.CharField(
        max_length=128,
        blank=True,
        null=True,
        help_text=l_(
            'message to display if the participant takes too long to respond'))

    prompt = models.CharField(
        max_length=32,
        blank=True,
        help_text=l_(
            "Any content here will be displayed below the stimulus, as a reminder to the participant"
        ))
    labels = JSONCharField(
        max_length=64,
        help_text=l_(
            'An array of tags to label the slider. must be eclosed in square brackets. Each label must be enclosed in double quotation marks. Labels must be separated by a single comma.'
        ))

    def toDict(self):
        initial = super(AudioSimilarityBlock, self).toDict()
        initial['prompt'] = "<p class=\"prompt\"> {} </p>".format(self.prompt)
        initial[
            'timeout_message'] = "<p class=\"feedback error\">{} </p>".format(
                self.timeout_message)
        return initial
Example #16
0
class SingleAudioBlockAdmin(GenericBlockAdmin):
    
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Single Audio task parameters"), {'fields':(
            'prompt',
            'choices',
            'timing_response',
            'response_ends_trial'
        )}),                               
    )
Example #17
0
class BaseStimuli(models.Model):
    class Meta:
        abstract = True

    name = models.CharField(
        max_length=26,
        help_text=l_("A simple name for this particular stimuli pair"))
    #TODO: change the stim to be an actual fileField so that users can upload real images instead of a path.
    stimulus = models.CharField(
        max_length=256,
        help_text=l_(
            "The path to your stimuli file inside the static files folder we provided. Or it can be a short HTML string"
        ))

    def to_Dict(self):
        dct = {}
        dct['name'] = self.name
        dct['stimulus'] = self.stimulus
        return json.dumps(dct)
Example #18
0
class MultiStimMultiResponseBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Multi Stim Multi Response task parameters"), {'fields':(
            'is_html',
            'prompt',
            'choices',
            'timing_stim',
            'timing_response',
            'response_ends_trial'           
        )}),                               
    )
Example #19
0
class AnimationBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Animation task parameters"), {'fields':(
            'choices',
            'prompt',
            'frame_time',
            'frame_isi',
            'sequence_reps'
            
        )}),                               
    )
Example #20
0
class ReviewForm(forms.ModelForm):
    title = forms.CharField(
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        max_length=255,
        label=l_('Title'))
    description = forms.CharField(
        widget=forms.Textarea(attrs={
            'class': 'form-control expanding',
            'rows': '4'
        }),
        max_length=500,
        required=False,
        label=l_('Description'))

    class Meta:
        model = Review
        fields = [
            'title',
            'description',
        ]
Example #21
0
class FreeSortBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Free Sort task parameters"), {'fields':(
            'stim_height',
            'stim_width',
            'sort_area_height',
            'sort_area_width',
            'prompt',
            'prompt_location'
        )}),                               
    )
Example #22
0
class AudioABXBlock(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Audio ABX task parameters"), {'fields':(
            'choices',
            'prompt',
            'timeout',
            'timeout_feedback',
            'timing_gap',
            'key_first',
            'key_second'       
        )}),                               
    )     
Example #23
0
class Category(models.Model):
    class Meta:
        verbose_name_plural = 'Categories'

    name = models.CharField(max_length=16)
    keycode = models.IntegerField(help_text=l_(
        "The character keycode representing the correct response for this category. See: http://www.cambiaresearch.com/articles/15/javascript-key-codes"
    ))
    setting = models.ForeignKey(SimCatGlobalSetting)

    def __str__(self):
        return self.name
Example #24
0
class SameDifferentBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Same Different task parameters"), {'fields':(
            'is_html',
            'same_key',
            'different_key',
            'timing_first_stim',
            'timing_gap',
            'timing_second_stim',
            'prompt'
        )}),                            
    )
Example #25
0
class Correction(models.Model):
    """
    Модель, в которой хранятся данные о том, что должен откорректировать Клиент в своей заявке.
    По логике приложения, в один момент времени у одной Заявки
    может быть только одна активная Корректировка для одного этапа согласования.
    Чтобы закрепить это утверждение на уровне БД, создан триггер only_one_active_correction_for_proposal_and_task.
    См. main.migrations.0002_add_constraint
    """
    class Meta:
        verbose_name = l_('Корректировка')
        verbose_name_plural = l_('Корректировка')

    proposal = models.ForeignKey(ProposalProcess, verbose_name=l_('Заявка'))
    task = models.ForeignKey(
        'viewflow.Task',
        verbose_name=l_('На каком шаге создана Корректировка'),
    )
    for_step = models.CharField(
        verbose_name=l_('Для какого шага создана Корректировка'),
        max_length=255,
        null=True,
        blank=True,
    )
    reviewed_version = models.ForeignKey(
        'reversion.Version',
        verbose_name=l_('К какой версии заявки относятся корректировки'),
        related_name='corrections_reviewed')
    fixed_in_version = models.ForeignKey(
        'reversion.Version',
        verbose_name=l_('В какой версии корректировки исправленны'),
        related_name='corrections_fixed',
        null=True,
        blank=True,
    )
    data = JSONField(l_('Данные о коррекции'))
    is_active = models.BooleanField(l_('Корректировки актуальны?'),
                                    default=True,
                                    db_index=True)
    created = models.DateTimeField(l_('Дата создания'), auto_now_add=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              blank=True,
                              null=True,
                              db_index=True,
                              on_delete=models.CASCADE,
                              verbose_name=l_('Создатель'))
Example #26
0
class Lobby(models.Model):
    
    experiment=models.OneToOneField(Experiment)
    content = MarkdownField(help_text=l_("Write here the content that people will see on the homepage of the experiment, before choosing to do it or not"))
    
    def render(self):
        if self.content is not None:
            return markdown.markdown(self.content)
        else:
            return l_("No homepage information has been set by the experimenters")
        
    def __str__(self):
        return l_("Welcome page for %s") % self.experiment.verbose_name
Example #27
0
class Debrief(models.Model):
    
    experiment = models.OneToOneField(Experiment)
    content = MarkdownField(help_text=l_("write the debrief content you'd like to show to subjects after the experiment."))
    
    def render(self):
        if self.content is not None:
            return markdown.markdown(self.content)
        else:
            return l_("No debrief information has been set by the experimenters")
        
    def __str__(self):
        return l_("Debrief for %s") % self.experiment.verbose_name
Example #28
0
class SynonymForm(forms.ModelForm):

    description = forms.CharField(
        widget=forms.TextInput(attrs={'class': 'form-control input-sm'}),
        max_length=200,
        required=True,
        label=l_('Description'))

    class Meta:
        model = Keyword
        fields = [
            'description',
        ]
Example #29
0
class AudioABXBlock(BaseSettingBlock):
    type = 'audio-abx'
    choices = choices = models.CharField(
        blank=True,
        max_length=1024,
        help_text=l_(
            "Choose the keys associated for all categories. You have separate them with a coma and non spaces."
        ))
    timeout = models.IntegerField(help_text=l_(
        "time limit for the participant before the trial automatically advances"
    ),
                                  default=-1)
    timeout_feedback = models.CharField(
        max_length=64,
        blank=True,
        help_text=l_(
            "Any content here will be displayed as a feedback given to the participants when he takes too long to answer the question if there is a timeout"
        ))
    timing_feedback = models.IntegerField(help_text=l_(
        "How long to show the feedback message for in milliseconds."),
                                          default=1000,
                                          blank=True)
    timing_gap = models.IntegerField(
        help_text=l_("How long to leave blank between the sounds."))
    prompt = models.CharField(
        max_length=256,
        blank=True,
        help_text=l_(
            "Any content here will be displayed below the stimulus, as a reminder to the participant"
        ))
    key_first = models.CharField(
        max_length=3,
        blank=True,
        help_text=l_(
            "The key that the person have to press if the first sound is the same as the last"
        ))
    key_second = models.CharField(
        max_length=3,
        blank=True,
        help_text=l_(
            "The key that the person have to press if it is the second sound that is the same as the last"
        ))

    def toDict(self):
        initial = super(AudioABXBlock, self).toDict()
        initial['choices'] = self.choices.split(',')
        initial['prompt'] = "<p class=\"prompt\"> {} </p>".format(self.prompt)
        initial['timeout_feedback'] = self.timeout_feedback
        return initial
Example #30
0
class CategorizeAnimationBlockAdmin(GenericBlockAdmin):
    fieldsets = GenericBlockAdmin.fieldsets + (
        (l_("Categorize animation task parameters"), {'fields':(
            'choices',
            'correct_text',
            'incorrect_text',
            'frame_time',
            'sequence_reps',
            'allow_response_before_complete',
            'prompt',
            'timing_feedback_duration'
        )}),                               
    )
Example #31
0
 def __str__(self):
     # Translators: %s represents the name of this object, so in French you should make it go after the word configuration since its name is kind of an adjective
     return l_("%s configuration") % self.name
Example #32
0
 def get_parent_name(self):
     
     if self.part_of is not None and hasattr(self.part_of, 'name'):
         return self.part_of.name
     else:
         return l_("No name for the containing global config")
Example #33
0
 def __str__(self):
     # Translators: 
     return l_('Exp. block "')+self.name+'"'
Example #34
0
 def __str__(self):
     return l_("Welcome page for %s") % self.experiment.verbose_name
Example #35
0
 def render(self):
     if self.content is not None:
         return markdown.markdown(self.content)
     else:
         return l_("No homepage information has been set by the experimenters")
Example #36
0
 def __str__(self):
     return l_("Debrief for %s") % self.experiment.verbose_name
Example #37
0
]

MEDIA_URL = '/media/'

#django-allauth settings
ACCOUNT_AUTHENTICATION_METHOD= "username_email"
LOGIN_REDIRECT_URL = "/"
# SOCIALACCOUNT_ADAPTER = 'expManager.adapters.SocialAuthAdapter'
ACCOUNT_EMAIL_VERIFICATION = 'optional'
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
)

ACCOUNT_EMAIL_REQUIRED = True
# email sending settings
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = get_secret("GMAIL_ACCOUNT_NAME")
EMAIL_HOST_PASSWORD = get_secret("GMAIL_ACCOUNT_PASSWORD")
DEFAULT_FROM_EMAIL = get_secret("GMAIL_ACCOUNT_NAME")


# Markdown
MARKDOWN_EDITOR_SKIN = 'simple'

# Grappelli options

GRAPPELLI_ADMIN_TITLE = l_("Web laboratory dashboard")