Repository: apluslms/a-plus

Issue:
Exercise API field html_url behaves inconsistently
If an exercise has a parent (i.e., is embedded in a chapter or an exercise), the html_url in the API differ between what the ExerciseBriefSerializer and ExerciseSerializer produce.

The brief serializer provides the wanted format of the url (link to the parent with anchor to exercise):
![image](https://github.com/apluslms/a-plus/assets/50318434/0d1cefb7-584d-4163-878c-f874a4b7e8d9)

However, the exercise detail page includes the previous format (to the exercise page): 
![image](https://github.com/apluslms/a-plus/assets/50318434/809a5cf2-0ba6-4f36-be2c-2c459bb787ac)

This is illogical, inconsistent, and causes problems for MOOC-Jutut.


Discussion:
The new behaviour for the brief serializer stems from [commit 'Use the content cache in the course exercise list API endpoint '](https://github.com/apluslms/a-plus/commit/ebf3bc012f61f219893d1e00a86acb00f08aa84e), I'm not directly able to pinpoint why the html_url doesn't work as wanted on the exercise details page.
We looked into this together.

https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/exercise/api/views.py#L81
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/exercise/api/full_serializers.py#L34
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/exercise/api/serializers.py#L18
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/lib/api/serializers.py#L160
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/lib/api/serializers.py#L66

https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/exercise/exercise_models.py#L304
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/lib/models.py#L8-L22

`HtmlViewField` can be changed to call `get_display_url()` instead of `get_absolute_url()`.
https://github.com/apluslms/a-plus/blob/041919f6d26314d0825b421887ca249bc0d5e0b0/lib/api/serializers.py#L63-L66

Resolving patch:
diff --git a/lib/api/serializers.py b/lib/api/serializers.py
--- a/lib/api/serializers.py
+++ b/lib/api/serializers.py
@@ -8,6 +8,7 @@
 from rest_framework.fields import get_attribute
 
 from .fields import NestedHyperlinkedIdentityField, NestedHyperlinkedRelatedField
+from lib.helpers import build_aplus_url
 
 
 class NestedHyperlinkedModelSerializer(HyperlinkedModelSerializer):
@@ -61,9 +62,8 @@ def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
     def to_representation(self, obj): # pylint: disable=arguments-renamed
-        request = self.context['request']
-        url = obj.get_absolute_url()
-        return request.build_absolute_uri(url)
+        url = obj.get_display_url()
+        return build_aplus_url(url, True)
 
 
 class NestedHyperlinkedIdentityFieldWithQuery(NestedHyperlinkedIdentityField):


Test patch:
diff --git a/course/api/tests.py b/course/api/tests.py
--- a/course/api/tests.py
+++ b/course/api/tests.py
@@ -1,4 +1,4 @@
-from django.test import TestCase
+from django.test import TestCase, override_settings
 from rest_framework.test import APIClient
 
 from course.models import CourseInstance
@@ -9,6 +9,7 @@ class CourseInstanceAPITest(TestCase):
     from ..tests import CourseTest # pylint: disable=import-outside-toplevel
     setUp = CourseTest.setUp
 
+    @override_settings(BASE_URL="http://testserver/")
     def test_get_courselist(self):
         """
         Test if list of courses are given correctly via REST.