Repository: carpentries/amy

Issue:
Modify members API call so that JSON includes user ID
Right now the 'members' API gives us name and email - the JSON should include each person's user ID as well.



Discussion:
@gvwilson and what do you need that ID for? And did you by ID meant username?

Yes, username - I want to be able to check against _include files, PDF 
certificates on disk, etc.


Resolving patch:
diff --git a/api/serializers.py b/api/serializers.py
--- a/api/serializers.py
+++ b/api/serializers.py
@@ -12,12 +12,12 @@ class Meta:
         fields = ('name', 'user', )
 
 
-class PersonNameEmailSerializer(serializers.ModelSerializer):
+class PersonNameEmailUsernameSerializer(serializers.ModelSerializer):
     name = serializers.CharField(source='get_full_name')
 
     class Meta:
         model = Person
-        fields = ('name', 'email')
+        fields = ('name', 'email', 'username')
 
 
 class ExportBadgesSerializer(serializers.ModelSerializer):
diff --git a/api/views.py b/api/views.py
--- a/api/views.py
+++ b/api/views.py
@@ -14,7 +14,7 @@
 from workshops.util import get_members, default_membership_cutoff
 
 from .serializers import (
-    PersonNameEmailSerializer,
+    PersonNameEmailUsernameSerializer,
     ExportBadgesSerializer,
     ExportInstructorLocationsSerializer,
     EventSerializer,
@@ -73,10 +73,10 @@ class ExportInstructorLocationsView(ListAPIView):
 
 class ExportMembersView(ListAPIView):
     """Show everyone who qualifies as an SCF member."""
-    permission_classes = (IsAuthenticatedOrReadOnly, )
+    permission_classes = (IsAuthenticated, )
     paginator = None  # disable pagination
 
-    serializer_class = PersonNameEmailSerializer
+    serializer_class = PersonNameEmailUsernameSerializer
 
     def get_queryset(self):
         earliest_default, latest_default = default_membership_cutoff()


Test patch:
diff --git a/api/test/test_export.py b/api/test/test_export.py
--- a/api/test/test_export.py
+++ b/api/test/test_export.py
@@ -28,6 +28,12 @@ def setUp(self):
         # 0064
         Badge.objects.all().delete()
 
+    def login(self):
+        self.admin = Person.objects.create_superuser(
+                username="admin", personal="Super", family="User",
+                email="sudo@example.org", password='admin')
+        self.client.login(username='admin', password='admin')
+
 
 class TestExportingBadges(BaseExportingTest):
     def setUp(self):
@@ -170,7 +176,8 @@ def setUp(self):
         self.expecting = [
             {
                 'name': 'Peter Q. Parker',
-                'email': 'peter@webslinger.net'
+                'email': 'peter@webslinger.net',
+                'username': 'spiderman',
             },
         ]
 
@@ -183,9 +190,18 @@ def test_serialization(self, mock_request):
         response = serializer(view.get_queryset(), many=True)
         self.assertEqual(response.data, self.expecting)
 
+    def test_requires_login(self):
+        url = reverse('api:export-members')
+        response = self.client.get(url, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        self.login()
+        response = self.client.get(url, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
     def test_view_default_cutoffs(self):
         # test only JSON output
         url = reverse('api:export-members')
+        self.login()
         response = self.client.get(url, format='json')
         content = response.content.decode('utf-8')
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -195,6 +211,7 @@ def test_view_explicit_earliest(self):
         url = reverse('api:export-members')
         data = {'earliest': universal_date_format(datetime.date.today())}
 
+        self.login()
         response = self.client.get(url, data, format='json')
         content = response.content.decode('utf-8')
         self.assertEqual(response.status_code, status.HTTP_200_OK)