diff --git a/lms/services/dashboard.py b/lms/services/dashboard.py index 26bb910471..689caeaa43 100644 --- a/lms/services/dashboard.py +++ b/lms/services/dashboard.py @@ -17,7 +17,7 @@ def __init__( self._course_service = course_service self._organization_service = organization_service - def get_request_assignment(self, request, admin_organizations: list[Organization]): + def get_request_assignment(self, request): """Get and authorize an assignment for the given request.""" assigment_id = request.matchdict.get( "assignment_id" @@ -30,6 +30,7 @@ def get_request_assignment(self, request, admin_organizations: list[Organization # STAFF members in our admin pages can access all assignments return assignment + admin_organizations = self.get_request_admin_organizations(request) if ( admin_organizations and assignment.course.application_instance.organization @@ -43,7 +44,7 @@ def get_request_assignment(self, request, admin_organizations: list[Organization return assignment - def get_request_course(self, request, admin_organizations: list[Organization]): + def get_request_course(self, request): """Get and authorize a course for the given request.""" course = self._course_service.get_by_id(request.matchdict["course_id"]) if not course: @@ -53,6 +54,7 @@ def get_request_course(self, request, admin_organizations: list[Organization]): # STAFF members in our admin pages can access all courses return course + admin_organizations = self.get_request_admin_organizations(request) if ( admin_organizations and course.application_instance.organization in admin_organizations @@ -65,23 +67,6 @@ def get_request_course(self, request, admin_organizations: list[Organization]): return course - def get_request_organization(self, request) -> Organization | None: - """Get and authorize an organization.""" - if not request.has_permission(Permissions.STAFF): - # For now only staff request are scoped to an organization - return None - - request_public_id = request.parsed_params.get("public_id") - if not request_public_id: - # Only relevant for request that include the query parameter - return None - - organization = self._organization_service.get_by_public_id(request_public_id) - if not organization: - raise HTTPNotFound() - - return organization - def get_organizations_by_admin_email(self, email: str) -> list[Organization]: """Get a list of organizations where the user with email `email` is an admin in.""" return self._db.scalars( @@ -105,6 +90,26 @@ def delete_dashboard_admin(self, dashboard_admin_id: int) -> None: """Delete an existing dashboard admin.""" self._db.query(DashboardAdmin).filter_by(id=dashboard_admin_id).delete() + def get_request_admin_organizations(self, request) -> list[Organization]: + """Get the organization the current user is an admin in.""" + if request.has_permission(Permissions.STAFF) and ( + request_public_id := request.params.get("public_id") + ): + # We special case permissions/filtering for staff members + # If the requests contains a filter for one organization will act as if the staff member + # is an admin in that organization. That will give access to its data and filter by it + organization = self._organization_service.get_by_public_id( + request_public_id + ) + if not organization: + raise HTTPNotFound() + + return [organization] + + return self.get_organizations_by_admin_email( + request.lti_user.email if request.lti_user else request.identity.userid + ) + def factory(_context, request): return DashboardService( diff --git a/lms/views/dashboard/api/assignment.py b/lms/views/dashboard/api/assignment.py index 28a44b1075..652258c060 100644 --- a/lms/views/dashboard/api/assignment.py +++ b/lms/views/dashboard/api/assignment.py @@ -26,6 +26,9 @@ class ListAssignmentsSchema(PaginationParametersMixin): h_userids = fields.List(fields.Str(), data_key="h_userid") """Return metrics for these users only.""" + public_id = fields.Str() + """Return only the assignments which belong to this organization. For staff member only.""" + class AssignmentsMetricsSchema(PyramidRequestSchema): """Query parameters to fetch metrics for assignments.""" @@ -38,6 +41,9 @@ class AssignmentsMetricsSchema(PyramidRequestSchema): assignment_ids = fields.List(fields.Integer(), data_key="assignment_id") """Return metrics for these assignments only.""" + public_id = fields.Str() + """Return only the assignments which belong to this organization. For staff member only.""" + class AssignmentViews: def __init__(self, request) -> None: @@ -48,12 +54,6 @@ def __init__(self, request) -> None: self.course_service = request.find_service(name="course") self.user_service: UserService = request.find_service(UserService) - self.admin_organizations = ( - self.dashboard_service.get_organizations_by_admin_email( - request.lti_user.email if request.lti_user else request.identity.userid - ) - ) - @view_config( route_name="api.dashboard.assignments", request_method="GET", @@ -63,8 +63,12 @@ def __init__(self, request) -> None: ) def assignments(self) -> APIAssignments: filter_by_h_userids = self.request.parsed_params.get("h_userids") + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request + ) + assignments = self.assignment_service.get_assignments( - admin_organization_ids=[org.id for org in self.admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], instructor_h_userid=self.request.user.h_userid if self.request.user else None, @@ -89,9 +93,7 @@ def assignments(self) -> APIAssignments: permission=Permissions.DASHBOARD_VIEW, ) def assignment(self) -> APIAssignment: - assignment = self.dashboard_service.get_request_assignment( - self.request, self.admin_organizations - ) + assignment = self.dashboard_service.get_request_assignment(self.request) return APIAssignment( id=assignment.id, title=assignment.title, @@ -106,24 +108,27 @@ def assignment(self) -> APIAssignment: schema=AssignmentsMetricsSchema, ) def course_assignments_metrics(self) -> APIAssignments: + # pylint:disable=too-many-locals current_h_userid = self.request.user.h_userid if self.request.user else None filter_by_h_userids = self.request.parsed_params.get("h_userids") filter_by_assignment_ids = self.request.parsed_params.get("assignment_ids") - course = self.dashboard_service.get_request_course( - self.request, self.admin_organizations + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request ) + + course = self.dashboard_service.get_request_course(self.request) course_students = self.request.db.scalars( self.user_service.get_users( course_ids=[course.id], role_scope=RoleScope.COURSE, role_type=RoleType.LEARNER, instructor_h_userid=current_h_userid, - admin_organization_ids=[org.id for org in self.admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], h_userids=filter_by_h_userids, ) ).all() assignments_query = self.assignment_service.get_assignments( - admin_organization_ids=[org.id for org in self.admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], course_ids=[course.id], instructor_h_userid=current_h_userid, h_userids=filter_by_h_userids, diff --git a/lms/views/dashboard/api/course.py b/lms/views/dashboard/api/course.py index 8c0ff349bd..613e156d1e 100644 --- a/lms/views/dashboard/api/course.py +++ b/lms/views/dashboard/api/course.py @@ -20,7 +20,7 @@ class ListCoursesSchema(PaginationParametersMixin): """Return only the courses to which these assigments belong.""" public_id = fields.Str() - """Return only the courses which belong to this organization.""" + """Return only the courses which belong to this organization. For staff member only.""" class CoursesMetricsSchema(PyramidRequestSchema): @@ -38,7 +38,7 @@ class CoursesMetricsSchema(PyramidRequestSchema): """Return metrics for these courses only.""" public_id = fields.Str() - """Return only the courses which belong to this organization.""" + """Return only the courses which belong to this organization. For staff member only.""" class CourseViews: @@ -60,9 +60,12 @@ def __init__(self, request) -> None: def courses(self) -> APICourses: filter_by_h_userids = self.request.parsed_params.get("h_userids") filter_by_assignment_ids = self.request.parsed_params.get("assignment_ids") + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request + ) courses = self.course_service.get_courses( - admin_organization_ids=[org.id for org in self._admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], instructor_h_userid=self.request.user.h_userid if self.request.user else None, @@ -90,9 +93,12 @@ def courses_metrics(self) -> APICourses: filter_by_h_userids = self.request.parsed_params.get("h_userids") filter_by_assignment_ids = self.request.parsed_params.get("assignment_ids") filter_by_course_ids = self.request.parsed_params.get("course_ids") + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request + ) courses_query = self.course_service.get_courses( - admin_organization_ids=[org.id for org in self._admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], instructor_h_userid=self.request.user.h_userid if self.request.user else None, @@ -130,27 +136,8 @@ def courses_metrics(self) -> APICourses: permission=Permissions.DASHBOARD_VIEW, ) def course(self) -> APICourse: - course = self.dashboard_service.get_request_course( - self.request, self._admin_organizations - ) + course = self.dashboard_service.get_request_course(self.request) return { "id": course.id, "title": course.lms_name, } - - @property - def _admin_organizations(self): - request_organization = self.dashboard_service.get_request_organization( - self.request - ) - if request_organization and self.request.has_permission(Permissions.STAFF): - # We special case permissions/filtering for staff members - # If the requests contains a filter for one organization will act as if the staff member - # is an admin in that organization. That will give access to its data and filter by it - return [request_organization] - - return self.dashboard_service.get_organizations_by_admin_email( - self.request.lti_user.email - if self.request.lti_user - else self.request.identity.userid - ) diff --git a/lms/views/dashboard/api/user.py b/lms/views/dashboard/api/user.py index 4ab40f0692..55aea514f9 100644 --- a/lms/views/dashboard/api/user.py +++ b/lms/views/dashboard/api/user.py @@ -27,6 +27,9 @@ class ListUsersSchema(PaginationParametersMixin): ) """Return users that belong to the assignment with these IDs.""" + public_id = fields.Str() + """Return only the users which belong to this organization. For staff member only.""" + class UsersMetricsSchema(PyramidRequestSchema): """Query parameters to fetch metrics for users.""" @@ -39,6 +42,9 @@ class UsersMetricsSchema(PyramidRequestSchema): h_userids = fields.List(fields.Str(), data_key="h_userid") """Return metrics for these users only.""" + public_id = fields.Str() + """Return only the users which belong to this organization. For staff member only.""" + class UserViews: def __init__(self, request) -> None: @@ -48,12 +54,6 @@ def __init__(self, request) -> None: self.h_api = request.find_service(HAPI) self.user_service: UserService = request.find_service(UserService) - self.admin_organizations = ( - self.dashboard_service.get_organizations_by_admin_email( - request.lti_user.email if request.lti_user else request.identity.userid - ) - ) - @view_config( route_name="api.dashboard.students", request_method="GET", @@ -62,13 +62,17 @@ def __init__(self, request) -> None: schema=ListUsersSchema, ) def students(self) -> APIStudents: + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request + ) + students_query = self.user_service.get_users( role_scope=RoleScope.COURSE, role_type=RoleType.LEARNER, instructor_h_userid=self.request.user.h_userid if self.request.user else None, - admin_organization_ids=[org.id for org in self.admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], course_ids=self.request.parsed_params.get("course_ids"), assignment_ids=self.request.parsed_params.get("assignment_ids"), ) @@ -96,9 +100,7 @@ def students(self) -> APIStudents: def students_metrics(self) -> APIStudents: """Fetch the stats for one particular assignment.""" request_h_userids = self.request.parsed_params.get("h_userids") - assignment = self.dashboard_service.get_request_assignment( - self.request, self.admin_organizations - ) + assignment = self.dashboard_service.get_request_assignment(self.request) stats = self.h_api.get_annotation_counts( [g.authority_provided_id for g in assignment.groupings], group_by="user", @@ -109,6 +111,10 @@ def students_metrics(self) -> APIStudents: stats_by_user = {s["userid"]: s for s in stats} students: list[APIStudent] = [] + admin_organizations = self.dashboard_service.get_request_admin_organizations( + self.request + ) + users_query = self.user_service.get_users( role_scope=RoleScope.COURSE, role_type=RoleType.LEARNER, @@ -117,7 +123,7 @@ def students_metrics(self) -> APIStudents: instructor_h_userid=self.request.user.h_userid if self.request.user else None, - admin_organization_ids=[org.id for org in self.admin_organizations], + admin_organization_ids=[org.id for org in admin_organizations], # Users the current user requested h_userids=request_h_userids, ) diff --git a/lms/views/dashboard/views.py b/lms/views/dashboard/views.py index 07dbb8ee1a..180bf390a5 100644 --- a/lms/views/dashboard/views.py +++ b/lms/views/dashboard/views.py @@ -77,9 +77,7 @@ def assignment_show(self): Authenticated via the LTIUser present in a cookie making this endpoint accessible directly in the browser. """ - assignment = self.dashboard_service.get_request_assignment( - self.request, self.admin_organizations - ) + assignment = self.dashboard_service.get_request_assignment(self.request) self.request.context.js_config.enable_dashboard_mode() self._set_lti_user_cookie(self.request.response) return {"title": assignment.title} @@ -95,9 +93,7 @@ def course_show(self): Authenticated via the LTIUser present in a cookie making this endpoint accessible directly in the browser. """ - course = self.dashboard_service.get_request_course( - self.request, self.admin_organizations - ) + course = self.dashboard_service.get_request_course(self.request) self.request.context.js_config.enable_dashboard_mode() self._set_lti_user_cookie(self.request.response) return {"title": course.lms_name} diff --git a/tests/unit/lms/services/dashboard_test.py b/tests/unit/lms/services/dashboard_test.py index 5e66dd43f7..12788b26e1 100644 --- a/tests/unit/lms/services/dashboard_test.py +++ b/tests/unit/lms/services/dashboard_test.py @@ -1,4 +1,4 @@ -from unittest.mock import sentinel +from unittest.mock import patch, sentinel import pytest from pyramid.httpexceptions import HTTPNotFound, HTTPUnauthorized @@ -11,41 +11,6 @@ class TestDashboardService: - def test_get_request_organization_for_non_staff(self, pyramid_request, svc): - pyramid_request.parsed_params = {"public_id": sentinel.public_id} - - assert not svc.get_request_organization(pyramid_request) - - def test_get_request_organization_no_parameter( - self, pyramid_request, svc, pyramid_config - ): - pyramid_request.parsed_params = {} - pyramid_config.testing_securitypolicy(permissive=True) - - assert not svc.get_request_organization(pyramid_request) - - def test_get_request_organization_no_organization( - self, pyramid_request, svc, pyramid_config, organization_service - ): - pyramid_config.testing_securitypolicy(permissive=True) - organization_service.get_by_public_id.return_value = None - pyramid_request.parsed_params = {"public_id": sentinel.public_id} - - with pytest.raises(HTTPNotFound): - svc.get_request_organization(pyramid_request) - - def test_get_request_organization( - self, pyramid_request, svc, pyramid_config, organization_service, organization - ): - pyramid_config.testing_securitypolicy(permissive=True) - organization_service.get_by_public_id.return_value = organization - pyramid_request.parsed_params = {"public_id": sentinel.public_id} - - assert svc.get_request_organization(pyramid_request) == organization - organization_service.get_by_public_id.assert_called_once_with( - sentinel.public_id - ) - def test_get_request_assignment_404( self, pyramid_request, @@ -56,7 +21,7 @@ def test_get_request_assignment_404( assignment_service.get_by_id.return_value = None with pytest.raises(HTTPNotFound): - svc.get_request_assignment(pyramid_request, []) + svc.get_request_assignment(pyramid_request) def test_get_request_assignment_403( self, @@ -68,7 +33,7 @@ def test_get_request_assignment_403( assignment_service.is_member.return_value = False with pytest.raises(HTTPUnauthorized): - svc.get_request_assignment(pyramid_request, []) + svc.get_request_assignment(pyramid_request) def test_get_request_assignment_for_staff( self, pyramid_request, assignment_service, pyramid_config, svc @@ -77,13 +42,13 @@ def test_get_request_assignment_for_staff( pyramid_request.matchdict["assignment_id"] = sentinel.id assignment_service.is_member.return_value = False - assert svc.get_request_assignment(pyramid_request, []) + assert svc.get_request_assignment(pyramid_request) def test_get_request_assignment(self, pyramid_request, assignment_service, svc): pyramid_request.matchdict["assignment_id"] = sentinel.id assignment_service.is_member.return_value = True - assert svc.get_request_assignment(pyramid_request, []) + assert svc.get_request_assignment(pyramid_request) assignment_service.is_member.assert_called_once_with( assignment_service.get_by_id.return_value, pyramid_request.user.h_userid @@ -97,16 +62,18 @@ def test_get_request_assignment_for_admin( organization, db_session, application_instance, + get_request_admin_organizations, ): assignment = factories.Assignment() course = factories.Course(application_instance=application_instance) factories.AssignmentGrouping(assignment=assignment, grouping=course) assignment_service.get_by_id.return_value = assignment + get_request_admin_organizations.return_value = [organization] db_session.flush() pyramid_request.matchdict["assignment_id"] = sentinel.id - assert svc.get_request_assignment(pyramid_request, [organization]) + assert svc.get_request_assignment(pyramid_request) def test_get_request_course_404( self, @@ -118,14 +85,14 @@ def test_get_request_course_404( course_service.get_by_id.return_value = None with pytest.raises(HTTPNotFound): - svc.get_request_course(pyramid_request, []) + svc.get_request_course(pyramid_request) def test_get_request_course_403(self, pyramid_request, course_service, svc): pyramid_request.matchdict["course_id"] = sentinel.id course_service.is_member.return_value = False with pytest.raises(HTTPUnauthorized): - svc.get_request_course(pyramid_request, []) + svc.get_request_course(pyramid_request) def test_get_request_course_for_staff( self, pyramid_request, course_service, pyramid_config, svc @@ -134,23 +101,30 @@ def test_get_request_course_for_staff( pyramid_request.matchdict["course_id"] = sentinel.id course_service.is_member.return_value = False - assert svc.get_request_course(pyramid_request, []) + assert svc.get_request_course(pyramid_request) def test_get_request_course_for_admin( - self, pyramid_request, course_service, svc, application_instance, organization + self, + pyramid_request, + course_service, + svc, + application_instance, + organization, + get_request_admin_organizations, ): course_service.get_by_id.return_value = factories.Course( application_instance=application_instance ) + get_request_admin_organizations.return_value = [organization] pyramid_request.matchdict["course_id"] = sentinel.id - assert svc.get_request_course(pyramid_request, [organization]) + assert svc.get_request_course(pyramid_request) def test_get_request_course(self, pyramid_request, course_service, svc): pyramid_request.matchdict["course_id"] = sentinel.id course_service.is_member.return_value = True - assert svc.get_request_course(pyramid_request, []) + assert svc.get_request_course(pyramid_request) def test_add_dashboard_admin(self, svc, db_session): admin = svc.add_dashboard_admin( @@ -177,6 +151,49 @@ def test_get_organizations_by_admin_email(self, svc, db_session, organization): assert svc.get_organizations_by_admin_email(admin.email) == [organization] + def test_get_request_admin_organizations_for_non_staff(self, pyramid_request, svc): + pyramid_request.params = {"public_id": sentinel.public_id} + + assert not svc.get_request_admin_organizations(pyramid_request) + + def test_get_request_admin_organizations_no_parameter( + self, pyramid_request, svc, pyramid_config + ): + pyramid_config.testing_securitypolicy(permissive=True) + + assert not svc.get_request_admin_organizations(pyramid_request) + + def test_get_request_admin_organizations_no_organization( + self, pyramid_request, svc, pyramid_config, organization_service + ): + pyramid_config.testing_securitypolicy(permissive=True) + organization_service.get_by_public_id.return_value = None + pyramid_request.params = {"public_id": sentinel.public_id} + + with pytest.raises(HTTPNotFound): + svc.get_request_admin_organizations(pyramid_request) + + def test_get_request_admin_organizations( + self, pyramid_request, svc, pyramid_config, organization_service, organization + ): + pyramid_config.testing_securitypolicy(permissive=True) + organization_service.get_by_public_id.return_value = organization + pyramid_request.params = {"public_id": sentinel.public_id} + + assert svc.get_request_admin_organizations(pyramid_request) == [organization] + organization_service.get_by_public_id.assert_called_once_with( + sentinel.public_id + ) + + def test_get_request_admin_organizations_for_staff( + self, svc, pyramid_config, pyramid_request, organization, organization_service + ): + pyramid_config.testing_securitypolicy(permissive=True) + pyramid_request.params = {"public_id": sentinel.id} + organization_service.get_by_public_id.return_value = organization + + assert svc.get_request_admin_organizations(pyramid_request) == [organization] + @pytest.fixture() def svc( self, assignment_service, course_service, organization_service, pyramid_request @@ -185,6 +202,13 @@ def svc( pyramid_request, assignment_service, course_service, organization_service ) + @pytest.fixture() + def get_request_admin_organizations(self, svc): + with patch.object( + svc, "get_request_admin_organizations" + ) as get_request_admin_organizations: + yield get_request_admin_organizations + @pytest.fixture(autouse=True) def pyramid_config(self, pyramid_config): pyramid_config.testing_securitypolicy(permissive=False) diff --git a/tests/unit/lms/views/dashboard/api/assignment_test.py b/tests/unit/lms/views/dashboard/api/assignment_test.py index 1fa9eeecd5..5f777a6980 100644 --- a/tests/unit/lms/views/dashboard/api/assignment_test.py +++ b/tests/unit/lms/views/dashboard/api/assignment_test.py @@ -51,8 +51,7 @@ def test_assignment( response = views.assignment() dashboard_service.get_request_assignment.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, + pyramid_request ) assert response == { diff --git a/tests/unit/lms/views/dashboard/api/course_test.py b/tests/unit/lms/views/dashboard/api/course_test.py index 22c4afa3f5..0f474790d0 100644 --- a/tests/unit/lms/views/dashboard/api/course_test.py +++ b/tests/unit/lms/views/dashboard/api/course_test.py @@ -43,30 +43,6 @@ def test_get_courses(self, course_service, pyramid_request, views, get_page): "pagination": sentinel.pagination, } - def test_get_courses_for_staff( - self, - course_service, - pyramid_request, - views, - dashboard_service, - get_page, - pyramid_config, - ): - pyramid_request.parsed_params = {} - get_page.return_value = [], sentinel.pagination - pyramid_config.testing_securitypolicy(permissive=True) - - views.courses() - - course_service.get_courses.assert_called_once_with( - admin_organization_ids=[ - dashboard_service.get_request_organization.return_value.id - ], - instructor_h_userid=pyramid_request.user.h_userid, - h_userids=None, - assignment_ids=None, - ) - def test_course_metrics( self, course_service, pyramid_request, views, db_session, assignment_service ): @@ -147,10 +123,7 @@ def test_course(self, views, pyramid_request, dashboard_service): response = views.course() - dashboard_service.get_request_course.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, - ) + dashboard_service.get_request_course.assert_called_once_with(pyramid_request) assert response == { "id": course.id, diff --git a/tests/unit/lms/views/dashboard/api/user_test.py b/tests/unit/lms/views/dashboard/api/user_test.py index 93d497c057..c2b41ae5bb 100644 --- a/tests/unit/lms/views/dashboard/api/user_test.py +++ b/tests/unit/lms/views/dashboard/api/user_test.py @@ -95,8 +95,7 @@ def test_students_metrics( response = views.students_metrics() dashboard_service.get_request_assignment.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, + pyramid_request ) h_api.get_annotation_counts.assert_called_once_with( [g.authority_provided_id for g in assignment.groupings], diff --git a/tests/unit/lms/views/dashboard/views_test.py b/tests/unit/lms/views/dashboard/views_test.py index 6640c6e593..6b62da1978 100644 --- a/tests/unit/lms/views/dashboard/views_test.py +++ b/tests/unit/lms/views/dashboard/views_test.py @@ -49,8 +49,7 @@ def test_assignment_show(self, views, pyramid_request, dashboard_service): views.assignment_show() dashboard_service.get_request_assignment.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, + pyramid_request ) pyramid_request.context.js_config.enable_dashboard_mode.assert_called_once() assert ( @@ -68,10 +67,7 @@ def test_course_show(self, views, pyramid_request, dashboard_service): views.course_show() - dashboard_service.get_request_course.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, - ) + dashboard_service.get_request_course.assert_called_once_with(pyramid_request) pyramid_request.context.js_config.enable_dashboard_mode.assert_called_once() assert ( pyramid_request.response.headers["Set-Cookie"] @@ -105,8 +101,7 @@ def test_assignment_show_with_no_lti_user( views.assignment_show() dashboard_service.get_request_assignment.assert_called_once_with( - pyramid_request, - dashboard_service.get_organizations_by_admin_email.return_value, + pyramid_request ) pyramid_request.context.js_config.enable_dashboard_mode.assert_called_once()