Repository: apluslms/a-plus

Issue:
Teacher should be able to change the teachers of the course
Currently, only A+ admins may change the teachers of a course (model `Course` defines the teachers for all `CourseInstances` of the course). However, this has been an unnecessary hindrance that causes extra manual work and it is annoying to contact admins for such a trivial task. A teacher should be able to add and remove other teachers in the course himself/herself. It should be even possible to remove oneself as the teacher, after which one can no longer access the edit course page.

The edit course form already displays the teachers of the course. It can be changed so that the teachers are edited there. The assistants are already edited in the same form.


Discussion:
Seppo is trying to fix this now.

Resolving patch:
diff --git a/edit_course/course_forms.py b/edit_course/course_forms.py
--- a/edit_course/course_forms.py
+++ b/edit_course/course_forms.py
@@ -4,7 +4,7 @@
 from django_colortag.forms import ColorTagForm
 
 from aplus.api import api_reverse
-from course.models import LearningObjectCategory, CourseModule, CourseInstance, UserTag
+from course.models import LearningObjectCategory, Course, CourseModule, CourseInstance, UserTag
 from lib.validators import generate_url_key_validator
 from lib.fields import UsersSearchSelectField
 from userprofile.models import UserProfile
@@ -145,6 +145,24 @@ class Meta:
         ]
 
 
+class CourseTeachersForm(forms.ModelForm):
+
+    teachers = UsersSearchSelectField(queryset=UserProfile.objects.all(),
+        initial_queryset=UserProfile.objects.none(),
+        required=False) # Not required because a course does not have to have any teachers.
+
+    class Meta:
+        model = Course
+        fields = [
+            'teachers'
+        ]
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.fields['teachers'].initial_queryset = self.instance.teachers.all()
+        self.fields['teachers'].widget.attrs["data-search-api-url"] = api_reverse("user-list")
+
+
 class CloneInstanceForm(forms.Form):
     url = forms.CharField(label=_("New URL identifier for the course instance:"),
         validators=[generate_url_key_validator()])
diff --git a/edit_course/urls.py b/edit_course/urls.py
--- a/edit_course/urls.py
+++ b/edit_course/urls.py
@@ -16,6 +16,9 @@
     url(EDIT_URL_PREFIX + r'course/$',
         views.EditInstanceView.as_view(),
         name='course-details'),
+    url(EDIT_URL_PREFIX + r'teachers/$',
+        views.EditTeachersView.as_view(),
+        name='course-teachers'),
     url(EDIT_URL_PREFIX + r'index/$',
         views.EditIndexView.as_view(),
         name='course-index'),
diff --git a/edit_course/views.py b/edit_course/views.py
--- a/edit_course/views.py
+++ b/edit_course/views.py
@@ -26,8 +26,9 @@
 from exercise.cache.exercise import invalidate_instance
 from exercise.cache.hierarchy import NoSuchContent
 from exercise.models import LearningObject
-from .course_forms import CourseInstanceForm, CourseIndexForm, \
-    CourseContentForm, CloneInstanceForm, UserTagForm, SelectUsersForm
+from .course_forms import CourseInstanceForm, CourseTeachersForm, \
+    CourseIndexForm, CourseContentForm, CloneInstanceForm, UserTagForm, \
+    SelectUsersForm
 from .managers import CategoryManager, ModuleManager, ExerciseManager
 
 
@@ -54,6 +55,29 @@ def form_invalid(self, form):
         return super().form_invalid(form)
 
 
+class EditTeachersView(CourseInstanceMixin, BaseFormView):
+    access_mode = ACCESS.TEACHER
+    template_name = "edit_course/edit_teachers.html"
+    form_class = CourseTeachersForm
+
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs["instance"] = self.course
+        return kwargs
+
+    def get_success_url(self):
+        return self.instance.get_url('course-teachers')
+
+    def form_valid(self, form):
+        self.course = form.save()
+        messages.success(self.request, _("Changes were saved succesfully."))
+        return super().form_valid(form)
+
+    def form_invalid(self, form):
+        messages.error(self.request, _("Failed to save changes."))
+        return super().form_invalid(form)
+
+
 class EditIndexView(EditInstanceView):
     template_name = "edit_course/edit_index.html"
     form_class = CourseIndexForm


Test patch: