Skip to content
Snippets Groups Projects
Select Git revision
  • 8055b891832c17b8f9b58131e92677ed9dd6dd43
  • main default protected
  • ardc-deploy20250618-hotfixes
  • ardc-main
  • ardc-379-improve-tags-filter
  • 379-improve-tags-filter
  • 103-improve-print-style
  • upgrade
  • ardc-334-overdue-reports
  • try-ci
  • ardc-389-de-regex-filetypes
  • ardc-279-require-organization-name-on-application
  • ardc-281-require-review-expertise-field-on-draft
  • ots-main
  • smex-production
  • request-review-workflow
  • lfc-main
  • smex-main
  • extension-ots-wagtail-email-configuration
  • enhancement/gh-3288-change-help-to-rich-text
  • new-workflow
  • ardc-deploy-20250722
  • ardc-deploy-20250717
  • ardc-deploy-20250618
  • ardc-deploy-20250518
  • ardc-deploy-20250514
  • ardc-deploy-20250513
  • ardc-deploy-20250321
  • ardc-deploy-20250204
  • v5.23.0
  • ardc-deploy-20250107
  • v5.22.0
  • ardc-deploy-20241220
  • v5.21.1
  • v5.21.0
  • v5.20.0
  • v5.19.0
  • ardc-deploy-20241210
  • ardc-deploy-20241122
  • ardc-deploy-20241107
  • v5.18.0
41 results

urls.py

Blame
  • forms.py 10.88 KiB
    from django import forms
    from django.utils.text import mark_safe, slugify
    from django.utils.translation import ugettext_lazy as _
    from django_select2.forms import Select2Widget
    
    from opentech.apply.categories.models import MetaCategory
    from opentech.apply.users.models import User
    
    from .models import AssignedReviewers, ApplicationSubmission, ReviewerRole
    from .utils import render_icon
    from .widgets import Select2MultiCheckboxesWidget, MetaCategorySelect2Widget
    from .workflow import get_action_mapping
    
    
    class ProgressSubmissionForm(forms.ModelForm):
        action = forms.ChoiceField(label='Take action')
    
        class Meta:
            model = ApplicationSubmission
            fields: list = []
    
        def __init__(self, *args, **kwargs):
            self.user = kwargs.pop('user')
            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 BatchProgressSubmissionForm(forms.Form):
        action = forms.ChoiceField(label='Take action')
        submissions = forms.CharField(widget=forms.HiddenInput(attrs={'class': 'js-submissions-id'}))
    
        def __init__(self, *args, round=None, **kwargs):
            self.user = kwargs.pop('user')
            super().__init__(*args, **kwargs)
            workflow = round and round.workflow
            self.action_mapping = get_action_mapping(workflow)
            choices = [(action, detail['display']) for action, detail in self.action_mapping.items()]
            self.fields['action'].choices = choices
    
        def clean_submissions(self):
            value = self.cleaned_data['submissions']
            submission_ids = [int(submission) for submission in value.split(',')]
            return ApplicationSubmission.objects.filter(id__in=submission_ids)
    
        def clean_action(self):
            value = self.cleaned_data['action']
            action = self.action_mapping[value]['transitions']
            return action
    
    
    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
            if self.user.is_apply_staff:
                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().only('pk', 'full_name'),
            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')
            super().__init__(*args, **kwargs)
    
            assigned_roles = {
                assigned.role: assigned.reviewer
                for assigned in self.instance.assigned.filter(
                    role__isnull=False
                )
            }
    
            self.role_fields = {}
            field_data = make_role_reviewer_fields()
    
            for data in field_data:
                field_name = data['field_name']
                self.fields[field_name] = data['field']
                self.role_fields[field_name] = data['role']
                self.fields[field_name].initial = assigned_roles.get(data['role'])
    
            submitted_reviewers = User.objects.filter(
                id__in=self.instance.assigned.reviewed().values('reviewer'),
            )
    
            if self.can_alter_external_reviewers(self.instance, self.user):
    
                reviewers = self.instance.reviewers.all().only('pk')
                self.prepare_field(
                    'reviewer_reviewers',
                    initial=reviewers,
                    excluded=submitted_reviewers
                )
    
                # Move the non-role reviewers field to the end of the field list
                self.fields.move_to_end('reviewer_reviewers')
            else:
                self.fields.pop('reviewer_reviewers')
    
        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)
    
        def clean(self):
            cleaned_data = super().clean()
            role_reviewers = [
                user
                for field, user in self.cleaned_data.items()
                if field in self.role_fields
            ]
    
            # 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.'))
    
            return cleaned_data
    
        def save(self, *args, **kwargs):
            instance = super().save(*args, **kwargs)
            """
            1. Update role reviewers
            2. Update non-role reviewers
                2a. Remove those not on form
                2b. Add in any new non-role reviewers selected
            """
    
            # 1. Update role reviewers
            assigned_roles = {
                role: self.cleaned_data[field]
                for field, role in self.role_fields.items()
            }
            for role, reviewer in assigned_roles.items():
                if reviewer:
                    AssignedReviewers.objects.update_role(role, reviewer, instance)
    
            # 2. Update non-role reviewers
            # 2a. Remove those not on form
            if self.can_alter_external_reviewers(self.instance, self.user):
                reviewers = self.cleaned_data.get('reviewer_reviewers')
                assigned_reviewers = instance.assigned.without_roles()
                assigned_reviewers.never_tried_to_review().exclude(
                    reviewer__in=reviewers
                ).delete()
    
                remaining_reviewers = assigned_reviewers.values_list('reviewer_id', flat=True)
    
                # 2b. Add in any new non-role reviewers selected
                AssignedReviewers.objects.bulk_create_reviewers(
                    [reviewer for reviewer in reviewers if reviewer.id not in remaining_reviewers],
                    instance,
                )
    
            return instance
    
    
    class BatchUpdateReviewersForm(forms.Form):
        submissions = forms.CharField(widget=forms.HiddenInput(attrs={'class': 'js-submissions-id'}))
    
        def __init__(self, *args, user=None, round=None, **kwargs):
            super().__init__(*args, **kwargs)
    
            self.role_fields = {}
            field_data = make_role_reviewer_fields()
    
            for data in field_data:
                field_name = data['field_name']
                self.fields[field_name] = data['field']
                self.role_fields[field_name] = data['role']
    
        def clean_submissions(self):
            value = self.cleaned_data['submissions']
            submission_ids = [int(submission) for submission in value.split(',')]
            return ApplicationSubmission.objects.filter(id__in=submission_ids)
    
        def clean(self):
            cleaned_data = super().clean()
            role_reviewers = [
                user
                for field, user in self.cleaned_data.items()
                if field in self.role_fields
            ]
    
            # 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.'))
    
            return cleaned_data
    
        def save(self):
            submissions = self.cleaned_data['submissions']
            assigned_roles = {
                role: self.cleaned_data[field]
                for field, role in self.role_fields.items()
            }
            for role, reviewer in assigned_roles.items():
                if reviewer:
                    AssignedReviewers.objects.update_role(role, reviewer, *submissions)
    
            return None
    
    
    def make_role_reviewer_fields():
        role_fields = []
        staff_reviewers = User.objects.staff().only('full_name', 'pk')
    
        for role in ReviewerRole.objects.all().order_by('order'):
            field_name = 'role_reviewer_' + slugify(str(role))
            field = forms.ModelChoiceField(
                queryset=staff_reviewers,
                widget=Select2Widget(attrs={
                    'data-placeholder': 'Select a reviewer',
                }),
                required=False,
                label=mark_safe(render_icon(role.icon) + f'{role.name} Reviewer'),
            )
            role_fields.append({
                'role': role,
                'field': field,
                'field_name': field_name,
            })
    
        return role_fields
    
    
    class UpdatePartnersForm(forms.ModelForm):
        partner_reviewers = forms.ModelMultipleChoiceField(
            queryset=User.objects.partners(),
            widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Partners'}),
            label='Partners',
            required=False,
        )
    
        class Meta:
            model = ApplicationSubmission
            fields: list = []
    
        def __init__(self, *args, **kwargs):
            kwargs.pop('user')
            super().__init__(*args, **kwargs)
            partners = self.instance.partners.all()
            self.submitted_partners = User.objects.partners().filter(id__in=self.instance.reviews.values('author'))
    
            partner_field = self.fields['partner_reviewers']
            partner_field.queryset = partner_field.queryset.exclude(id__in=self.submitted_partners)
            partner_field.initial = partners
    
        def save(self, *args, **kwargs):
            instance = super().save(*args, **kwargs)
    
            instance.partners.set(
                self.cleaned_data['partner_reviewers'] |
                self.submitted_partners
            )
            return instance
    
    
    class MetaCategoryMultipleChoiceField(forms.ModelMultipleChoiceField):
        def label_from_instance(self, obj):
            depth_line = '-' * (obj.get_depth() - 2)
            label = "{} {}".format(depth_line, super().label_from_instance(obj))
            return {'label': label, 'disabled': not obj.is_leaf()}
    
    
    class UpdateMetaCategoriesForm(forms.ModelForm):
        meta_categories = MetaCategoryMultipleChoiceField(
            queryset=None,  # updated in init method
            widget=MetaCategorySelect2Widget(attrs={'data-placeholder': 'Meta categories'}),
            label='Meta categories',
            required=False,
            help_text='Meta categories are hierarchical in nature, - highlights the depth in the tree.',
        )
    
        class Meta:
            model = ApplicationSubmission
            fields: list = []
    
        def __init__(self, *args, **kwargs):
            kwargs.pop('user')
            super().__init__(*args, **kwargs)
            self.fields['meta_categories'].queryset = MetaCategory.get_root_descendants()