Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add openedx-filters hook to account settings before rendering it context #31295

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion openedx/core/djangoapps/user_api/accounts/settings_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.decorators.http import require_http_methods
from django_countries import countries

from openedx_filters.learning.filters import AccountSettingsRenderStarted
from common.djangoapps import third_party_auth
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.student.models import UserProfile
Expand Down Expand Up @@ -72,7 +74,25 @@ def account_settings(request):
return redirect(url)

context = account_settings_context(request)
return render_to_response('student_account/account_settings.html', context)

account_settings_template = 'student_account/account_settings.html'

try:
# .. filter_implemented_name: AccountSettingsRenderStarted
# .. filter_type: org.openedx.learning.student.settings.render.started.v1
context, account_settings_template = AccountSettingsRenderStarted.run_filter(
context=context, template_name=account_settings_template,
)
except AccountSettingsRenderStarted.RenderInvalidAccountSettings as exc:
response = render_to_response(exc.account_settings_template, exc.template_context)
except AccountSettingsRenderStarted.RedirectToPage as exc:
response = HttpResponseRedirect(exc.redirect_to or reverse('dashboard'))
except AccountSettingsRenderStarted.RenderCustomResponse as exc:
response = exc.response
else:
response = render_to_response(account_settings_template, context)

return response


def account_settings_context(request):
Expand Down
241 changes: 241 additions & 0 deletions openedx/core/djangoapps/user_api/accounts/tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
"""
Test that various filters are fired for views in the certificates app.
"""
from django.http import HttpResponse
from django.test import override_settings
from django.urls import reverse
from openedx_filters import PipelineStep
from openedx_filters.learning.filters import AccountSettingsRenderStarted
from rest_framework import status
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase

from openedx.core.djangolib.testing.utils import skip_unless_lms
from common.djangoapps.student.tests.factories import UserFactory

mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved

class TestRenderInvalidAccountSettings(PipelineStep):
"""
Utility class used when getting steps for pipeline.
"""

def run_filter(self, context, template_name): # pylint: disable=arguments-differ
"""
Pipeline step that stops the course about render process.
"""
raise AccountSettingsRenderStarted.RenderInvalidAccountSettings(
"You can't access the account settings page.",
account_settings_template="static_templates/server-error.html",
)


class TestRedirectToPage(PipelineStep):
"""
Utility class used when getting steps for pipeline.
"""

def run_filter(self, context, template_name): # pylint: disable=arguments-differ
"""
Pipeline step that redirects to dashboard before rendering the account settings page.

When raising RedirectToPage, this filter uses a redirect_to field handled by
the course about view that redirects to that URL.
"""
raise AccountSettingsRenderStarted.RedirectToPage(
"You can't access this page, redirecting to dashboard.",
redirect_to="/courses",
)


class TestRedirectToDefaultPage(PipelineStep):
"""
Utility class used when getting steps for pipeline.
"""

def run_filter(self, context, template_name): # pylint: disable=arguments-differ
"""
Pipeline step that redirects to dashboard before rendering the account settings page.

When raising RedirectToPage, this filter uses a redirect_to field handled by
the course about view that redirects to that URL.
"""
raise AccountSettingsRenderStarted.RedirectToPage(
"You can't access this page, redirecting to dashboard."
)


class TestRenderCustomResponse(PipelineStep):
"""
Utility class used when getting steps for pipeline.
"""

def run_filter(self, context, template_name): # pylint: disable=arguments-differ
"""Pipeline step that returns a custom response when rendering the account settings page."""
response = HttpResponse("Here's the text of the web page.")
raise AccountSettingsRenderStarted.RenderCustomResponse(
"You can't access this page.",
response=response,
)


class TestAccountSettingsRender(PipelineStep):
"""
Utility class used when getting steps for pipeline.
"""

def run_filter(self, context, template_name): # pylint: disable=arguments-differ
"""Pipeline step that returns a custom response when rendering the account settings page."""
template_name = 'static_templates/about.html'
return {
"context": context, "template_name": template_name,
}


@skip_unless_lms
class TestAccountSettingsFilters(SharedModuleStoreTestCase):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use these tests as a template for testing this kind of filters:

test_account_render_filter_executed
test_account_render_alternative
test_account_redirect
test_account_redirect_default
test_account_custom_response
test_account_render_without_filter_config

Those are precisely the same as here. I know this needs to be documented somewhere -we're working on it- but again, you could use them as a guide.

"""
Tests for the Open edX Filters associated with the account settings proccess.

This class guarantees that the following filters are triggered during the user's account settings rendering:

- AccountSettingsRenderStarted
"""
def setUp(self): # pylint: disable=arguments-differ
super().setUp()
self.user = UserFactory.create(
username="somestudent",
first_name="Student",
last_name="Person",
email="[email protected]",
is_active=True,
password="password",
)
self.client.login(username=self.user.username, password="password")
self.account_settings_url = '/account/settings'

@override_settings(
OPEN_EDX_FILTERS_CONFIG={
"org.openedx.learning.student.settings.render.started.v1": {
"pipeline": [
"openedx.core.djangoapps.user_api.accounts.tests.test_filters.TestAccountSettingsRender",
],
"fail_silently": False,
},
},
)
def test_account_settings_render_filter_executed(self):
"""
Test whether the account settings filter is triggered before the user's
account settings page is rendered.

Expected result:
- AccountSettingsRenderStarted is triggered and executes TestAccountSettingsRender
"""
response = self.client.get(self.account_settings_url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertContains(response, "This page left intentionally blank. Feel free to add your own content.")

@override_settings(
OPEN_EDX_FILTERS_CONFIG={
"org.openedx.learning.student.settings.render.started.v1": {
"pipeline": [
"openedx.core.djangoapps.user_api.accounts.tests.test_filters.TestRenderInvalidAccountSettings", # pylint: disable=line-too-long
],
"fail_silently": False,
},
},
PLATFORM_NAME="My site",
)
def test_account_settings_render_alternative(self):
"""
Test whether the account settings filter is triggered before the user's
account settings page is rendered.

Expected result:
- AccountSettingsRenderStarted is triggered and executes TestRenderInvalidAccountSettings # pylint: disable=line-too-long
"""
response = self.client.get(self.account_settings_url)

self.assertContains(response, "There has been a 500 error on the <em>My site</em> servers")

@override_settings(
OPEN_EDX_FILTERS_CONFIG={
"org.openedx.learning.student.settings.render.started.v1": {
"pipeline": [
"openedx.core.djangoapps.user_api.accounts.tests.test_filters.TestRenderCustomResponse",
],
"fail_silently": False,
},
},
)
def test_account_settings_render_custom_response(self):
"""
Test whether the account settings filter is triggered before the user's
account settings page is rendered.

Expected result:
- AccountSettingsRenderStarted is triggered and executes TestRenderCustomResponse
"""
response = self.client.get(self.account_settings_url)

self.assertEqual(response.content, b"Here's the text of the web page.")

@override_settings(
OPEN_EDX_FILTERS_CONFIG={
"org.openedx.learning.student.settings.render.started.v1": {
"pipeline": [
"openedx.core.djangoapps.user_api.accounts.tests.test_filters.TestRedirectToPage",
],
"fail_silently": False,
},
},
)
def test_account_settings_redirect_to_page(self):
"""
Test whether the account settings filter is triggered before the user's
account settings page is rendered.

Expected result:
- AccountSettingsRenderStarted is triggered and executes TestRedirectToPage
"""
response = self.client.get(self.account_settings_url)

self.assertEqual(response.status_code, status.HTTP_302_FOUND)
self.assertEqual('/courses', response.url)

@override_settings(
OPEN_EDX_FILTERS_CONFIG={
"org.openedx.learning.student.settings.render.started.v1": {
"pipeline": [
"openedx.core.djangoapps.user_api.accounts.tests.test_filters.TestRedirectToDefaultPage",
],
"fail_silently": False,
},
},
)
def test_account_settings_redirect_default(self):
"""
Test whether the account settings filter is triggered before the user's
account settings page is rendered.

Expected result:
- AccountSettingsRenderStarted is triggered and executes TestRedirectToDefaultPage
"""
response = self.client.get(self.account_settings_url)

self.assertEqual(response.status_code, status.HTTP_302_FOUND)
self.assertEqual(f"{reverse('dashboard')}", response.url)

@override_settings(OPEN_EDX_FILTERS_CONFIG={})
def test_account_settings_render_without_filter_config(self):
"""
Test whether the course about filter is triggered before the course about
render without affecting its execution flow.

Expected result:
- AccountSettingsRenderStarted executes a noop (empty pipeline). Without any
modification comparing it with the effects of TestAccountSettingsRender.
- The view response is HTTP_200_OK.
"""
response = self.client.get(self.account_settings_url)

self.assertNotContains(response, "This page left intentionally blank. Feel free to add your own content.")
2 changes: 1 addition & 1 deletion requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ openedx-events==5.1.0
# via
# -r requirements/edx/base.in
# edx-event-bus-kafka
openedx-filters==1.1.0
openedx-filters==1.2.0
# via
# -r requirements/edx/base.in
# lti-consumer-xblock
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ openedx-events==5.1.0
# via
# -r requirements/edx/testing.txt
# edx-event-bus-kafka
openedx-filters==1.1.0
openedx-filters==1.2.0
# via
# -r requirements/edx/testing.txt
# lti-consumer-xblock
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ openedx-events==5.1.0
# via
# -r requirements/edx/base.txt
# edx-event-bus-kafka
openedx-filters==1.1.0
openedx-filters==1.2.0
# via
# -r requirements/edx/base.txt
# lti-consumer-xblock
Expand Down