Repository: wger-project/wger

Issue:
Return image URL on muscle endpoint
The muscle endpoint should also return the URLs for the muscle images and the backgrounds (probably the exercise endpoint as well). Needs to check whether we can access the URL when the static files are hosted on AWS or such


Discussion:
To get the URL: 

```python
url = request.build_absolute_uri(static('images/path/foo/bar.svg')),
```
A better place would a property in the model itself that returns the URL, then it can be used in the endpoint and templates e.g.
Hi, I would be interested in looking at this issue!
Hi! I have heard that @lydiaxing wanted to do this
Hi! I'm already working on another issue so Kevin can take this one!

Resolving patch:
diff --git a/wger/core/templatetags/wger_extras.py b/wger/core/templatetags/wger_extras.py
--- a/wger/core/templatetags/wger_extras.py
+++ b/wger/core/templatetags/wger_extras.py
@@ -18,6 +18,7 @@
 from django import template
 from django.conf import settings
 from django.db.models import QuerySet
+from django.templatetags.static import static
 from django.utils.html import strip_spaces_between_tags
 from django.utils.safestring import mark_safe
 from django.utils.translation import (
@@ -131,9 +132,9 @@ def render_muscles(muscles=None, muscles_sec=None):
     except IndexError:
         front_back = "front" if out_sec[0].is_front else "back"
 
-    backgrounds = [f"images/muscles/main/muscle-{i.id}.svg" for i in out_main] \
-        + [f"images/muscles/secondary/muscle-{i.id}.svg" for i in out_sec] \
-        + [f"images/muscles/muscular_system_{front_back}.svg"]
+    backgrounds = [i.image_url_main for i in out_main] \
+        + [i.image_url_secondary for i in out_sec] \
+        + [static(f"images/muscles/muscular_system_{front_back}.svg")]
 
     return {"backgrounds": backgrounds,
             "empty": False}
diff --git a/wger/exercises/api/serializers.py b/wger/exercises/api/serializers.py
--- a/wger/exercises/api/serializers.py
+++ b/wger/exercises/api/serializers.py
@@ -107,4 +107,4 @@ class MuscleSerializer(serializers.ModelSerializer):
     """
     class Meta:
         model = Muscle
-        fields = '__all__'
+        fields = ['name', 'is_front', 'image_url_main', 'image_url_secondary']
diff --git a/wger/exercises/models.py b/wger/exercises/models.py
--- a/wger/exercises/models.py
+++ b/wger/exercises/models.py
@@ -27,6 +27,7 @@
 from django.core.validators import MinLengthValidator
 from django.db import models
 from django.template.loader import render_to_string
+from django.templatetags.static import static
 from django.urls import reverse
 from django.utils import translation
 from django.utils.text import slugify
@@ -68,6 +69,16 @@ class Muscle(models.Model):
     class Meta:
         ordering = ["name", ]
 
+    # Image to use when displaying this as a main muscle in an exercise
+    @property
+    def image_url_main(self):
+        return static(f"images/muscles/main/muscle-{self.id}.svg")
+
+    # Image to use when displaying this as a secondary muscle in an exercise
+    @property
+    def image_url_secondary(self):
+        return static(f"images/muscles/secondary/muscle-{self.id}.svg")
+
     def __str__(self):
         """
         Return a more human-readable representation


Test patch:
diff --git a/wger/exercises/tests/test_muscles.py b/wger/exercises/tests/test_muscles.py
--- a/wger/exercises/tests/test_muscles.py
+++ b/wger/exercises/tests/test_muscles.py
@@ -41,6 +41,12 @@ def test_representation(self):
         """
         self.assertEqual("{0}".format(Muscle.objects.get(pk=1)), 'Anterior testoid')
 
+        # Check image URL properties
+        self.assertIn("images/muscles/main/muscle-2.svg",
+                      Muscle.objects.get(pk=2).image_url_main)
+        self.assertIn("images/muscles/secondary/muscle-1.svg",
+                      Muscle.objects.get(pk=1).image_url_secondary)
+
 
 class MuscleAdminOverviewTest(WgerAccessTestCase):
     """
@@ -148,3 +154,14 @@ class MuscleApiTestCase(api_base_test.ApiBaseResourceTestCase):
     private_resource = False
     data = {'name': 'The name',
             'is_front': True}
+
+    def test_get_detail(self):
+        super().test_get_detail()
+
+        # Check that image URLs are present in response
+        response = self.client.get(self.url_detail)
+        response_object = response.json()
+        self.assertIn("images/muscles/main/muscle-1.svg",
+                      response_object["image_url_main"])
+        self.assertIn("images/muscles/secondary/muscle-1.svg",
+                      response_object["image_url_secondary"])