Repository: carpentries/amy

Issue:
Wrong link being sent to main website
(Amended) use event.get_website_url to fetch the URL for a workshop when building the main website in order to prevent problems of the kind described below.

---
1. Go to http://software-carpentry.org/workshops/index.html#future
2. Look at the Sept 28-29 workshop at Oxford
3. The link is to the GitHub repository, _not_ to the GitHub Pages website.
4. But if you look in AMY at https://amy.software-carpentry.org/workshops/event/2015-09-28-oxford, the website URL and repository URL fields look correct.

Same issue shows up with several other workshops (e.g., Sept 17-18 at Western University Sydney links to the repo, not to the gh-pages site).



Discussion:
@gvwilson 

The event's URL (`Event.url`) is this: "https://github.com/jpallen/2015-09-28-oxford". You can see that when you go to Edit event: https://amy.software-carpentry.org/workshops/event/2015-09-28-oxford/edit

In the event details page we don't display `Event.url` (at least not directly). We display `event.get_repository_url()` and `event.get_website_url()`.

Events are exported with their URL, not the translated version from `get_repository_url` or `get_website_url`.

So do I fix this by changing this URL (and all others that are 
github.com) to their github.io gh-pages equivalents?

That's one possible fix.

Other is to make `get_repository_url` and `get_website_url` properties and in API return `event.website_url` instead of `event.url`.

What's simplest and most reliable?

The best for now is to manually change `event.url` to the website URL. The proper solution long-term would be making a property out of `event.get_website_url` and using it in API.


Resolving patch:
diff --git a/api/serializers.py b/api/serializers.py
--- a/api/serializers.py
+++ b/api/serializers.py
@@ -34,6 +34,7 @@ class EventSerializer(serializers.ModelSerializer):
     country = serializers.CharField()
     start = serializers.DateField(format=None)
     end = serializers.DateField(format=None)
+    url = serializers.URLField(source='website_url')
 
     def get_humandate(self, obj):
         """Render start and end dates as human-readable short date."""
diff --git a/workshops/models.py b/workshops/models.py
--- a/workshops/models.py
+++ b/workshops/models.py
@@ -481,7 +481,7 @@ class Event(models.Model):
     REPO_FORMAT = 'https://github.com/{name}/{repo}'
     WEBSITE_REGEX = re.compile(r'https?://(?P<name>[^.]+)\.github\.'
                                r'(io|com)/(?P<repo>[^/]+)/?')
-    WEBSITE_FORMAT = 'https://{name}.github.io/{repo}'
+    WEBSITE_FORMAT = 'https://{name}.github.io/{repo}/'
 
     class Meta:
         ordering = ('-start', )
@@ -495,13 +495,17 @@ def __str__(self):
     def get_absolute_url(self):
         return reverse('event_details', args=[self.get_ident()])
 
-    def get_repository_url(self):
+    @property
+    def repository_url(self):
         """Return self.url formatted as it was repository URL.
 
         Repository URL is as specified in REPO_FORMAT.
         If it doesn't match, the original URL is returned."""
         try:
-            mo = self.WEBSITE_REGEX.match(self.url)
+            # Try to match repo regex first. This will result in all repo URLs
+            # always formatted in the same way.
+            mo = (self.REPO_REGEX.match(self.url)
+                  or self.WEBSITE_REGEX.match(self.url))
             if not mo:
                 return self.url
 
@@ -511,13 +515,17 @@ def get_repository_url(self):
             # KeyError: mo.groupdict doesn't supply required names to format
             return self.url
 
-    def get_website_url(self):
+    @property
+    def website_url(self):
         """Return self.url formatted as it was website URL.
 
         Website URL is as specified in WEBSITE_FORMAT.
         If it doesn't match, the original URL is returned."""
         try:
-            mo = self.REPO_REGEX.match(self.url)
+            # Try to match website regex first. This will result in all website
+            # URLs always formatted in the same way.
+            mo = (self.WEBSITE_REGEX.match(self.url)
+                  or self.REPO_REGEX.match(self.url))
             if not mo:
                 return self.url
 
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -791,7 +791,7 @@ def validate_event(request, event_ident):
     event = Event.get_by_ident(event_ident)
     github_url = request.GET.get('url', None)  # for manual override
     if github_url is None:
-        github_url = event.get_repository_url()
+        github_url = event.repository_url
 
     try:
         page_url, _ = normalize_event_index_url(github_url)


Test patch:
diff --git a/api/test/test_events.py b/api/test/test_events.py
--- a/api/test/test_events.py
+++ b/api/test/test_events.py
@@ -34,21 +34,21 @@ def setUp(self):
             slug='event1', start=past - delta_2d, end=past - delta_1d,
             host=host, latitude=3, longitude=-2, venue='University',
             address='On the street', country='US', contact='sb@sth.edu',
-            url='http://url1/',
+            url='https://user.github.io/repository/',
         )
         # ongoing event
         self.event2 = Event.objects.create(
             slug='event2', start=today - delta_2d, end=today + delta_2d,
             host=host, latitude=3, longitude=-2, venue='University',
             address='On the street', country='US', contact='sb@sth.edu',
-            url='http://url2/',
+            url='https://github.com/user/repository',
         )
         # future event
         self.event3 = Event.objects.create(
             slug='event3', start=future - delta_2d, end=future + delta_2d,
             host=host, latitude=3, longitude=-2, venue='University',
             address='On the street', country='US', contact='sb@sth.edu',
-            url='http://url3/',
+            url='http://github.com/user/repository/',
         )
         # event with missing start
         self.event4 = Event.objects.create(
@@ -76,12 +76,12 @@ def setUp(self):
                 'start': self.event3.start,
                 'end': self.event3.end,
                 'humandate': 'Mar 23-27, 2030',
-                'latitude': 3,
-                'longitude': -2,
+                'latitude': 3.,
+                'longitude': -2.,
                 'venue': 'University',
                 'address': 'On the street',
                 'country': 'US',
-                'url': 'http://url3/',
+                'url': 'https://user.github.io/repository/',
                 'contact': 'sb@sth.edu',
             },
             {
@@ -91,12 +91,12 @@ def setUp(self):
                 'humandate': self.serializer_class.human_readable_date(
                     self.event2.start, self.event2.end
                 ),
-                'latitude': 3,
-                'longitude': -2,
+                'latitude': 3.,
+                'longitude': -2.,
                 'venue': 'University',
                 'address': 'On the street',
                 'country': 'US',
-                'url': 'http://url2/',
+                'url': 'https://user.github.io/repository/',
                 'contact': 'sb@sth.edu',
             },
             {
@@ -104,12 +104,12 @@ def setUp(self):
                 'start': self.event1.start,
                 'end': self.event1.end,
                 'humandate': 'Aug 28-29, 1993',
-                'latitude': 3,
-                'longitude': -2,
+                'latitude': 3.,
+                'longitude': -2.,
                 'venue': 'University',
                 'address': 'On the street',
                 'country': 'US',
-                'url': 'http://url1/',
+                'url': 'https://user.github.io/repository/',
                 'contact': 'sb@sth.edu',
             },
         ]
diff --git a/workshops/test/test_event.py b/workshops/test/test_event.py
--- a/workshops/test/test_event.py
+++ b/workshops/test/test_event.py
@@ -158,7 +158,7 @@ def test_delete_event_with_tasks_and_awards(self):
         Task.objects.get(pk=task.pk)
         Award.objects.get(pk=award.pk)
 
-    def test_repository_url(self):
+    def test_repository_website_url(self):
         test_host = Host.objects.all()[0]
         links = [
             'http://user-name.github.com/repo-name',
@@ -169,32 +169,21 @@ def test_repository_url(self):
             'http://user-name.github.io/repo-name/',
             'https://user-name.github.com/repo-name/',
             'https://user-name.github.io/repo-name/',
-        ]
-        REPO = 'https://github.com/user-name/repo-name'
-        for index, link in enumerate(links):
-            event = Event.objects.create(
-                slug='e{}'.format(index),
-                host=test_host,
-                url=link
-            )
-            assert event.get_repository_url() == REPO
-
-    def test_website_url(self):
-        test_host = Host.objects.all()[0]
-        links = [
             'http://github.com/user-name/repo-name',
             'http://github.com/user-name/repo-name/',
             'https://github.com/user-name/repo-name',
             'https://github.com/user-name/repo-name/',
         ]
-        WEBSITE = 'https://user-name.github.io/repo-name'
+        REPO = 'https://github.com/user-name/repo-name'
+        WEBSITE = 'https://user-name.github.io/repo-name/'
         for index, link in enumerate(links):
             event = Event.objects.create(
                 slug='e{}'.format(index),
                 host=test_host,
                 url=link
             )
-            assert event.get_website_url() == WEBSITE
+            assert event.repository_url == REPO
+            assert event.website_url == WEBSITE
 
     def test_wrong_repository_website_urls(self):
         test_host = Host.objects.all()[0]
@@ -204,8 +193,8 @@ def test_wrong_repository_website_urls(self):
             host=test_host,
             url=link
         )
-        assert event.get_repository_url() == link
-        assert event.get_website_url() == link
+        assert event.repository_url == link
+        assert event.website_url == link
 
 
 class TestEventViews(TestBase):