Repository: apluslms/a-plus

Issue:
API does not show course exercises to the teacher before the opening time (was: in a hidden course)
If a course instance is hidden from students (referring to the "visible to students" checkbox in the course settings), then the teacher does not see the exercises at all in the API endpoint `/api/v2/courses/ID/exercises/`. The teacher should see the exercises since teachers are of course allowed to see their own hidden courses.

Check also if the API hides exercises from teachers in modules that haven't opened yet or have closed. The teacher should see all exercises despite the module opening times.

Edit: see comments below. The "visible to students" checkbox was not a problem, but teachers can not see modules that have not opened yet.

Hints:
* The API view for the course exercises: https://github.com/apluslms/a-plus/blob/0cf8c3126d6011f08201764c3878b930ec4f3e31/course/api/views.py#L64
* The filtering method that is called from the API view: https://github.com/apluslms/a-plus/blob/0cf8c3126d6011f08201764c3878b930ec4f3e31/course/models.py#L657
* The filter builder that seems to think that "visible to students" should apply to all users: https://github.com/apluslms/a-plus/blob/0cf8c3126d6011f08201764c3878b930ec4f3e31/course/models.py#L308


Discussion:
When you modify the `get_course_visibility_filter` function, you need to think of all the old code that uses this same function and what they expect to get from it. Is it safe to directly modify the function or should the calling code be changed too?
This bug doesn't seem to exist if I understand it correctly, all the exercise seem to be shown even when the course is hidden
> This bug doesn't seem to exist if I understand it correctly, all the exercise seem to be shown even when the course is hidden

Did you check the api as `root` or as `teacher`?
> > This bug doesn't seem to exist if I understand it correctly, all the exercise seem to be shown even when the course is hidden
> 
> Did you check the api as `root` or as `teacher`?

I tested as `teacher` and `assistant` no problems there either
@HenrikSundell OK, it looks like that actually, the `visible_to_students` checkbox is not the problem for teachers. The filters use the OR operator so the course visibility can be False if the other filters are True for teachers.

https://github.com/apluslms/a-plus/blob/0cf8c3126d6011f08201764c3878b930ec4f3e31/course/models.py#L329

However, the module opening time is a real problem. Teachers do not see modules (in `/api/v2/courses/ID/exercises/`) that have not opened yet. This line affects teachers, but the teacher should see closed modules in his/her own course: https://github.com/apluslms/a-plus/blob/0cf8c3126d6011f08201764c3878b930ec4f3e31/course/models.py#L666
I assume that all course staff should see the unopened modules. Should this also be fixed for assistants?
> I assume that all course staff should see the unopened modules. Should this also be fixed for assistants?

Yes.

Resolving patch:
diff --git a/course/models.py b/course/models.py
--- a/course/models.py
+++ b/course/models.py
@@ -305,13 +305,10 @@ class Meta:
         ordering = ['tag']
 
 
-def get_course_visibility_filter(user, prefix=None):
+def get_course_staff_visibility_filter(user, prefix=None):
     class OR(Q):
         default = Q.OR
-
-    filters = (
-        ('visible_to_students', True),
-    )
+    filters = ()
     if isinstance(user, User):
         user = user.userprofile
         filters += (
@@ -341,7 +338,10 @@ def get_visible(self, user=None):
         if not user or not user.is_authenticated:
             return self.filter(visible_to_students=True)
         if not user.is_superuser:
-            return self.filter(get_course_visibility_filter(user)).distinct()
+            return self.filter(
+                get_course_staff_visibility_filter(user)
+                | Q(visible_to_students=True),
+            ).distinct()
         return self.all()
 
 
@@ -662,8 +662,8 @@ def get_visible(self, user=None):
             )
         if not user.is_superuser:
             return self.filter(
-                get_course_visibility_filter(user, 'course_instance__'),
-                opening_time__lte=timezone.now(),
+                get_course_staff_visibility_filter(user, 'course_instance__')
+                | Q(course_instance__visible_to_students=True, opening_time__lte=timezone.now()),
             ).distinct()
         return self.all()
 


Test patch: