diff --git a/lms/djangoapps/lms_xblock/runtime.py b/lms/djangoapps/lms_xblock/runtime.py index 3df3c6a899b18698189d15277e8992992c834b43..1a31eaa3f65f31c57456bbaf92ec1a8da63f7444 100644 --- a/lms/djangoapps/lms_xblock/runtime.py +++ b/lms/djangoapps/lms_xblock/runtime.py @@ -13,6 +13,7 @@ from edx_django_utils.cache import DEFAULT_REQUEST_CACHE from badges.service import BadgingService from badges.utils import badges_enabled from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig +from lms.djangoapps.teams.services import TeamsService from openedx.core.djangoapps.user_api.course_tag import api as user_course_tag_api from openedx.core.lib.url_utils import quote_slashes from openedx.core.lib.xblock_utils import wrap_xblock_aside, xblock_local_resource_url @@ -155,6 +156,7 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method if badges_enabled(): services['badging'] = BadgingService(course_id=kwargs.get('course_id'), modulestore=store) self.request_token = kwargs.pop('request_token', None) + services['teams'] = TeamsService() super(LmsModuleSystem, self).__init__(**kwargs) def handler_url(self, *args, **kwargs): diff --git a/lms/djangoapps/teams/api.py b/lms/djangoapps/teams/api.py index 39ab79e957d820afdbc791334023e835430a6d66..01f6f8d0aa0fe5fdde387dc8408f731ea1bca521 100644 --- a/lms/djangoapps/teams/api.py +++ b/lms/djangoapps/teams/api.py @@ -7,6 +7,8 @@ import logging from enum import Enum from django.db.models import Count +from opaque_keys import InvalidKeyError +from opaque_keys.edx.keys import CourseKey from course_modes.models import CourseMode from lms.djangoapps.discussion.django_comment_client.utils import has_discussion_privileges @@ -241,3 +243,22 @@ def can_user_create_team_in_topic(user, course_id, topic_id): (not is_instructor_managed_topic(topic_id)) or has_course_staff_privileges(user, course_id) ) + + +def get_team_for_user_and_course(user, course_id): + """ + Returns the team that the given user is on in the course, or None + + If course_id does not exist, a ValueError is raised + """ + try: + course_key = CourseKey.from_string(course_id) + except InvalidKeyError: + raise ValueError(u"The supplied course id {course_id} is not valid.".format( + course_id=course_id + )) + + return CourseTeam.objects.filter( + course_id=course_key, + membership__user__username=user.username, + ).first() diff --git a/lms/djangoapps/teams/services.py b/lms/djangoapps/teams/services.py new file mode 100644 index 0000000000000000000000000000000000000000..486a2a81d820bb4eef95735eee8ab5ab3e77ea4b --- /dev/null +++ b/lms/djangoapps/teams/services.py @@ -0,0 +1,21 @@ +""" Services to expose the Teams API to XBlocks """ +from __future__ import absolute_import + +from django.urls import reverse + + +class TeamsService(object): + """ Functions to provide teams functionality to XBlocks""" + def get_team(self, user, course_id): + from . import api + return api.get_team_for_user_and_course(user, course_id) + + def get_team_detail_url(self, team): + """ Returns the url to the detail view for the given team """ + teams_dashboard_url = reverse('teams_dashboard', kwargs={'course_id': team.course_id}) + # Unfortunately required since this URL resolution is done in a Backbone view + return "{teams_dashboard_url}#teams/{topic_id}/{team_id}".format( + teams_dashboard_url=teams_dashboard_url, + topic_id=team.topic_id, + team_id=team.team_id, + ) diff --git a/lms/djangoapps/teams/tests/factories.py b/lms/djangoapps/teams/tests/factories.py index 77466de97b388c2a0ae7d460e96d9ee50de4f7be..b1917a49b11ebaa6f5111481e1722f39cfa8c6be 100644 --- a/lms/djangoapps/teams/tests/factories.py +++ b/lms/djangoapps/teams/tests/factories.py @@ -25,6 +25,7 @@ class CourseTeamFactory(DjangoModelFactory): django_get_or_create = ('team_id',) team_id = factory.Sequence('team-{0}'.format) + topic_id = factory.Sequence('topic-{0}'.format) discussion_topic_id = factory.LazyAttribute(lambda a: uuid4().hex) name = factory.Sequence(u"Awesome Team {0}".format) description = "A simple description" diff --git a/lms/djangoapps/teams/tests/test_api.py b/lms/djangoapps/teams/tests/test_api.py index 58efde255733e315b035253ae35343211bce0f83..fb4ab853d7697565ec6860eca226117972387545 100644 --- a/lms/djangoapps/teams/tests/test_api.py +++ b/lms/djangoapps/teams/tests/test_api.py @@ -81,6 +81,35 @@ class PythonAPITests(SharedModuleStoreTestCase): self.assertTrue(teams_api.discussion_visible_by_user(self.team2.discussion_topic_id, self.user2)) self.assertTrue(teams_api.discussion_visible_by_user('DO_NOT_EXISTS', self.user3)) + def test_get_team(self): + # Course 1 + user1_team = teams_api.get_team_for_user_and_course(self.user1, str(COURSE_KEY1)) + user2_team = teams_api.get_team_for_user_and_course(self.user2, str(COURSE_KEY1)) + user3_team = teams_api.get_team_for_user_and_course(self.user3, str(COURSE_KEY1)) + + self.assertEqual(user1_team, self.team1) + self.assertEqual(user2_team, self.team1) + self.assertEqual(user3_team, None) + + # Course 2 + user1_team = teams_api.get_team_for_user_and_course(self.user1, str(COURSE_KEY2)) + user2_team = teams_api.get_team_for_user_and_course(self.user2, str(COURSE_KEY2)) + user3_team = teams_api.get_team_for_user_and_course(self.user3, str(COURSE_KEY2)) + + self.assertEqual(user1_team, None) + self.assertEqual(user2_team, None) + self.assertEqual(user3_team, self.team2) + + def test_get_team_invalid_course(self): + invalid_course_id = 'lol!()#^$&course' + message = 'The supplied course id lol!()#^$&course is not valid' + with self.assertRaisesMessage(ValueError, message): + teams_api.get_team_for_user_and_course(self.user1, invalid_course_id) + + def test_get_team_course_not_found(self): + team = teams_api.get_team_for_user_and_course(self.user1, 'nonsense/garbage/nonexistant') + self.assertIsNone(team) + @ddt.ddt class TeamAccessTests(SharedModuleStoreTestCase): diff --git a/lms/djangoapps/teams/tests/test_services.py b/lms/djangoapps/teams/tests/test_services.py new file mode 100644 index 0000000000000000000000000000000000000000..09708e631032150d3caf2f8475859c04b493f7a0 --- /dev/null +++ b/lms/djangoapps/teams/tests/test_services.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +""" +Tests for any Teams app services +""" +from __future__ import absolute_import, unicode_literals + +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from openedx.core.djangoapps.catalog.tests.factories import CourseRunFactory + +from lms.djangoapps.teams.services import TeamsService +from lms.djangoapps.teams.tests.factories import CourseTeamFactory + + +class TeamsServiceTests(ModuleStoreTestCase): + """ Tests for the TeamsService """ + + def setUp(self): + super(TeamsServiceTests, self).setUp() + self.course_run = CourseRunFactory.create() + self.team = CourseTeamFactory.create(course_id=self.course_run['key']) + self.service = TeamsService() + + def test_get_team_detail_url(self): + # edx.org/courses/blah/teams/#teams/topic_id/team_id + team_detail_url = self.service.get_team_detail_url(self.team) + split_url = team_detail_url.split('/') + self.assertEqual( + split_url[1:], + [ + 'courses', + str(self.course_run['key']), + 'teams', + '#teams', + self.team.topic_id, + self.team.team_id, + ] + )