Skip to content

Commit

Permalink
Adds readers update view
Browse files Browse the repository at this point in the history
  • Loading branch information
jmsmkn committed Jul 25, 2019
1 parent c9d8dd8 commit 6dc0a45
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 32 deletions.
27 changes: 18 additions & 9 deletions app/grandchallenge/reader_studies/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,13 @@ class Meta:
fields = ("question_text", "answer_type", "order")


class EditorsForm(SaveFormInitMixin, Form):
class UserGroupForm(SaveFormInitMixin, Form):
ADD = "ADD"
REMOVE = "REMOVE"
CHOICES = ((ADD, "Add editor"), (REMOVE, "Remove editor"))
CHOICES = ((ADD, "Add"), (REMOVE, "Remove"))
user = ModelChoiceField(
queryset=get_user_model().objects.all().order_by("username"),
help_text=(
"Select a user that will be added to the admins group for "
"this reader study."
),
help_text=("Select a user that will be added to the group"),
required=True,
widget=autocomplete.ModelSelect2(
url="reader-studies:users-autocomplete",
Expand All @@ -75,11 +72,23 @@ class EditorsForm(SaveFormInitMixin, Form):
def clean_user(self):
user = self.cleaned_data["user"]
if user == get_anonymous_user():
raise ValidationError("You cannot add this user as an editor!")
raise ValidationError("You cannot add this user!")
return user

def add_or_remove_user(self, *, reader_study):
if self.cleaned_data["action"] == EditorsForm.ADD:
reader_study.add_editor(self.cleaned_data["user"])
getattr(reader_study, f"add_{self.role}")(
self.cleaned_data["user"]
)
elif self.cleaned_data["action"] == EditorsForm.REMOVE:
reader_study.remove_editor(self.cleaned_data["user"])
getattr(reader_study, f"remove_{self.role}")(
self.cleaned_data["user"]
)


class EditorsForm(UserGroupForm):
role = "editor"


class ReadersForm(UserGroupForm):
role = "reader"
3 changes: 3 additions & 0 deletions app/grandchallenge/reader_studies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ def is_reader(self, user):
def add_editor(self, user):
return self.editors_group.user_set.add(user)

def add_reader(self, user):
return self.readers_group.user_set.add(user)

@property
def study_image_names(self):
return [im.name for im in self.images.all()]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@ <h1>Reader Study {{ object.title }}</h1>
</a>
</p>

<h2>Editors</h2>
<ul>
{% for user in object.editors_group.user_set.all %}
<li>{{ user }}</li>
{% endfor %}
</ul>

<p class="mt-3">
<a class="btn btn-primary"
href="{% url 'reader-studies:editors-update' slug=object.slug %}">
<i class="fas fa-plus"></i> Add editors
</a>
</p>

<h2>Readers</h2>
<ul>
{% for user in object.readers_group.user_set.all %}
<li>{{ user }}</li>
{% endfor %}
</ul>

<p class="mt-3">
<a class="btn btn-primary"
href="{% url 'reader-studies:readers-update' slug=object.slug %}">
<i class="fas fa-plus"></i> Add readers
</a>
</p>

<h2>Upload Sessions</h2>

<ul>
Expand Down Expand Up @@ -61,7 +89,7 @@ <h2>Questions</h2>
</a>
<a class="btn btn-primary"
href="{% url 'reader-studies:update' slug=object.slug %}">
<i class="fa fa-edit"></i>
<i class="fa fa-edit"></i> Edit this reader study
</a>
</p>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load static %}

{% block content %}
<h2>Add another editor to {{ object }}</h2>
<h2>Add a user to the {{ role }}s group for {{ object }}</h2>

{% crispy form %}
{% endblock %}
Expand Down
10 changes: 8 additions & 2 deletions app/grandchallenge/reader_studies/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
AddImagesToReaderStudy,
AddQuestionToReaderStudy,
EditorsUpdate,
EditorsUpdateAutocomplete,
ReaderStudyCreate,
ReaderStudyDetail,
ReaderStudyList,
ReaderStudyUpdate,
ReaderStudyUserAutocomplete,
ReadersUpdate,
)

app_name = "reader-studies"
Expand All @@ -19,7 +20,7 @@
path("create/", ReaderStudyCreate.as_view(), name="create"),
path(
"users-autocomplete/",
EditorsUpdateAutocomplete.as_view(),
ReaderStudyUserAutocomplete.as_view(),
name="users-autocomplete",
),
path("<slug>/", ReaderStudyDetail.as_view(), name="detail"),
Expand All @@ -44,4 +45,9 @@
EditorsUpdate.as_view(),
name="editors-update",
),
path(
"<slug>/readers/update/",
ReadersUpdate.as_view(),
name="readers-update",
),
]
41 changes: 22 additions & 19 deletions app/grandchallenge/reader_studies/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
ReaderStudyUpdateForm,
QuestionCreateForm,
EditorsForm,
ReadersForm,
)
from grandchallenge.reader_studies.models import ReaderStudy, Question, Answer
from grandchallenge.reader_studies.serializers import (
Expand Down Expand Up @@ -94,7 +95,9 @@ class ReaderStudyUpdate(
)


class AddObjectToReaderStudyMixin:
class AddObjectToReaderStudyMixin(
LoginRequiredMixin, ObjectPermissionRequiredMixin, CreateView
):
"""
Mixin that adds an object that has a foreign key to a reader study and a
creator. The url to this view must include a slug that points to the slug
Expand Down Expand Up @@ -128,29 +131,19 @@ def get_success_url(self):
return self.object.reader_study.get_absolute_url()


class AddImagesToReaderStudy(
LoginRequiredMixin,
AddObjectToReaderStudyMixin,
ObjectPermissionRequiredMixin,
CreateView,
):
class AddImagesToReaderStudy(AddObjectToReaderStudyMixin):
model = RawImageUploadSession
form_class = UploadRawImagesForm
template_name = "reader_studies/readerstudy_add_images.html"


class AddQuestionToReaderStudy(
LoginRequiredMixin,
AddObjectToReaderStudyMixin,
ObjectPermissionRequiredMixin,
CreateView,
):
class AddQuestionToReaderStudy(AddObjectToReaderStudyMixin):
model = Question
form_class = QuestionCreateForm
template_name = "reader_studies/readerstudy_add_question.html"


class EditorsUpdateAutocomplete(
class ReaderStudyUserAutocomplete(
LoginRequiredMixin, UserPassesTestMixin, autocomplete.Select2QuerySetView
):
def test_func(self):
Expand All @@ -170,15 +163,13 @@ def get_queryset(self):
return qs


class EditorsUpdate(
class ReaderStudyUserGroupUpdateMixin(
LoginRequiredMixin,
ObjectPermissionRequiredMixin,
SuccessMessageMixin,
FormView,
):
form_class = EditorsForm
template_name = "reader_studies/readerstudy_editors_form.html"
success_message = "Editors successfully updated"
template_name = "reader_studies/readerstudy_user_groups_form.html"
permission_required = (
f"{ReaderStudy._meta.app_label}.change_{ReaderStudy._meta.model_name}"
)
Expand All @@ -192,7 +183,9 @@ def reader_study(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({"object": self.reader_study})
context.update(
{"object": self.reader_study, "role": self.get_form().role}
)
return context

def get_success_url(self):
Expand All @@ -203,6 +196,16 @@ def form_valid(self, form):
return super().form_valid(form)


class EditorsUpdate(ReaderStudyUserGroupUpdateMixin):
form_class = EditorsForm
success_message = "Editors successfully updated"


class ReadersUpdate(ReaderStudyUserGroupUpdateMixin):
form_class = ReadersForm
success_message = "Readers successfully updated"


class ReaderStudyViewSet(ReadOnlyModelViewSet):
serializer_class = ReaderStudySerializer
queryset = ReaderStudy.objects.all().prefetch_related(
Expand Down

0 comments on commit 6dc0a45

Please sign in to comment.