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 = ('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__')