Skip to content
Snippets Groups Projects
forms.py 6.51 KiB
Newer Older
  • Learn to ignore specific revisions
  • Todd Dembrey's avatar
    Todd Dembrey committed
    from django import forms
    
    Erin Mullaney's avatar
    Erin Mullaney committed
    from django.utils.text import slugify
    
    Erin Mullaney's avatar
    Erin Mullaney committed
    from django.utils.translation import ugettext_lazy as _
    
    from opentech.apply.users.models import User
    
    
    from .models import ApplicationSubmission, AssignedReviewers, ReviewerRole
    
    Erin Mullaney's avatar
    Erin Mullaney committed
    from .widgets import Select2MultiCheckboxesWidget, Select2IconWidget
    
    Todd Dembrey's avatar
    Todd Dembrey committed
    class ProgressSubmissionForm(forms.ModelForm):
    
        action = forms.ChoiceField(label='Take action')
    
    Todd Dembrey's avatar
    Todd Dembrey committed
        class Meta:
            model = ApplicationSubmission
    
    Todd Dembrey's avatar
    Todd Dembrey committed
            fields: list = []
    
    Todd Dembrey's avatar
    Todd Dembrey committed
        def __init__(self, *args, **kwargs):
    
            self.user = kwargs.pop('user')
    
    Todd Dembrey's avatar
    Todd Dembrey committed
            super().__init__(*args, **kwargs)
    
            choices = list(self.instance.get_actions_for_user(self.user))
    
            action_field = self.fields['action']
            action_field.choices = choices
    
            self.should_show = bool(choices)
    
    class ScreeningSubmissionForm(forms.ModelForm):
    
        class Meta:
            model = ApplicationSubmission
    
            fields = ('screening_status',)
    
    
        def __init__(self, *args, **kwargs):
            self.user = kwargs.pop('user')
            super().__init__(*args, **kwargs)
    
            self.should_show = False
    
                self.should_show = True
    
    class UpdateSubmissionLeadForm(forms.ModelForm):
        class Meta:
            model = ApplicationSubmission
            fields = ('lead',)
    
        def __init__(self, *args, **kwargs):
    
            kwargs.pop('user')
    
            super().__init__(*args, **kwargs)
    
            lead_field = self.fields['lead']
            lead_field.label = f'Update lead from { self.instance.lead } to'
            lead_field.queryset = lead_field.queryset.exclude(id=self.instance.lead.id)
    
    
    
    class UpdateReviewersForm(forms.ModelForm):
    
        reviewer_reviewers = forms.ModelMultipleChoiceField(
            queryset=User.objects.reviewers().exclude(id__in=User.objects.staff()),
            widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Reviewers'}),
            label='Reviewers',
            required=False,
        )
    
    
        class Meta:
            model = ApplicationSubmission
            fields: list = []
    
        def __init__(self, *args, **kwargs):
    
            self.user = kwargs.pop('user')
    
    Erin Mullaney's avatar
    Erin Mullaney committed
            self.request = kwargs.pop('request', None)
    
            super().__init__(*args, **kwargs)
    
            # All submitted reviews by non-role reviewers
    
            self.submitted_reviewers = User.objects.filter(id__in=self.instance.reviews.values('author'))
    
            self.submitted_reviewers = self.submitted_reviewers.exclude(
                id__in=AssignedReviewers.objects.role_reviewers_by_submission(self.instance).values('reviewer'))
    
    
            if self.can_alter_external_reviewers(self.instance, self.user):
    
                reviewers = self.instance.reviewers.all()
                self.prepare_field(
                    'reviewer_reviewers',
                    initial=reviewers,
                    excluded=self.submitted_reviewers
                )
    
            else:
                self.fields.pop('reviewer_reviewers')
    
    
            staff_reviewers = User.objects.staff()
    
    
            assigned_roles = {
                assigned.role: assigned.reviewer
    
                for assigned in self.instance.assigned.filter(
    
            for role in ReviewerRole.objects.all().order_by('order'):
    
    Erin Mullaney's avatar
    Erin Mullaney committed
                field_name = 'reviewer_role_' + slugify(str(role))
    
                self.roles[field_name] = role
    
    
                self.fields[field_name] = forms.ModelChoiceField(
    
                    queryset=staff_reviewers,
    
                    widget=Select2IconWidget(attrs={
    
                        'data-placeholder': 'Select a reviewer', 'icon': role.icon
                    }),
    
                    required=False,
    
                    label=f'{role.name} Reviewer',
    
                # Pre-populate form field
    
                self.fields[field_name].initial = assigned_roles.get(role)
    
        def prepare_field(self, field_name, initial, excluded):
            field = self.fields[field_name]
            field.queryset = field.queryset.exclude(id__in=excluded)
            field.initial = initial
    
        def can_alter_external_reviewers(self, instance, user):
            return instance.stage.has_external_review and (user == instance.lead or user.is_superuser)
    
    
    Erin Mullaney's avatar
    Erin Mullaney committed
        def clean(self):
            cleaned_data = super().clean()
    
            role_reviewers = [
                user
                for field, user in self.cleaned_data.items()
                if field != 'reviewer_reviewers'
            ]
    
            # If any of the users match and are set to multiple roles, throw an error
    
            if len(role_reviewers) != len(set(role_reviewers)) and any(role_reviewers):
    
                self.add_error(None, _('Users cannot be assigned to multiple roles.'))
    
    Erin Mullaney's avatar
    Erin Mullaney committed
    
            return cleaned_data
    
    
        def save(self, *args, **kwargs):
            instance = super().save(*args, **kwargs)
    
    
            assigned_roles = {
                role: self.cleaned_data[field]
                for field, role in self.roles.items()
            }
    
    
            assigned_staff = instance.staff_not_reviewed.filter(
    
                assignedreviewers__submission=instance,
                assignedreviewers__role__isnull=True
            ).exclude(
    
                id__in=[user.id for user in assigned_roles.values() if user]
    
            if self.can_alter_external_reviewers(self.instance, self.user):
                reviewers = self.cleaned_data.get('reviewer_reviewers')
            else:
                reviewers = instance.reviewers_not_reviewed
    
    
            current_reviewers = set(reviewers | self.submitted_reviewers | assigned_staff)
    
            # Clear out old reviewers
            instance.assigned.filter(role=None).exclude(reviewer__in=current_reviewers).delete()
    
            AssignedReviewers.objects.bulk_create(
                AssignedReviewers(
    
                    reviewer=reviewer,
                ) for reviewer in current_reviewers
    
                if reviewer not in instance.reviewers.filter(assignedreviewers__role=None)
    
            for role, reviewer in assigned_roles.items():
    
                if reviewer:
                    AssignedReviewers.objects.update_or_create(
                        submission=instance,
                        role=role,
                        defaults={'reviewer': reviewer},
                    )
    
    
    class BatchUpdateReviewersForm(forms.Form):
        staff_reviewers = forms.ModelMultipleChoiceField(
            queryset=User.objects.staff(),
            widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Staff'}),
        )
        submission_ids = forms.CharField(widget=forms.HiddenInput())
    
    
        def clean_submission_ids(self):
            value = self.cleaned_data['submission_ids']
            return [int(submission) for submission in value.split(',')]