Repository: comic/grand-challenge.org

Issue:
Replace links in the challenge copying command
People might use full url links in the page HTML, use a regex to replace the links using the new challenge short name.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/challenges/management/commands/copy_challenge.py b/app/grandchallenge/challenges/management/commands/copy_challenge.py
--- a/app/grandchallenge/challenges/management/commands/copy_challenge.py
+++ b/app/grandchallenge/challenges/management/commands/copy_challenge.py
@@ -1,3 +1,6 @@
+import re
+
+from django.contrib.sites.models import Site
 from django.core.management import BaseCommand, CommandError
 
 from grandchallenge.challenges.models import Challenge
@@ -57,7 +60,6 @@ class Command(BaseCommand):
         "order",
         "display_title",
         "hidden",
-        "html",
     ]
 
     def add_arguments(self, parser):
@@ -113,12 +115,24 @@ def _copy_evaluation_config(self, *, src_challenge, dest_challenge):
 
         dest_config.save()
 
+    def _substitute_urls(self, html, domain, old, new):
+        quote_replace = r"href='([^']*)'"
+        regex = fr'href="[^/]*//{old}.{domain}([^""]*)"'
+        html = re.sub(quote_replace, r'href="\1"', html)
+        return re.sub(regex, fr'href="https://{new}.{domain}\1"', html,)
+
     def _copy_pages(self, *, src_challenge, dest_challenge):
         src_pages = src_challenge.page_set.all()
 
+        site = Site.objects.get_current()
+        domain = site.domain
+        old = src_challenge.short_name
+        new = dest_challenge.short_name
+
         for src_page in src_pages:
             Page.objects.create(
                 challenge=dest_challenge,
+                html=self._substitute_urls(src_page.html, domain, old, new),
                 **{f: getattr(src_page, f) for f in self.page_fields},
             )
 


Test patch:
diff --git a/app/tests/challenges_tests/test_management_commands.py b/app/tests/challenges_tests/test_management_commands.py
--- a/app/tests/challenges_tests/test_management_commands.py
+++ b/app/tests/challenges_tests/test_management_commands.py
@@ -1,4 +1,5 @@
 import pytest
+from django.contrib.sites.models import Site
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
 from django.core.management import CommandError, call_command
 
@@ -23,7 +24,9 @@ def test_copy_challenge():
 
     with pytest.raises(ObjectDoesNotExist):
         call_command("copy_challenge", "foo", "bar")
-
+    site = Site.objects.get_current()
+    site.domain = "foo.bar"
+    site.save()
     src = ChallengeFactory(short_name="foo", use_evaluation=True)
     # toggle a boolean field
     src.evaluation_config.show_publication_url = (
@@ -34,7 +37,15 @@ def test_copy_challenge():
     src.modalities.add(ImagingModalityFactory())
 
     for _ in range(3):
-        PageFactory(challenge=src)
+        PageFactory(
+            challenge=src,
+            html=(
+                "<p><a href='https://foo.foo.bar/test'>test1</a>"
+                '<a href="https://foo.foo.bar/test">test2</a>'
+                "<a href='http://foo.foo.bar/test'>test3</a>"
+                '<a href="http://foo.foo.bar/test">test4</a></p>'
+            ),
+        )
 
     assert Challenge.objects.count() == 1
     assert Page.objects.count() == 3
@@ -52,6 +63,14 @@ def test_copy_challenge():
 
     dest = Challenge.objects.get(short_name="bar")
 
+    for page in dest.page_set.all():
+        assert page.html == (
+            '<p><a href="https://bar.foo.bar/test">test1</a>'
+            '<a href="https://bar.foo.bar/test">test2</a>'
+            '<a href="https://bar.foo.bar/test">test3</a>'
+            '<a href="https://bar.foo.bar/test">test4</a></p>'
+        )
+
     assert (
         dest.evaluation_config.show_publication_url
         == src.evaluation_config.show_publication_url