Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow assigning a project author as the editor #2290

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
21 changes: 19 additions & 2 deletions physionet-django/console/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,38 @@ def clean_project(self):
raise forms.ValidationError("Incorrect project selected.")
return pid

def clean(self):
project = ActiveProject.objects.get(id=self.cleaned_data["project"])
editor = self.cleaned_data["editor"]
if project.authors.filter(user=editor).exists():
raise forms.ValidationError(
'%(name)s is an author of "%(project)s". '
'Select an editor who is not one of the project authors.',
code='assign_own_project',
params={
'name': editor.get_full_name(),
'project': project.title,
},
)


class ReassignEditorForm(forms.Form):
"""
Assign an editor to a project under submission
"""
editor = forms.ModelChoiceField(queryset=None, widget=forms.Select(attrs={'onchange': 'set_editor_text()'}))

def __init__(self, user, *args, **kwargs):
def __init__(self, *args, project, **kwargs):
"""
Set the appropriate queryset
"""
super().__init__(*args, **kwargs)
users = User.get_users_with_permission('project', 'can_edit_activeprojects') \
.order_by('username')
users = users.exclude(username=user.username)
if project.editor:
users = users.exclude(id=project.editor.id)
author_ids = project.authors.values_list('user__id', flat=True)
users = users.exclude(id__in=author_ids)
self.fields['editor'].queryset = users


Expand Down
100 changes: 79 additions & 21 deletions physionet-django/console/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,41 +46,99 @@ def test_assign_editor(self):
"""
Assign an editor
"""
# Submit project
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
editor = User.objects.get(username='amitupreti')

# Add editor as a project author
temp_author = project.authors.create(
user=editor,
display_order=project.authors.count() + 1,
)
temp_author.affiliations.create(name='MIT')

# Submit project
self.assertTrue(project.is_submittable())
project.submit(author_comments='')
# Assign editor
self.assertIsNone(project.editor)
self.assertEqual(project.submission_status, SubmissionStatus.NEEDS_ASSIGNMENT)

# Try to assign editor; this should fail
self.client.login(username='admin', password='Tester11!')
editor = User.objects.get(username='amitupreti')
response = self.client.post(reverse(
'submitted_projects'), data={'project':project.id,
'editor':editor.id})
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
self.assertTrue(project.editor, editor)
self.client.post(reverse('submitted_projects'), data={
'project': project.id,
'editor': editor.id,
})
project.refresh_from_db()
self.assertIsNone(project.editor)
self.assertEqual(project.submission_status, SubmissionStatus.NEEDS_ASSIGNMENT)

# Remove author and try to assign again
temp_author.delete()
self.client.login(username='admin', password='Tester11!')
self.client.post(reverse('submitted_projects'), data={
'project': project.id,
'editor': editor.id,
})
project.refresh_from_db()
self.assertEqual(project.editor, editor)
self.assertEqual(project.submission_status, SubmissionStatus.NEEDS_DECISION)

def test_reassign_editor(self):
"""
Assign an editor, then reassign it
"""
# Submit project
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
editor1 = User.objects.get(username='cindyehlert')
editor2 = User.objects.get(username='amitupreti')

# Add editor2 as a project author
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
temp_author = project.authors.create(
user=editor2,
display_order=project.authors.count() + 1,
)
temp_author.affiliations.create(name='MIT')

# Submit project
self.assertTrue(project.is_submittable())
project.submit(author_comments='')
# Assign editor
self.assertIsNone(project.editor)
self.assertEqual(project.submission_status, SubmissionStatus.NEEDS_ASSIGNMENT)

# Assign editor1 as initial editor
self.client.login(username='admin', password='Tester11!')
editor = User.objects.get(username='cindyehlert')
response = self.client.post(reverse('submitted_projects'), data={
'project': project.id, 'editor': editor.id})
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
self.assertTrue(project.editor, editor)
self.client.post(reverse('submitted_projects'), data={
'project': project.id,
'editor': editor1.id,
})
project.refresh_from_db()
self.assertEqual(project.editor, editor1)
self.assertEqual(project.submission_status, SubmissionStatus.NEEDS_DECISION)

# Reassign editor
editor = User.objects.get(username='amitupreti')
response = self.client.post(reverse('submission_info',
args=(project.slug,)), data={'editor': editor.id})
project = ActiveProject.objects.get(title='MIT-BIH Arrhythmia Database')
self.assertTrue(project.editor, editor)
# Try to reassign to editor2; this should fail
self.client.login(username=editor1.username, password='Tester11!')
self.client.post(
reverse('submission_info', args=(project.slug,)),
data={
'reassign_editor': '',
'editor': editor2.id,
},
)
project.refresh_from_db()
self.assertEqual(project.editor, editor1)

# Remove author and try to reassign again
temp_author.delete()
self.client.login(username=editor1.username, password='Tester11!')
self.client.post(
reverse('submission_info', args=(project.slug,)),
data={
'reassign_editor': '',
'editor': editor2.id,
},
)
project.refresh_from_db()
self.assertEqual(project.editor, editor2)

def test_edit_reject(self):
"""
Expand Down
31 changes: 19 additions & 12 deletions physionet-django/console/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ def submitted_projects(request):
notification.assign_editor_notify(project)
notification.editor_notify_new_project(project, user)
messages.success(request, 'The editor has been assigned')
else:
for _, errors in assign_editor_form.errors.items():
for error in errors:
messages.error(request, error)

# Submitted projects
projects = ActiveProject.objects.filter(submission_status__gt=SubmissionStatus.ARCHIVED).order_by(
Expand Down Expand Up @@ -322,7 +326,7 @@ def submission_info(request, project_slug):
copyedit_logs = project.copyedit_log_history()

data = request.POST or None
reassign_editor_form = forms.ReassignEditorForm(user, data=data)
reassign_editor_form = forms.ReassignEditorForm(project=project, data=data)
internal_note_form = forms.InternalNoteForm(data)
embargo_form = forms.EmbargoFilesDaysForm()
passphrase = ''
Expand All @@ -333,13 +337,16 @@ def submission_info(request, project_slug):
elif 'remove_passphrase' in request.POST:
project.anonymous.all().delete()
anonymous_url, passphrase = '', 'revoked'
elif 'reassign_editor' in request.POST and reassign_editor_form.is_valid():
project.reassign_editor(reassign_editor_form.cleaned_data['editor'])
notification.editor_notify_new_project(project, user, reassigned=True)
messages.success(request, 'The editor has been reassigned')
LOGGER.info("The editor for the project {0} has been reassigned from "
"{1} to {2}".format(project, user,
reassign_editor_form.cleaned_data['editor']))
elif 'reassign_editor' in request.POST and user == project.editor:
if reassign_editor_form.is_valid():
project.reassign_editor(reassign_editor_form.cleaned_data['editor'])
notification.editor_notify_new_project(project, user, reassigned=True)
messages.success(request, 'The editor has been reassigned')
LOGGER.info("The editor for the project {0} has been reassigned from "
"{1} to {2}".format(project, user,
reassign_editor_form.cleaned_data['editor']))
else:
messages.error(request, 'Invalid submission. See errors below.')
elif 'embargo_files' in request.POST:
embargo_form = forms.EmbargoFilesDaysForm(data=request.POST)
if settings.SYSTEM_MAINTENANCE_NO_UPLOAD:
Expand Down Expand Up @@ -403,7 +410,7 @@ def edit_submission(request, project_slug, *args, **kwargs):
except EditLog.DoesNotExist:
return redirect('editor_home')

reassign_editor_form = forms.ReassignEditorForm(request.user)
reassign_editor_form = forms.ReassignEditorForm(project=project)
embargo_form = forms.EmbargoFilesDaysForm()
internal_note_form = forms.InternalNoteForm()

Expand Down Expand Up @@ -464,7 +471,7 @@ def copyedit_submission(request, project_slug, *args, **kwargs):
return redirect('editor_home')

copyedit_log = project.copyedit_logs.get(complete_datetime=None)
reassign_editor_form = forms.ReassignEditorForm(request.user)
reassign_editor_form = forms.ReassignEditorForm(project=project)
embargo_form = forms.EmbargoFilesDaysForm()
internal_note_form = forms.InternalNoteForm()

Expand Down Expand Up @@ -644,7 +651,7 @@ def awaiting_authors(request, project_slug, *args, **kwargs):

outstanding_emails = ';'.join([a.user.email for a in authors.filter(
approval_datetime=None)])
reassign_editor_form = forms.ReassignEditorForm(request.user)
reassign_editor_form = forms.ReassignEditorForm(project=project)
embargo_form = forms.EmbargoFilesDaysForm()
internal_note_form = forms.InternalNoteForm()

Expand Down Expand Up @@ -711,7 +718,7 @@ def publish_submission(request, project_slug, *args, **kwargs):
if settings.SYSTEM_MAINTENANCE_NO_UPLOAD:
raise ServiceUnavailable()

reassign_editor_form = forms.ReassignEditorForm(request.user)
reassign_editor_form = forms.ReassignEditorForm(project=project)
embargo_form = forms.EmbargoFilesDaysForm()
internal_note_form = forms.InternalNoteForm()

Expand Down
13 changes: 11 additions & 2 deletions physionet-django/project/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,17 @@ def clean(self):
raise forms.ValidationError(
'You are not invited.')

if cleaned_data['response'] and not cleaned_data.get('affiliation'):
raise forms.ValidationError('You must specify your affiliation.')
if cleaned_data['response']:
if self.user == self.instance.project.editor:
raise forms.ValidationError(
'You must reassign this project to another editor '
'before accepting an authorship invitation.'
)

if not cleaned_data.get('affiliation'):
raise forms.ValidationError(
'You must specify your affiliation.'
)

return cleaned_data

Expand Down
Loading