Skip to content
Snippets Groups Projects
forms.py 9.57 KiB
import logging

from crispy_forms.bootstrap import Tab, TabHolder
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout
from django import forms
from django.contrib.auth.models import User
from django.contrib.postgres.forms import HStoreField
from django.urls import resolve
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _

from .models import (Alert, AppSettings, DataFile, DataSet, Institution, Lab,
                     Profile, ShareGroup)

logger = logging.getLogger('debug')


class BaseNestedFormSet(forms.BaseFormSet):
    def is_valid(self):
        result = super().is_valid()

        if self.is_bound:
            for form in self.forms:
                if hasattr(form, 'nested'):
                    result = result and form.nested.is_valid()

        return result


class BaseInlineNestedFormSet(forms.BaseInlineFormSet):
    def is_valid(self):
        result = super().is_valid()

        if self.is_bound:
            for form in self.forms:
                if hasattr(form, 'nested'):
                    result = result and form.nested.is_valid()

        return result

    def save(self, commit=True):
        result = super().save(commit=commit)

        for form in self.forms:
            if hasattr(form, 'nested'):
                if not self._should_delete_form(form):
                    form.nested.save(commit=commit)

        return result


class AlertForm(forms.ModelForm):
    class Meta:
        model = Alert
        fields = ['id', 'message_en', 'message_fr', 'start', 'end']
        labels = {
            'message_en': _('Message (English)'),
            'message_fr': _('Message (French)'),
            'start': _('Start'),
            'end': _('End')
        }
        widgets = {
            'message_en': forms.Textarea(attrs={'rows': 3}),
            'message_fr': forms.Textarea(attrs={'rows': 3}),
        }


class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if self.instance.pk and self.instance.profile.accountname:
            self.fields['first_name'].disabled = True
            self.fields['last_name'].disabled = True
            self.fields['email'].disabled = True

        else:
            self.fields['first_name'].required = True
            self.fields['last_name'].required = True
            self.fields['email'].required = True


class LDAPUserForm(forms.Form):
    accountname = forms.CharField(max_length=32, required=True, label=_('LDAP ID'))


class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude = ('user', 'accountname')
        widgets = {'labs': forms.CheckboxSelectMultiple()}


class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude = ('user',)
        widgets = {'labs': forms.CheckboxSelectMultiple()}
        labels = {
            'accountname': _('LDAP ID')
        }

    field_order = ['accountname']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if hasattr(self.instance, 'user') and self.instance.accountname:
            self.fields['labs'].widget = forms.CheckboxSelectMultiple(attrs={'disabled': 'disabled'})
            self.fields['accountname'].widget.attrs['readonly'] = True


class InstitutionForm(forms.ModelForm):
    class Meta:
        model = Institution
        fields = ('__all__')


class DataFileForm(forms.ModelForm):
    class Meta:
        model = DataFile
        fields = ('filename', 'annotations', 'lab')
        help_texts = {'annotations': _('Pro Tip: You can also drop a tab separated value file onto this field')}

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['lab'].choices = [('', '----------')]
        if request.user.is_staff:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in Lab.objects.all()]
        else:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in request.user.profile.labs.all()]


class BasicDataFileForm(forms.ModelForm):
    class Meta:
        model = DataFile
        fields = ('file',)


class DataFileServletUploadForm(forms.ModelForm):
    dataset = forms.ModelChoiceField(required=False, label=_('Attach uploaded files to this dataset:'), queryset=DataSet.objects.all())
    as_user = forms.ModelChoiceField(required=False, label=_('Upload as user:'), queryset=Profile.objects.all())

    class Meta:
        model = DataFile
        fields = ('file', 'annotations', 'lab')

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['lab'].choices = [('', '----------')]
        if request.user.is_staff:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in Lab.objects.all()]
        else:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in request.user.profile.labs.all()]

        if not request.user.is_staff:
            self.fields['dataset'].queryset = DataSet.objects.accessible_to_profile(request.user.profile).all()


class DataFileAnnotationForm(forms.Form):
    dropzone_files = forms.CharField(required=False, widget=forms.HiddenInput)
    annotations = HStoreField(required=False, label=_('Attach these annotations with the uploaded files:'), help_text=_('Pro Tip: You can also drop a tab separated value file onto this field'))
    lab = forms.ChoiceField(required=False, label=_('Attach uploaded files to this lab:'))

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['lab'].choices = [('', '----------')]
        if request.user.is_staff:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in Lab.objects.all()]
        else:
            self.fields['lab'].choices += [(lab.id, lab.name) for lab in request.user.profile.labs.all()]


class BatchAddDataFileAnnotationForm(forms.Form):
    datafiles = forms.MultipleChoiceField(required=True, widget=forms.HiddenInput)
    annotations = HStoreField(required=True, label=_('Add/Update the following annotations for the selected files'), help_text=_('Pro Tip: You can also drop a tab separated value file onto this field'))


class BatchRemoveDataFileAnnotationForm(forms.Form):
    datafiles = forms.MultipleChoiceField(required=True, widget=forms.HiddenInput)
    annotations = forms.MultipleChoiceField(required=True, label=_('Remove the following annotations from the selected files'))


class DataSetForm(forms.ModelForm):
    class Meta:
        model = DataSet
        fields = ('name', 'share_profiles', 'share_labs', 'share_groups', 'files')
        labels = {
            'name': _('Name'),
            'share_profiles': _('Share with these users'),
            'share_labs': _('Share with these labs'),
            'share_groups': _('Share with these groups'),
            'files': _('Files')
        }


class DataSetDisplayFieldsForm(forms.ModelForm):
    options = forms.MultipleChoiceField(
        required=False, widget=forms.CheckboxSelectMultiple,
        label=_('Choose the fields you would like to use when displaying the DataSet details'),
        help_text=_('Pro Tip: The order in which you click the options will determine their display order')
    )

    class Meta:
        model = DataSet
        fields = ('display_fields',)
        labels = {'display_fields': _('Manually rearrange the field names to alter their display order')}
        help_texts = {'display_fields': _('Pro Tip: Field names should be comma separated')}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        choice_fields = set()
        for f in self.instance.files.all():
            if f.annotations:
                choice_fields.update([k for k in f.annotations.keys()])
        self.fields['options'].choices = [
            ('name', 'name'), ('size', 'size'),
            ('upload_timestamp', 'upload_timestamp'), ('uploaded_by', 'uploaded_by')
        ] + [(f, f) for f in choice_fields]

        if self.instance.display_fields:
            self.fields['options'].initial = [df for df in self.instance.display_fields['fields'].split(', ')]

        self.helper = FormHelper(self)
        self.helper.form_tag = False
        self.helper.use_custom_control = True
        self.helper.layout = Layout(
            TabHolder(
                Tab(
                    ugettext('Display Options'),
                    'options'
                ),
                Tab(
                    ugettext('Manual override'),
                    'display_fields',
                )
            )
        )


class LabForm(forms.ModelForm):
    class Meta:
        model = Lab
        fields = ('__all__')


class ShareGroupForm(forms.ModelForm):
    class Meta:
        model = ShareGroup
        fields = ('name', 'profiles')


class LabSelectionForm(forms.Form):
    lab = forms.ChoiceField(required=True)
    redirect_to = forms.CharField(max_length=256, required=True, widget=forms.HiddenInput)

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if request.user.is_authenticated:
            self.fields['lab'].choices = [(lab.id, lab.name) for lab in request.user.profile.labs.all()]
            self.fields['lab'].initial = request.session.get('active_lab_id')

        self.fields['redirect_to'].initial = resolve(request.path_info).url_name

        self.helper = FormHelper()
        self.helper.form_show_labels = False


class AppSettingsForm(forms.ModelForm):
    class Meta:
        model = AppSettings
        fields = ('__all__')