Skip to content

Commit

Permalink
feat: allow disabling user tours
Browse files Browse the repository at this point in the history
A similar waffle flag was dropped in 2038633.

(cherry picked from commit 21f2e30)
  • Loading branch information
Agrendalath committed Feb 7, 2024
1 parent 43fbbf6 commit c352d5b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
15 changes: 15 additions & 0 deletions lms/djangoapps/user_tours/toggles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Toggles for the User Tours Experience.
"""

from edx_toggles.toggles import WaffleFlag

# .. toggle_name: user_tours.tours_disabled
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
# .. toggle_description: This flag disables user tours in LMS.
# .. toggle_warnings: None
# .. toggle_use_cases: opt_out
# .. toggle_creation_date: 2024-02-06
# .. toggle_target_removal_date: None
USER_TOURS_DISABLED = WaffleFlag('user_tours.tours_disabled', module_name=__name__, log_prefix='user_tours')
19 changes: 19 additions & 0 deletions lms/djangoapps/user_tours/v1/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
from django.db.models.signals import post_save
from django.test import TestCase, override_settings
from django.urls import reverse
from edx_toggles.toggles.testutils import override_waffle_flag
from rest_framework import status

from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.user_tours.handlers import init_user_tour
from lms.djangoapps.user_tours.models import UserTour, UserDiscussionsTours
from lms.djangoapps.user_tours.toggles import USER_TOURS_DISABLED
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user

User = get_user_model()
Expand Down Expand Up @@ -47,6 +49,13 @@ def send_request(self, jwt_user, request_user, method, data=None):
elif method == 'PATCH':
return self.client.patch(url, data, content_type='application/json', **headers)

@ddt.data('GET', 'PATCH')
@override_waffle_flag(USER_TOURS_DISABLED, active=True)
def test_tours_disabled(self, method):
""" Test that the tours can be turned off with a waffle flag. """
response = self.send_request(self.staff_user, self.user, method)
assert response.status_code == status.HTTP_403_FORBIDDEN

@ddt.data('GET', 'PATCH')
def test_unauthorized_user(self, method):
""" Test all endpoints if request does not have jwt auth. """
Expand Down Expand Up @@ -188,6 +197,11 @@ def test_get_tours(self):
self.assertEqual(response.data[1]['tour_name'], 'not_responded_filter')
self.assertTrue(response.data[1]['show_tour'])

# Test that the view can be disabled by a waffle flag.
with override_waffle_flag(USER_TOURS_DISABLED, active=True):
response = self.client.get(self.url, **headers)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_get_tours_unauthenticated(self):
"""
Test that an unauthenticated user cannot access the discussion tours endpoint.
Expand Down Expand Up @@ -215,3 +229,8 @@ def test_update_tour(self):
# Check that the tour was updated in the database
updated_tour = UserDiscussionsTours.objects.get(id=self.tour.id)
self.assertEqual(updated_tour.show_tour, False)

# Test that the view can be disabled by a waffle flag.
with override_waffle_flag(USER_TOURS_DISABLED, active=True):
response = self.client.put(url, updated_data, content_type='application/json', **headers)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
18 changes: 15 additions & 3 deletions lms/djangoapps/user_tours/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from rest_framework import status

from lms.djangoapps.user_tours.models import UserTour, UserDiscussionsTours
from lms.djangoapps.user_tours.toggles import USER_TOURS_DISABLED
from lms.djangoapps.user_tours.v1.serializers import UserTourSerializer, UserDiscussionsToursSerializer

from rest_framework.views import APIView
Expand Down Expand Up @@ -41,9 +42,12 @@ def get(self, request, username): # pylint: disable=arguments-differ
400 if there is a not allowed request (requesting a user you don't have access to)
401 if unauthorized request
403 if waffle flag is not enabled
403 if tours are disabled
404 if the UserTour does not exist (shouldn't happen, but safety first)
"""
if USER_TOURS_DISABLED.is_enabled():
return Response(status=status.HTTP_403_FORBIDDEN)

if request.user.username != username and not request.user.is_staff:
return Response(status=status.HTTP_400_BAD_REQUEST)

Expand All @@ -66,8 +70,11 @@ def patch(self, request, username): # pylint: disable=arguments-differ
400 if update was unsuccessful or there was nothing to update
401 if unauthorized request
403 if waffle flag is not enabled
403 if tours are disabled
"""
if USER_TOURS_DISABLED.is_enabled():
return Response(status=status.HTTP_403_FORBIDDEN)

if request.user.username != username:
return Response(status=status.HTTP_400_BAD_REQUEST)

Expand Down Expand Up @@ -125,8 +132,11 @@ def get(self, request, tour_id=None):
"user": 1
}
]
403 if the tours are disabled
"""
if USER_TOURS_DISABLED.is_enabled():
return Response(status=status.HTTP_403_FORBIDDEN)
try:
with transaction.atomic():
tours = UserDiscussionsTours.objects.filter(user=request.user)
Expand Down Expand Up @@ -158,9 +168,11 @@ def put(self, request, tour_id):
Returns:
200: The updated tour, serialized using the UserDiscussionsToursSerializer
404: If the tour does not exist
403: If the user does not have permission to update the tour
403: If the user does not have permission to update the tour or the tours are disabled
400: Validation error
"""
if USER_TOURS_DISABLED.is_enabled():
return Response(status=status.HTTP_403_FORBIDDEN)
tour = get_object_or_404(UserDiscussionsTours, pk=tour_id)
if tour.user != request.user:
return Response(status=status.HTTP_403_FORBIDDEN)
Expand Down

0 comments on commit c352d5b

Please sign in to comment.