Repository: apluslms/a-plus

Issue:
API: Submission sheet won't work correctly with groups.
```python
        for profile in s.submitters.all():
            row['UserID'] = profile.user.id
            row['StudentID'] = profile.student_id
            row['Email'] = profile.user.email
            sheet.append(row)
```
on https://github.com/Aalto-LeTech/a-plus/blob/master/exercise/api/submission_sheet.py#L107

Above code will change dictionary for previous lines. Second student would need a copy of the dictionary.


Discussion:

Resolving patch:
diff --git a/edit_course/operations/configure.py b/edit_course/operations/configure.py
--- a/edit_course/operations/configure.py
+++ b/edit_course/operations/configure.py
@@ -226,7 +226,7 @@ def configure_content(instance, url):
         config = json.loads(response.text)
     except Exception as e:
         return [_("JSON parser raised error '{error!s}'. "
-                  "Configuration of course aborted.".format(error=e))]
+                  "Configuration of course aborted.").format(error=e)]
 
     errors = []
 
diff --git a/exercise/api/submission_sheet.py b/exercise/api/submission_sheet.py
--- a/exercise/api/submission_sheet.py
+++ b/exercise/api/submission_sheet.py
@@ -104,10 +104,11 @@ def url(submission, obj):
                 files.append(f.param_name)
             row[f.param_name] = url(s,f)
 
-        for profile in s.submitters.all():
-            row['UserID'] = profile.user.id
-            row['StudentID'] = profile.student_id
-            row['Email'] = profile.user.email
-            sheet.append(row)
+        for i,profile in enumerate(s.submitters.all()):
+            r = row.copy() if i > 0 else row
+            r['UserID'] = profile.user.id
+            r['StudentID'] = profile.student_id
+            r['Email'] = profile.user.email
+            sheet.append(r)
 
     return sheet,fields,files
diff --git a/exercise/api/views.py b/exercise/api/views.py
--- a/exercise/api/views.py
+++ b/exercise/api/views.py
@@ -346,9 +346,13 @@ def int_or_none(value):
         }
 
     def list(self, request, version=None, course_id=None):
+        profiles = self.filter_queryset(self.get_queryset())
         search_args = self.get_search_args(request)
         ids = [e['id'] for e in self.content.search_exercises(**search_args)]
-        queryset = Submission.objects.filter(exercise_id__in=ids)
+        queryset = Submission.objects.filter(
+            exercise_id__in=ids,
+            submitters__in=profiles
+        )
         return self.serialize_submissions(request, queryset, best=search_args['best'])
 
     def retrieve(self, request, version=None, course_id=None, user_id=None):


Test patch:
diff --git a/exercise/tests.py b/exercise/tests.py
--- a/exercise/tests.py
+++ b/exercise/tests.py
@@ -209,7 +209,7 @@ def setUp(self):
         self.late_late_submission_when_late_allowed.submitters.add(self.user.userprofile)
 
         self.course_hook = CourseHook.objects.create(
-            hook_url="test_hook_url",
+            hook_url="http://localhost/test_hook_url",
             course_instance=self.course_instance
         )
 
@@ -484,7 +484,7 @@ def test_unofficial_submission(self):
         self.assertEqual(self.late_submission_when_late_allowed.grade, 100)
         self.assertEqual(self.late_submission_when_late_allowed.status, Submission.STATUS.UNOFFICIAL)
         summary = UserExerciseSummary(self.base_exercise_with_late_submission_allowed, self.user)
-        self.assertEqual(summary.get_submission_count(), 0)
+        self.assertEqual(summary.get_submission_count(), 3)
         self.assertEqual(summary.get_points(), 100)
         self.assertFalse(summary.is_graded())
         self.assertTrue(summary.is_unofficial())
diff --git a/selenium_test/test/page_objects.py b/selenium_test/test/page_objects.py
--- a/selenium_test/test/page_objects.py
+++ b/selenium_test/test/page_objects.py
@@ -39,7 +39,8 @@ def load(self, url, loaded_check=None):
         self.driver.get(url)
         if loaded_check:
             self.waitForElement(loaded_check)
-        self.checkBrowserErrors()
+        # The log command is not supported.
+        #self.checkBrowserErrors()
 
     def clickThrough(self, element, timeout=None):
         try:
diff --git a/selenium_test/test/test_initializer.py b/selenium_test/test/test_initializer.py
--- a/selenium_test/test/test_initializer.py
+++ b/selenium_test/test/test_initializer.py
@@ -9,7 +9,7 @@
 class TestInitializer(object):
 
     def getDefaultDriver(self):
-        driver = self.getChromeDriver()
+        driver = self.getFirefoxDriver()
         driver.set_window_size(1024,768)
         return driver
 
@@ -23,12 +23,7 @@ def getChromeDriver(self):
         return webdriver.Chrome()
 
     def getFirefoxDriver(self):
-        firefoxCapabilities =  DesiredCapabilities.FIREFOX
-        firefoxCapabilities['marionette'] = True
-        firefoxCapabilities['loggingPrefs'] = {'Browser': 'ALL'}
-        profile = webdriver.FirefoxProfile()
-        profile.set_preference('startup.homepage_welcome_url.additional', '')
-        return webdriver.Firefox(profile, capabilities=firefoxCapabilities)
+        return webdriver.Firefox()
 
     # This just replaces the current database with a copy.
     # TODO Should use Django unit tests that run selenium.