def clean()

in src/olympia/reviewers/forms.py [0:0]


    def clean(self):
        super().clean()
        if self.cleaned_data.get('attachment_input') and self.cleaned_data.get(
            'attachment_file'
        ):
            self.add_error('attachment_input', 'Cannot upload both a file and input.')
        selected_action = self.cleaned_data.get('action')
        # If the user select a different type of job before changing actions there could
        # be non-appeal jobs selected as cinder_jobs_to_resolve under resolve_appeal_job
        # action, or appeal jobs under resolve_reports_job action. So filter them out.
        if selected_action == 'resolve_appeal_job':
            self.cleaned_data['cinder_jobs_to_resolve'] = [
                job
                for job in self.cleaned_data.get('cinder_jobs_to_resolve', ())
                if job.is_appeal
            ]
        elif selected_action == 'resolve_reports_job':
            self.cleaned_data['cinder_jobs_to_resolve'] = [
                job
                for job in self.cleaned_data.get('cinder_jobs_to_resolve', ())
                if not job.is_appeal
            ]
        if self.cleaned_data.get('cinder_jobs_to_resolve') and self.cleaned_data.get(
            'cinder_policies'
        ):
            actions = self.helper.handler.get_decision_actions_from_policies(
                self.cleaned_data.get('cinder_policies')
            )
            if len(actions) == 0:
                self.add_error(
                    'cinder_policies',
                    'No policies selected with an associated cinder action.',
                )
            elif len(actions) > 1:
                self.add_error(
                    'cinder_policies',
                    'Multiple policies selected with different cinder actions.',
                )

        if self.helper.actions.get(selected_action, {}).get('delayable'):
            delayed_rejection = self.cleaned_data.get('delayed_rejection')
            delayed_rejection_date = self.cleaned_data.get('delayed_rejection_date')
            # Extra required checks are added here because the NullBooleanField
            # otherwise accepts missing data as `None`.
            if 'delayed_rejection' not in self.data:
                self.add_error(
                    'delayed_rejection',
                    self.fields['delayed_rejection'].error_messages['required'],
                )
            elif delayed_rejection and not self.data.get('delayed_rejection_date'):
                # In case reviewer selected delayed rejection option and
                # somehow cleared the date widget, raise an error.
                self.add_error(
                    'delayed_rejection_date',
                    self.fields['delayed_rejection'].error_messages['required'],
                )
            elif (
                selected_action == 'change_or_clear_pending_rejection_multiple_versions'
                and delayed_rejection
                and delayed_rejection_date
                and self.cleaned_data.get('versions')
            ):
                distinct_pending_rejection_dates = (
                    self.cleaned_data['versions']
                    .values_list('reviewerflags__pending_rejection')
                    .distinct()
                    .count()
                )
                if distinct_pending_rejection_dates > 1:
                    self.add_error(
                        'versions',
                        forms.ValidationError(
                            'Can only change the delayed rejection date of multiple '
                            'versions at once if their pending rejection dates are all '
                            'the same.'
                        ),
                    )

        return self.cleaned_data