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

WIP: Add functionality for managing project reviews #2261

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions physionet-django/console/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
SubmissionStatus,
exists_project_slug,
InternalNote,
PeerReview,
)
from project.validators import MAX_PROJECT_SLUG_LENGTH, validate_doi, validate_slug
from user.models import CodeOfConduct, CredentialApplication, CredentialReview, User, TrainingQuestion
Expand Down Expand Up @@ -83,6 +84,15 @@ class Meta:
fields = ['content']


class PeerReviewForm(forms.ModelForm):
class Meta:
widgets = {
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 6}),
}
model = PeerReview
fields = ['content']


class AssignEditorForm(forms.Form):
"""
Assign an editor to a project under submission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
{{ notes|task_count_badge|safe }}
</a>
</li>
<li class="nav-item">
<a class="nav-link" id="reviews-tab" data-toggle="tab" href="#reviews" role="tab" aria-controls="reviews" aria-selected="false">Peer reviews
{{ reviews|task_count_badge|safe }}
</a>
</li>
</ul>
</div>
<div class="card-body">
Expand Down Expand Up @@ -158,6 +163,40 @@ <h5>Uploaded Documents</h5>
</form>
</div>

{# Reviews #}
<div class="tab-pane fade" id="reviews" role="tabpanel" aria-labelledby="reviews-tab">
<p>Reviews posted here are visible only to the editorial team. They are not visible to authors.</p>
<ul class="list-group">
{% for review in reviews %}
<li class="list-group-item">
<p>{{ review.content|linebreaks }}</p>
<p class="small text-muted">Created by {{ review.created_by }} on {{ review.created_at }}</p>
{% if review.created_by == user %}
<form action="{% url 'submission_info' project.slug %}" method="POST" id="peer_review_form">
{% csrf_token %}
<input type="hidden" name="review_id" value="{{ review.id }}">
<button class="btn btn-danger btn-rsp" type="submit" name="delete_peer_review" onclick="return confirm('Are you sure you want to delete this review?');">
Delete
</button>
</form>
{% endif %}
</li>
{% endfor %}
</ul>

<br />

<form action="{% url 'submission_info' project.slug %}" method="POST" id="peer_review_form">
{% csrf_token %}
<div class="form-group">
{{ peer_review_form.content }}
</div>
<button class="btn btn-primary" type="submit" name="add_peer_review">
Add Review
</button>
</form>
</div>

{# Permanent Reassign #}
{% if project.editor == user %}
<div class="tab-pane fade" id="reassign" role="tabpanel" aria-labelledby="reassign-tab">
Expand Down
28 changes: 26 additions & 2 deletions physionet-django/console/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
SubmissionStatus,
Topic,
exists_project_slug,
InternalNote
InternalNote,
PeerReview
)
from project.authorization.access import can_view_project_files
from project.utility import readable_size
Expand Down Expand Up @@ -278,13 +279,15 @@ def submission_info(request, project_slug):
"""
project = get_object_or_404(ActiveProject, slug=project_slug)
notes = project.internal_notes.all().order_by('-created_at')
reviews = project.peer_reviews.all().order_by('-created_at')

user = request.user
authors, author_emails, storage_info, edit_logs, copyedit_logs, latest_version = project.info_card()

data = request.POST or None
reassign_editor_form = forms.ReassignEditorForm(user, data=data)
internal_note_form = forms.InternalNoteForm(data)
peer_review_form = forms.PeerReviewForm(data)
embargo_form = forms.EmbargoFilesDaysForm()
passphrase = ''
anonymous_url = project.get_anonymous_url()
Expand Down Expand Up @@ -331,6 +334,24 @@ def submission_info(request, project_slug):
else:
messages.error(request, "You are not authorized to delete this note.")
return redirect(f'{request.path}?tab=notes')
if 'add_peer_review' in request.POST:
if peer_review_form.is_valid():
review = peer_review_form.save(commit=False)
review.project = project
review.created_by = request.user
review.save()
messages.success(request, "Review added.")
peer_review_form = forms.PeerReviewForm()
return redirect(f'{request.path}?tab=reviews')
if 'delete_peer_review' in request.POST:
review_id = request.POST['review_id']
review = get_object_or_404(PeerReview, pk=review_id, project=project)
if review.created_by == request.user:
review.delete()
messages.success(request, "Review deleted.")
else:
messages.error(request, "You are not authorized to delete this review.")
return redirect(f'{request.path}?tab=reviews')

url_prefix = notification.get_url_prefix(request)
bulk_url_prefix = notification.get_url_prefix(request, bulk_download=True)
Expand All @@ -344,7 +365,10 @@ def submission_info(request, project_slug):
'reassign_editor_form': reassign_editor_form,
'embargo_form': embargo_form,
'notes': notes,
'internal_note_form': internal_note_form})
'internal_note_form': internal_note_form,
'reviews': reviews,
'peer_review_form': peer_review_form})


@handling_editor
def edit_submission(request, project_slug, *args, **kwargs):
Expand Down
46 changes: 46 additions & 0 deletions physionet-django/project/migrations/0077_peerreview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 4.1.13 on 2024-07-18 02:45

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("project", "0076_internalnote"),
]

operations = [
migrations.CreateModel(
name="PeerReview",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("content", models.TextField()),
(
"created_by",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="peer_reviews",
to="project.activeproject",
),
),
],
),
]
15 changes: 15 additions & 0 deletions physionet-django/project/modelcomponents/activeproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,3 +654,18 @@ class InternalNote(models.Model):

def __str__(self):
return f"Note by {self.created_by} on {self.created_at}"


class PeerReview(models.Model):
"""
Allow reviews to be created for active projects.

These reviews should only be viewable by people with editor status.
"""
project = models.ForeignKey('project.ActiveProject', on_delete=models.CASCADE, related_name='peer_reviews')
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
content = models.TextField()

def __str__(self):
return f"Review by {self.created_by} on {self.created_at}"
Loading