Newer
Older
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.utils.image import generate_image_tag
from .models import ApplicationSubmission, ReviewerRole
from .utils import render_icon, save_reviewers_with_roles
from .widgets import Select2MultiCheckboxesWidget
from .workflow import get_action_mapping
action = forms.ChoiceField(label='Take action')
self.user = kwargs.pop('user')
choices = list(self.instance.get_actions_for_user(self.user))
action_field = self.fields['action']
action_field.choices = 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']
Erin Mullaney
committed
class ScreeningSubmissionForm(forms.ModelForm):
class Meta:
model = ApplicationSubmission
Erin Mullaney
committed
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.should_show = False
Fredrik Jonsson
committed
if self.user.is_apply_staff:
self.should_show = True
Erin Mullaney
committed
class UpdateSubmissionLeadForm(forms.ModelForm):
class Meta:
model = ApplicationSubmission
fields = ('lead',)
def __init__(self, *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')
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'])
self.submitted_reviewers = User.objects.filter(
id__in=self.instance.reviews.values('author'),
)
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=self.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)
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.'))
def save(self, *args, **kwargs):
instance = super().save(*args, **kwargs)
<<<<<<< variant A
"""
1. Update role reviewers
2. Update non-role reviewers
2a. Remove those not on form
2b. Add in any new non-role reviewers selected
3. Add in anyone who has already reviewed but who is not selected as a reviewer on the form
"""
# 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.filter(submission=instance, role=role).delete()
AssignedReviewers.objects.update_or_create(submission=instance, reviewer=reviewer, defaults={'role': role})
# 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.exclude(
reviewer__in=reviewers | self.submitted_reviewers
remaining_reviewers = assigned_reviewers.values_list('reviewer_id', flat=True)
# 2b. Add in any new non-role reviewers selected
AssignedReviewers.objects.bulk_create(
AssignedReviewers(
) for reviewer in reviewers
if reviewer.id not in remaining_reviewers
>>>>>>> variant B
======= end
instance = save_reviewers_with_roles(
submission=instance,
role_fields=self.role_fields,
cleaned_data=self.cleaned_data,
alter_external_reviewers=self.can_alter_external_reviewers(self.instance, self.user),
submitted_reviewers=self.submitted_reviewers,
return instance
Erin Mullaney
committed
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)
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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 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