internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: comic/grand-challenge.org

Issue:
Add profile information to the verification admin
When manually reviewing verification requests it would be helpful to have more information in the admin such as the users full name, location, department and website.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/verifications/admin.py b/app/grandchallenge/verifications/admin.py
--- a/app/grandchallenge/verifications/admin.py
+++ b/app/grandchallenge/verifications/admin.py
@@ -23,14 +23,15 @@ def mark_not_verified(modeladmin, request, queryset):
 class VerificationAdmin(admin.ModelAdmin):
     list_display = (
         "user",
+        "user_info",
         "created",
         "signup_email",
-        "signup_email_activated",
         "email",
         "email_is_verified",
         "is_verified",
         "verified_at",
     )
+    list_select_related = ("user__user_profile",)
     list_filter = ("email_is_verified", "is_verified")
     readonly_fields = (
         "created",
diff --git a/app/grandchallenge/verifications/models.py b/app/grandchallenge/verifications/models.py
--- a/app/grandchallenge/verifications/models.py
+++ b/app/grandchallenge/verifications/models.py
@@ -1,6 +1,7 @@
 from allauth.account.signals import email_confirmed
 from django.contrib.auth import get_user_model
 from django.db import models
+from django.utils.html import format_html
 from django.utils.timezone import now
 from pyswot import is_academic
 
@@ -69,6 +70,17 @@ def save(self, *args, **kwargs):
 
         super().save(*args, **kwargs)
 
+    @property
+    def user_info(self):
+        return format_html(
+            "<span>{} <br/> {} <br/> {} <br/> {} <br/> {}</span>",
+            self.user.get_full_name(),
+            self.user.user_profile.institution,
+            self.user.user_profile.department,
+            self.user.user_profile.country,
+            self.user.user_profile.website,
+        )
+
 
 def create_verification(email_address, *_, **__):
     if (


Test patch:
Repository: comic/grand-challenge.org

Issue:
Make ComponentInterface configurable
The setting store_in_database is not editable when creating or editing a ComponentInterface. 


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/components/admin.py b/app/grandchallenge/components/admin.py
--- a/app/grandchallenge/components/admin.py
+++ b/app/grandchallenge/components/admin.py
@@ -14,9 +14,14 @@ class ComponentInterfaceAdmin(admin.ModelAdmin):
         "kind",
         "default_value",
         "relative_path",
-        "store_in_database",
     )
 
+    def get_readonly_fields(self, request, obj=None):
+        if obj:
+            return ("store_in_database", *self.readonly_fields)
+        else:
+            return self.readonly_fields
+
 
 class ComponentInterfaceValueAdmin(admin.ModelAdmin):
     list_display = ("pk", "interface", "value", "file", "image")
diff --git a/app/grandchallenge/components/migrations/0003_auto_20210323_1452.py b/app/grandchallenge/components/migrations/0003_auto_20210323_1452.py
new file mode 100644
--- /dev/null
+++ b/app/grandchallenge/components/migrations/0003_auto_20210323_1452.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.1.6 on 2021-03-23 14:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [("components", "0002_auto_20210203_0747")]
+
+    operations = [
+        migrations.AlterField(
+            model_name="componentinterface",
+            name="store_in_database",
+            field=models.BooleanField(
+                default=True,
+                help_text="Should the value be saved in a database field, only valid for outputs.",
+            ),
+        )
+    ]
diff --git a/app/grandchallenge/components/models.py b/app/grandchallenge/components/models.py
--- a/app/grandchallenge/components/models.py
+++ b/app/grandchallenge/components/models.py
@@ -155,7 +155,7 @@ class ComponentInterface(models.Model):
     )
     store_in_database = models.BooleanField(
         default=True,
-        editable=False,
+        editable=True,
         help_text=(
             "Should the value be saved in a database field, "
             "only valid for outputs."


Test patch:
Repository: comic/grand-challenge.org

Issue:
Increase width of algorithm result table
The table on the algorithm results page can become wider than the page container if the name of the scan is very long. The user then has to scroll to the right to see the "Open Result in Viewer" button, which is quite confusing.

![image](https://user-images.githubusercontent.com/773597/112984872-ba647b00-915f-11eb-9837-560159d3a314.png)


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/core/context_processors.py b/app/grandchallenge/core/context_processors.py
--- a/app/grandchallenge/core/context_processors.py
+++ b/app/grandchallenge/core/context_processors.py
@@ -5,6 +5,7 @@
 from guardian.utils import get_anonymous_user
 
 from grandchallenge.blogs.models import Post
+from grandchallenge.participants.models import RegistrationRequest
 from grandchallenge.policies.models import Policy
 
 logger = logging.getLogger(__name__)
@@ -31,6 +32,9 @@ def challenge(request):
         "challenge_perms": get_perms(user, challenge),
         "user_is_participant": challenge.is_participant(user),
         "pages": challenge.page_set.all(),
+        "pending_requests": challenge.registrationrequest_set.filter(
+            status=RegistrationRequest.PENDING
+        ),
     }
 
 


Test patch:
Repository: comic/grand-challenge.org

Issue:
Not setting `USER` directive in processor Dockerfile fails silently
Building a processor image without setting `USER` directive in Dockerfile will result in the container never being marked as ready and triggers a (silent) error in sentry: 
https://sentry.io/organizations/grand-challenge/issues/2396054397/?project=303639&query=is%3Aunresolved

It should fail properly returning a validation error to the user indicating that the `USER` directive should be set in the Dockerfile according to docker best practices.



Discussion:

Resolving patch:
diff --git a/app/grandchallenge/components/tasks.py b/app/grandchallenge/components/tasks.py
--- a/app/grandchallenge/components/tasks.py
+++ b/app/grandchallenge/components/tasks.py
@@ -66,7 +66,9 @@ def _validate_docker_image_manifest(*, model, instance) -> str:
     )
     config = json.loads(config)
 
-    if str(config["config"]["User"].lower()) in ["", "root", "0"]:
+    if "User" not in config["config"] or str(
+        config["config"]["User"].lower()
+    ) in ["", "root", "0"]:
         model.objects.filter(pk=instance.pk).update(
             status=(
                 "The container runs as root. Please add a user, group and "


Test patch:
Repository: comic/grand-challenge.org

Issue:
Redirect to question overview after adding a question [Readerstudy]
**Is your feature request related to a problem? Please describe.**
After adding a question to a Readerstudy design you are redirected to the Information page. I have to add multiple questions so now I have to click every time back to the questions overview. 

**Describe the solution you'd like**
Redirect the save button to the question overview




Discussion:

Resolving patch:
diff --git a/app/grandchallenge/reader_studies/models.py b/app/grandchallenge/reader_studies/models.py
--- a/app/grandchallenge/reader_studies/models.py
+++ b/app/grandchallenge/reader_studies/models.py
@@ -1382,6 +1382,9 @@ def is_image_type(self):
             self.AnswerType.MULTIPLE_POLYGONS_IMAGE,
         ]
 
+    def get_absolute_url(self):
+        return self.reader_study.get_absolute_url() + "#questions"
+
 
 class CategoricalOption(models.Model):
     question = models.ForeignKey(
diff --git a/app/grandchallenge/reader_studies/views.py b/app/grandchallenge/reader_studies/views.py
--- a/app/grandchallenge/reader_studies/views.py
+++ b/app/grandchallenge/reader_studies/views.py
@@ -433,9 +433,6 @@ def get_context_data(self, **kwargs):
     def form_valid(self, form):
         return self.validate_options(form, super())
 
-    def get_success_url(self):
-        return self.object.reader_study.get_absolute_url()
-
 
 class BaseAddObjectToReaderStudyMixin(
     LoginRequiredMixin, ObjectPermissionRequiredMixin
@@ -474,9 +471,6 @@ def form_valid(self, form):
         form.instance.reader_study = self.reader_study
         return super().form_valid(form)
 
-    def get_success_url(self):
-        return self.object.reader_study.get_absolute_url()
-
 
 class AddGroundTruthToReaderStudy(BaseAddObjectToReaderStudyMixin, FormView):
     form_class = GroundTruthForm
@@ -604,9 +598,6 @@ def get_form_kwargs(self):
         )
         return kwargs
 
-    def get_success_url(self):
-        return self.object.get_absolute_url()
-
 
 class AddQuestionToReaderStudy(
     QuestionOptionMixin, AddObjectToReaderStudyMixin


Test patch:
Repository: comic/grand-challenge.org

Issue:
Change order of the blog posts
Currently all blog posts that are published on grand-challenge are sorted based on the date the post was initially created. We would like to change this to the date the post was published such that the most recent post are shown on top. I had contact with @jmsmkn on slack after which he suggested a few changes I could make in the code to change this. After discussing this with Kiran we thought it might be best to first create an issue here. 



Discussion:
Note that they're already ordered by `post.created` (descending) https://github.com/comic/grand-challenge.org/blob/8128f42f200b68cd99dad5ba670df739def67ffd/app/grandchallenge/blogs/models.py#L31-L32. I have suggested updating the created date to `django.utils.timezone.now` when the `published` status changes from `False` to `True`.

Resolving patch:
diff --git a/app/grandchallenge/blogs/models.py b/app/grandchallenge/blogs/models.py
--- a/app/grandchallenge/blogs/models.py
+++ b/app/grandchallenge/blogs/models.py
@@ -1,6 +1,7 @@
 from django.conf import settings
 from django.contrib.auth import get_user_model
 from django.db import models
+from django.utils import timezone
 from django_extensions.db.fields import AutoSlugField
 from simple_history.models import HistoricalRecords
 from stdimage import JPEGField
@@ -48,6 +49,16 @@ class Meta:
     def __str__(self):
         return self.title
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self._published_orig = self.published
+
+    def save(self, *args, **kwargs):
+        if self._published_orig is False and self.published is True:
+            self.created = timezone.now()
+
+        super().save(*args, **kwargs)
+
     def get_absolute_url(self):
         return reverse("blogs:detail", kwargs={"slug": self.slug})
 


Test patch:
diff --git a/app/tests/blogs_tests/test_models.py b/app/tests/blogs_tests/test_models.py
new file mode 100644
--- /dev/null
+++ b/app/tests/blogs_tests/test_models.py
@@ -0,0 +1,18 @@
+import pytest
+
+from tests.blogs_tests.factory import PostFactory
+
+
+@pytest.mark.django_db
+def test_created_updated_when_published():
+    p = PostFactory()
+    assert p.published is False
+
+    created = p.created
+
+    p.published = True
+    p.save()
+
+    p.refresh_from_db()
+
+    assert p.created > created
Repository: comic/grand-challenge.org

Issue:
Challenge creation notifications
At the moment, staff users receive emails about new challenges. It would be nice to turns those emails into notifications. 

**Challenge creation emails**

- create follow: `staff users` --> `gc.localhost Site`
- upon challenge creation: send `action` with challenge `creator` as `actor`, the created `challenge` as `action_object` and the `gc.localhost site` as `target`
- _Notification template:_ print action as is for normal challenges, for external challenges, make sure to link the `update_url` for the challenge in the notification rather than the challenge url


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/challenges/emails.py b/app/grandchallenge/challenges/emails.py
--- a/app/grandchallenge/challenges/emails.py
+++ b/app/grandchallenge/challenges/emails.py
@@ -1,7 +1,5 @@
-from django.conf import settings
-from django.contrib.auth import get_user_model
 from django.contrib.sites.models import Site
-from django.core.mail import send_mail
+from django.core.mail import mail_managers
 
 from grandchallenge.subdomains.utils import reverse
 
@@ -9,7 +7,7 @@
 def send_challenge_created_email(challenge):
     site = Site.objects.get_current()
     message = (
-        f"Dear {{}},\n\n"
+        f"Dear manager,\n\n"
         f"User {challenge.creator} has just created the challenge "
         f"{challenge.short_name} at {challenge.get_absolute_url()}.\n\n"
         f"Regards,\n"
@@ -17,15 +15,10 @@ def send_challenge_created_email(challenge):
         f"This is an automated service email from {site.domain}."
     )
 
-    staff = get_user_model().objects.filter(is_staff=True)
-
-    for s in staff:
-        send_mail(
-            subject=f"[{site.domain.lower()}] New Challenge Created",
-            message=message.format(s.username),
-            from_email=settings.DEFAULT_FROM_EMAIL,
-            recipient_list=[s.email],
-        )
+    mail_managers(
+        subject=f"[{site.domain.lower()}] New Challenge Created",
+        message=message,
+    )
 
 
 def send_external_challenge_created_email(challenge):
@@ -36,7 +29,7 @@ def send_external_challenge_created_email(challenge):
     )
 
     message = (
-        f"Dear {{}},\n\n"
+        f"Dear manager,\n\n"
         f"User {challenge.creator} has just created the challenge "
         f"{challenge.short_name}. You need to un-hide it before it is visible "
         f"on the all challenges page, you can do that here: {update_url}\n\n"
@@ -45,12 +38,7 @@ def send_external_challenge_created_email(challenge):
         f"This is an automated service email from {site.domain}."
     )
 
-    staff = get_user_model().objects.filter(is_staff=True)
-
-    for s in staff:
-        send_mail(
-            subject=f"[{site.domain.lower()}] New External Challenge",
-            message=message.format(s.username),
-            from_email=settings.DEFAULT_FROM_EMAIL,
-            recipient_list=[s.email],
-        )
+    mail_managers(
+        subject=f"[{site.domain.lower()}] New External Challenge",
+        message=message,
+    )


Test patch:
Repository: comic/grand-challenge.org

Issue:
Filter reader study answers by username
It would be handy if reader study answers could be filtered by username ("creator")


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/reader_studies/filters.py b/app/grandchallenge/reader_studies/filters.py
--- a/app/grandchallenge/reader_studies/filters.py
+++ b/app/grandchallenge/reader_studies/filters.py
@@ -1,7 +1,18 @@
+from django_filters import CharFilter
+from django_filters.rest_framework import FilterSet
+
 from grandchallenge.core.filters import TitleDescriptionModalityStructureFilter
-from grandchallenge.reader_studies.models import ReaderStudy
+from grandchallenge.reader_studies.models import Answer, ReaderStudy
 
 
 class ReaderStudyFilter(TitleDescriptionModalityStructureFilter):
     class Meta(TitleDescriptionModalityStructureFilter.Meta):
         model = ReaderStudy
+
+
+class AnswerFilter(FilterSet):
+    creator = CharFilter(field_name="creator__username", label="username")
+
+    class Meta:
+        model = Answer
+        fields = ("creator", "question__reader_study")
diff --git a/app/grandchallenge/reader_studies/views.py b/app/grandchallenge/reader_studies/views.py
--- a/app/grandchallenge/reader_studies/views.py
+++ b/app/grandchallenge/reader_studies/views.py
@@ -59,7 +59,10 @@
 from grandchallenge.datatables.views import Column, PaginatedTableListView
 from grandchallenge.groups.forms import EditorsForm
 from grandchallenge.groups.views import UserGroupUpdateMixin
-from grandchallenge.reader_studies.filters import ReaderStudyFilter
+from grandchallenge.reader_studies.filters import (
+    AnswerFilter,
+    ReaderStudyFilter,
+)
 from grandchallenge.reader_studies.forms import (
     AnswersRemoveForm,
     CategoricalOptionFormSet,
@@ -892,7 +895,7 @@ class AnswerViewSet(
     )
     permission_classes = [DjangoObjectPermissions]
     filter_backends = [DjangoFilterBackend, ObjectPermissionsFilter]
-    filterset_fields = ["question__reader_study"]
+    filterset_class = AnswerFilter
     renderer_classes = (
         *api_settings.DEFAULT_RENDERER_CLASSES,
         PaginatedCSVRenderer,


Test patch:
Repository: comic/grand-challenge.org

Issue:
Search is broken for Archive Items list view
To reproduce, navigate to `/archives/<slug>/items/`, type something in the search box.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/archives/views.py b/app/grandchallenge/archives/views.py
--- a/app/grandchallenge/archives/views.py
+++ b/app/grandchallenge/archives/views.py
@@ -492,10 +492,13 @@ class ArchiveItemsList(
     row_template = "archives/archive_items_row.html"
     search_fields = [
         "pk",
-        "name",
+        "values__interface__title",
+        "values__value",
+        "values__image__name",
+        "values__file",
     ]
     columns = [
-        Column(title="Values", sort_field="pk"),
+        Column(title="Values", sort_field="values"),
         Column(title="Edit", sort_field="pk"),
     ]
 


Test patch:
Repository: comic/grand-challenge.org

Issue:
Integrate Forums into challenges 
Navigating to the forum of a challenge currently takes the participant outside of the challenge environment. Navigating back to the challenge is not possible through the breadcrumbs on the forum page and instead requires going via the Challenge tab and searching for the respective Challenge again. It would be nicer if the forums were visually integrated into the challenge page layout and if the breadcrumbs reflected their nesting in the challenge rather than their nesting under all forum on GC. 

See here: https://github.com/DIAGNijmegen/rse-roadmap/issues/83#issuecomment-919250835



Discussion:

Resolving patch:
diff --git a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
--- a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
+++ b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
@@ -51,3 +51,9 @@ def get_content_type(follow_object):
     except AttributeError:
         ct = None
     return ct
+
+
+@register.simple_tag()
+def is_participant(user, challenge):
+    if challenge.is_participant(user):
+        return True


Test patch:
Repository: comic/grand-challenge.org

Issue:
Incorrect values in Archive Item List 
The Archive Item list view displays the correct archive items, but for some reason, the `archive_item.values` are duplicated.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/archives/views.py b/app/grandchallenge/archives/views.py
--- a/app/grandchallenge/archives/views.py
+++ b/app/grandchallenge/archives/views.py
@@ -498,7 +498,7 @@ class ArchiveItemsList(
         "values__file",
     ]
     columns = [
-        Column(title="Values", sort_field="values"),
+        Column(title="Values", sort_field="created"),
         Column(title="Edit", sort_field="pk"),
     ]
 


Test patch:
Repository: comic/grand-challenge.org

Issue:
Syntax highlighting for GC
It would be nice, especially for the documentation pages, to enable syntax highlighting. 

The Markdown editor we use already produces the correct html tags (`''''python` is correctly translated to `<pre><code class="language-python"> ... </code></pre>`

Getting the syntax highlighting to work is then a matter of adding some custom css. There are multiple options, one of them being [prism.js](https://prismjs.com/index.html). To use prism, we just need to add a few links to `base.html` and `style.html`: https://prismjs.com/index.html#basic-usage-cdn



Discussion:
I would prefer to use something on the backend to do this. Why not `pygments` and the `codehilite` plugin for markdown? https://python-markdown.github.io/extensions/code_hilite/
Ah nice. I tried it out and it works super well! 

Resolving patch:
diff --git a/app/config/settings.py b/app/config/settings.py
--- a/app/config/settings.py
+++ b/app/config/settings.py
@@ -680,6 +680,7 @@ def strtobool(val) -> bool:
     "markdown.extensions.fenced_code",
     "markdown.extensions.tables",
     "markdown.extensions.sane_lists",
+    "markdown.extensions.codehilite",
     BS4Extension(),
 ]
 MARKDOWNX_MARKDOWNIFY_FUNCTION = (
diff --git a/app/grandchallenge/core/utils/markdown.py b/app/grandchallenge/core/utils/markdown.py
--- a/app/grandchallenge/core/utils/markdown.py
+++ b/app/grandchallenge/core/utils/markdown.py
@@ -23,6 +23,9 @@ def run(self, root):
             elif el.tag == "thead":
                 el.set("class", "thead-light")
 
+            elif el.tag == "code":
+                el.set("class", "codehilite")
+
 
 class LinkBlankTargetExtension(Extension):
     def extendMarkdown(self, md):  # noqa: N802


Test patch:
diff --git a/app/tests/core_tests/test_markdown.py b/app/tests/core_tests/test_markdown.py
--- a/app/tests/core_tests/test_markdown.py
+++ b/app/tests/core_tests/test_markdown.py
@@ -10,6 +10,11 @@
 --- | --- | ---
 *Still* | `renders` | **nicely**
 1 | 2 | 3
+
+```python
+ def test_function():
+    pass
+```
 """
 
 EXPECTED_HTML = """<p><img alt="" class="img-fluid" src="whatever.png" /></p>
@@ -27,7 +32,7 @@
 <tbody>
 <tr>
 <td><em>Still</em></td>
-<td><code>renders</code></td>
+<td><code class="codehilite">renders</code></td>
 <td><strong>nicely</strong></td>
 </tr>
 <tr>
@@ -36,7 +41,10 @@
 <td>3</td>
 </tr>
 </tbody>
-</table>"""
+</table>
+<div class="codehilite"><pre><span></span><code> <span class="k">def</span> <span class="nf">test_function</span><span class="p">():</span>
+    <span class="k">pass</span>
+</code></pre></div>"""
 
 
 def test_markdown_rendering():
Repository: comic/grand-challenge.org

Issue:
Video maximize button not working in Chrome and Edge
The video maximize button (see [here](https://grand-challenge.org/documentation/create-your-own-algorithm/)) does not work in Chrome and Edge. It is greyed out, maximizing is not possible. 

This button does work in Safari and Firefox, so this appears to be a browser issue. 

Possibly this can be fixed with a browser specific attribute in the markdown or with some custom css? 

 


Discussion:

Resolving patch:
diff --git a/app/config/settings.py b/app/config/settings.py
--- a/app/config/settings.py
+++ b/app/config/settings.py
@@ -286,7 +286,7 @@ def strtobool(val) -> bool:
     "display-capture": [],
     "document-domain": [],
     "encrypted-media": [],
-    "fullscreen": [],
+    "fullscreen": ["self"],
     "geolocation": [],
     "gyroscope": [],
     "interest-cohort": [],


Test patch: