Merge pull request #29846 from openedx/mikix/drop-dates-view
feat!: drop legacy dates tab, in favor of MFE version
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
Dates Tab Views
|
||||
"""
|
||||
|
||||
from django.http.response import Http404
|
||||
from edx_django_utils import monitoring as monitoring_utils
|
||||
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
||||
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
|
||||
@@ -14,7 +13,6 @@ from rest_framework.response import Response
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from lms.djangoapps.course_goals.models import UserActivity
|
||||
from lms.djangoapps.course_home_api.dates.serializers import DatesTabSerializer
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_legacy_is_active
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs
|
||||
from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_with_access
|
||||
@@ -76,9 +74,6 @@ class DatesTabView(RetrieveAPIView):
|
||||
course_key_string = kwargs.get('course_key_string')
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
|
||||
if course_home_legacy_is_active(course_key):
|
||||
raise Http404
|
||||
|
||||
# Enable NR tracing for this view based on course
|
||||
monitoring_utils.set_custom_attribute('course_id', course_key_string)
|
||||
monitoring_utils.set_custom_attribute('user_id', request.user.id)
|
||||
|
||||
@@ -198,10 +198,7 @@ class OutlineTabView(RetrieveAPIView):
|
||||
user_timezone_locale = user_timezone_locale_prefs(request)
|
||||
user_timezone = user_timezone_locale['user_timezone']
|
||||
|
||||
if course_home_legacy_is_active(course.id):
|
||||
dates_tab_link = request.build_absolute_uri(reverse('dates', args=[course.id]))
|
||||
else:
|
||||
dates_tab_link = get_learning_mfe_home_url(course_key=course.id, url_fragment='dates')
|
||||
dates_tab_link = get_learning_mfe_home_url(course_key=course.id, url_fragment='dates')
|
||||
|
||||
# Set all of the defaults
|
||||
access_expiration = None
|
||||
|
||||
@@ -334,11 +334,8 @@ class DatesTab(EnrolledTab):
|
||||
view_name = "dates"
|
||||
|
||||
def __init__(self, tab_dict):
|
||||
def link_func(course, reverse_func):
|
||||
if course_home_legacy_is_active(course.id):
|
||||
return reverse_func(self.view_name, args=[str(course.id)])
|
||||
else:
|
||||
return get_learning_mfe_home_url(course_key=course.id, url_fragment=self.view_name)
|
||||
def link_func(course, _reverse_func):
|
||||
return get_learning_mfe_home_url(course_key=course.id, url_fragment='dates')
|
||||
|
||||
tab_dict['link_func'] = link_func
|
||||
super().__init__(tab_dict)
|
||||
|
||||
@@ -724,33 +724,25 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
assert block.relative_datestring == expected_date_string
|
||||
|
||||
@ddt.data(
|
||||
('info', True),
|
||||
('info', False),
|
||||
('openedx.course_experience.course_home', True),
|
||||
('openedx.course_experience.course_home', False),
|
||||
'info',
|
||||
'openedx.course_experience.course_home',
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=False)
|
||||
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
||||
def test_dates_tab_link_render(self, url_name, legacy_active):
|
||||
def test_dates_tab_link_render(self, url_name):
|
||||
""" The dates tab link should only show for enrolled or staff users """
|
||||
course = create_course_run()
|
||||
html_elements = [
|
||||
'class="dates-tab-link"',
|
||||
'View all course dates</a>',
|
||||
f'/course/{course.id}/dates',
|
||||
]
|
||||
# The url should change based on the mfe being active.
|
||||
if legacy_active:
|
||||
html_elements.append('/courses/' + str(course.id) + '/dates')
|
||||
else:
|
||||
html_elements.append('/course/' + str(course.id) + '/dates')
|
||||
url = reverse(url_name, args=(course.id,))
|
||||
|
||||
def assert_html_elements(assert_function, user):
|
||||
self.client.login(username=user.username, password=TEST_PASSWORD)
|
||||
with override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=legacy_active):
|
||||
response = self.client.get(url, follow=True)
|
||||
if legacy_active or user.is_staff:
|
||||
response = self.client.get(url, follow=True)
|
||||
if user.is_staff:
|
||||
for html in html_elements:
|
||||
assert_function(response, html)
|
||||
else:
|
||||
|
||||
@@ -8,7 +8,7 @@ import itertools
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import MagicMock, PropertyMock, call, create_autospec, patch
|
||||
from unittest.mock import MagicMock, PropertyMock, create_autospec, patch
|
||||
from urllib.parse import urlencode
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -30,7 +30,7 @@ from freezegun import freeze_time
|
||||
from markupsafe import escape
|
||||
from milestones.tests.utils import MilestonesTestCaseMixin
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
from pytz import UTC, utc
|
||||
from pytz import UTC
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import Scope, String
|
||||
@@ -97,7 +97,6 @@ from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateCli
|
||||
from lms.djangoapps.grades.config.waffle import ASSUME_ZERO_GRADE_IF_ABSENT
|
||||
from lms.djangoapps.grades.config.waffle import waffle_switch as grades_waffle_switch
|
||||
from lms.djangoapps.instructor.access import allow_access
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from openedx.core.djangoapps.catalog.tests.factories import CourseFactory as CatalogCourseFactory
|
||||
from openedx.core.djangoapps.catalog.tests.factories import CourseRunFactory, ProgramFactory
|
||||
@@ -115,7 +114,6 @@ from openedx.features.course_experience import (
|
||||
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG,
|
||||
DISABLE_COURSE_OUTLINE_PAGE_FLAG,
|
||||
DISABLE_UNIFIED_COURSE_TAB_FLAG,
|
||||
RELATIVE_DATES_FLAG
|
||||
)
|
||||
from openedx.features.course_experience.tests.views.helpers import add_course_mode
|
||||
from openedx.features.course_experience.url_helpers import (
|
||||
@@ -3496,146 +3494,17 @@ class AccessUtilsTestCase(ModuleStoreTestCase):
|
||||
assert bool(check_course_open_for_learner(staff_user, course)) == expected_value
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True)
|
||||
class DatesTabTestCase(ModuleStoreTestCase):
|
||||
class DatesTabTestCase(TestCase):
|
||||
"""
|
||||
Ensure that the dates page renders with the correct data for both a verified and audit learner
|
||||
Ensure that the legacy dates view redirects appropriately (it no longer exists).
|
||||
"""
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
now = datetime.now(utc)
|
||||
self.course = CourseFactory.create(start=now + timedelta(days=-1), self_paced=True)
|
||||
self.course.end = now + timedelta(days=3)
|
||||
|
||||
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
|
||||
CourseModeFactory(course_id=self.course.id, mode_slug=CourseMode.AUDIT)
|
||||
CourseModeFactory(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.VERIFIED,
|
||||
expiration_datetime=now + timedelta(days=1)
|
||||
)
|
||||
VerificationDeadline.objects.create(
|
||||
course_key=self.course.id,
|
||||
deadline=now + timedelta(days=2)
|
||||
)
|
||||
|
||||
self.user = UserFactory()
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2017, 1, 1))
|
||||
|
||||
def _get_response(self, course):
|
||||
""" Returns the HTML for the dates page """
|
||||
return self.client.get(reverse('dates', args=[str(course.id)]))
|
||||
|
||||
def test_tab_redirects_if_not_logged_in(self):
|
||||
self.client.logout()
|
||||
response = self._get_response(self.course)
|
||||
assert response.status_code == 302
|
||||
assert '/login?next=/courses/' in response.url
|
||||
|
||||
def test_tab_redirects_if_not_enrolled_and_not_staff(self):
|
||||
response = self._get_response(self.course)
|
||||
assert response.status_code == 302
|
||||
# Beginning of redirect URL
|
||||
assert '/courses/' in response.url
|
||||
# End of redirect URL
|
||||
assert '/course/' in response.url
|
||||
|
||||
# Now check staff users can see
|
||||
self.user.is_staff = True
|
||||
self.user.save()
|
||||
response = self._get_response(self.course)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Enrolled users can also see
|
||||
self.client.logout()
|
||||
enrolled_user = UserFactory()
|
||||
CourseEnrollmentFactory(course_id=self.course.id, user=enrolled_user, mode=CourseMode.VERIFIED)
|
||||
self.client.login(username=enrolled_user.username, password=TEST_PASSWORD)
|
||||
response = self._get_response(self.course)
|
||||
assert response.status_code == 200
|
||||
|
||||
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
||||
@patch('edx_django_utils.monitoring.set_custom_attribute')
|
||||
def test_defaults(self, mock_set_custom_attribute):
|
||||
enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.VERIFIED)
|
||||
now = datetime.now(utc)
|
||||
with self.store.bulk_operations(self.course.id):
|
||||
section = ItemFactory.create(category='chapter', parent_location=self.course.location)
|
||||
subsection = ItemFactory.create(
|
||||
category='sequential',
|
||||
display_name='Released',
|
||||
parent_location=section.location,
|
||||
start=now - timedelta(days=1),
|
||||
due=now + timedelta(days=1), # Setting this to tomorrow so it'll show the 'Due Next' pill
|
||||
graded=True,
|
||||
format='Homework',
|
||||
)
|
||||
vertical = ItemFactory.create(category='vertical', parent_location=subsection.location)
|
||||
ItemFactory.create(category='problem', parent_location=vertical.location, has_score=True)
|
||||
|
||||
response = self._get_response(self.course)
|
||||
self.assertContains(response, subsection.display_name)
|
||||
# Show the Verification Deadline for verified only
|
||||
self.assertContains(response, 'Verification Deadline')
|
||||
# Make sure pill exists for today's date
|
||||
self.assertContains(response, '<div class="pill today">')
|
||||
# Make sure pill exists for next due assignment
|
||||
self.assertContains(response, '<div class="pill due-next">')
|
||||
# No pills for verified enrollments
|
||||
self.assertNotContains(response, '<div class="pill verified">')
|
||||
# Make sure the assignment type is rendered
|
||||
self.assertContains(response, 'Homework:')
|
||||
|
||||
enrollment.delete()
|
||||
enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.AUDIT)
|
||||
|
||||
expected_calls = [
|
||||
call('course_id', str(self.course.id)),
|
||||
call('user_id', self.user.id),
|
||||
call('is_staff', self.user.is_staff),
|
||||
]
|
||||
|
||||
response = self._get_response(self.course)
|
||||
|
||||
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)
|
||||
self.assertContains(response, subsection.display_name)
|
||||
# Don't show the Verification Deadline for audit
|
||||
self.assertNotContains(response, 'Verification Deadline')
|
||||
# Pill doesn't exist for assignment due tomorrow
|
||||
self.assertNotContains(response, '<div class="pill due-next">')
|
||||
# Should have verified pills for audit enrollments
|
||||
self.assertContains(response, '<div class="pill verified">')
|
||||
# Make sure the assignment type is rendered
|
||||
self.assertContains(response, 'Homework:')
|
||||
|
||||
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
||||
def test_reset_deadlines_banner_displays(self):
|
||||
CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.VERIFIED)
|
||||
now = datetime.now(utc)
|
||||
with self.store.bulk_operations(self.course.id):
|
||||
section = ItemFactory.create(category='chapter', parent_location=self.course.location)
|
||||
ItemFactory.create(
|
||||
category='sequential',
|
||||
display_name='Released',
|
||||
parent_location=section.location,
|
||||
start=now - timedelta(days=1),
|
||||
due=now - timedelta(days=1), # Setting this to tomorrow so it'll show the 'Due Next' pill
|
||||
graded=True,
|
||||
)
|
||||
response = self._get_response(self.course)
|
||||
self.assertContains(response, 'div class="banner-cta-text"')
|
||||
|
||||
@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=False)
|
||||
def test_legacy_redirect(self):
|
||||
"""
|
||||
Verify that the legacy dates page redirects to the MFE correctly.
|
||||
"""
|
||||
response = self.client.get(reverse('dates', args=[str(self.course.id)]) + '?foo=b$r')
|
||||
response = self.client.get('/courses/course-v1:Org+Course+Run/dates?foo=b$r')
|
||||
assert response.status_code == 302
|
||||
assert response.get('Location') == f'http://learning-mfe/course/{self.course.id}/dates?foo=b%24r'
|
||||
assert response.get('Location') == 'http://learning-mfe/course/course-v1:Org+Course+Run/dates?foo=b%24r'
|
||||
|
||||
|
||||
class TestShowCoursewareMFE(TestCase):
|
||||
@@ -3936,7 +3805,6 @@ class TestCourseWideResources(ModuleStoreTestCase):
|
||||
|
||||
@ddt.data(
|
||||
('courseware', 'course_id', False, True),
|
||||
('dates', 'course_id', False, False),
|
||||
('progress', 'course_id', False, False),
|
||||
('instructor_dashboard', 'course_id', True, False),
|
||||
('forum_form_discussion', 'course_id', False, False),
|
||||
|
||||
@@ -32,7 +32,6 @@ from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_GET, require_http_methods, require_POST
|
||||
from django.views.generic import View
|
||||
from edx_django_utils import monitoring as monitoring_utils
|
||||
from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key
|
||||
from ipware.ip import get_client_ip
|
||||
from markupsafe import escape
|
||||
@@ -77,7 +76,6 @@ from lms.djangoapps.courseware.courses import (
|
||||
can_self_enroll_in_course,
|
||||
course_open_for_self_enrollment,
|
||||
get_course,
|
||||
get_course_date_blocks,
|
||||
get_course_overview_with_access,
|
||||
get_course_with_access,
|
||||
get_courses,
|
||||
@@ -125,7 +123,6 @@ from openedx.core.djangoapps.util.user_messages import PageLevelMessages
|
||||
from openedx.core.djangoapps.zendesk_proxy.utils import create_zendesk_ticket
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
|
||||
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
|
||||
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
|
||||
from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url_name
|
||||
from openedx.features.course_experience.course_tools import CourseToolsPluginManager
|
||||
@@ -141,7 +138,6 @@ from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBA
|
||||
from openedx.features.course_experience.waffle import waffle as course_experience_waffle
|
||||
from openedx.features.enterprise_support.api import data_sharing_consent_required
|
||||
|
||||
from ..context_processor import user_timezone_locale_prefs
|
||||
from ..entrance_exams import user_can_skip_entrance_exam
|
||||
from ..module_render import get_module, get_module_by_usage_id, get_module_for_descriptor
|
||||
from ..tabs import _get_dynamic_tabs
|
||||
@@ -1054,82 +1050,12 @@ def program_marketing(request, program_uuid):
|
||||
return render_to_response('courseware/program_marketing.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
@ensure_csrf_cookie
|
||||
@ensure_valid_course_key
|
||||
def dates(request, course_id):
|
||||
"""
|
||||
Display the course's dates.html, or 404 if there is no such course.
|
||||
Assumes the course_id is in a valid format.
|
||||
Simply redirects to the MFE dates tab, as this legacy view for dates no longer exists.
|
||||
"""
|
||||
from lms.urls import COURSE_DATES_NAME, RESET_COURSE_DEADLINES_NAME
|
||||
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
if not (course_home_legacy_is_active(course_key) or request.user.is_staff):
|
||||
raise Redirect(get_learning_mfe_home_url(
|
||||
course_key=course_key, url_fragment=COURSE_DATES_NAME, params=request.GET,
|
||||
))
|
||||
|
||||
# Enable NR tracing for this view based on course
|
||||
monitoring_utils.set_custom_attribute('course_id', str(course_key))
|
||||
monitoring_utils.set_custom_attribute('user_id', request.user.id)
|
||||
monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff)
|
||||
|
||||
course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)
|
||||
|
||||
masquerade = None
|
||||
can_masquerade = request.user.has_perm(MASQUERADE_AS_STUDENT, course)
|
||||
if can_masquerade:
|
||||
masquerade, masquerade_user = setup_masquerade(
|
||||
request,
|
||||
course.id,
|
||||
can_masquerade,
|
||||
reset_masquerade_data=True,
|
||||
)
|
||||
request.user = masquerade_user
|
||||
|
||||
user_is_enrolled = CourseEnrollment.is_enrolled(request.user, course_key)
|
||||
user_is_staff = bool(has_access(request.user, 'staff', course_key))
|
||||
|
||||
# Render the full content to enrolled users, as well as to course and global staff.
|
||||
# Unenrolled users who are not course or global staff are redirected to the Outline Tab.
|
||||
if not user_is_enrolled and not user_is_staff:
|
||||
raise CourseAccessRedirect(reverse('openedx.course_experience.course_home', args=[course_id]))
|
||||
|
||||
course_date_blocks = get_course_date_blocks(course, request.user, request,
|
||||
include_access=True, include_past_dates=True)
|
||||
|
||||
learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment(request.user, course_key)
|
||||
|
||||
# User locale settings
|
||||
user_timezone_locale = user_timezone_locale_prefs(request)
|
||||
user_timezone = user_timezone_locale['user_timezone']
|
||||
user_language = user_timezone_locale['user_language']
|
||||
|
||||
missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user)
|
||||
|
||||
context = {
|
||||
'course': course,
|
||||
'course_date_blocks': course_date_blocks,
|
||||
'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course),
|
||||
'learner_is_full_access': learner_is_full_access,
|
||||
'user_timezone': user_timezone,
|
||||
'user_language': user_language,
|
||||
'supports_preview_menu': True,
|
||||
'can_masquerade': can_masquerade,
|
||||
'masquerade': masquerade,
|
||||
'on_dates_tab': True,
|
||||
'content_type_gating_enabled': ContentTypeGatingConfig.enabled_for_enrollment(
|
||||
user=request.user,
|
||||
course_key=course_key,
|
||||
),
|
||||
'missed_deadlines': missed_deadlines,
|
||||
'missed_gated_content': missed_gated_content,
|
||||
'reset_deadlines_url': reverse(RESET_COURSE_DEADLINES_NAME),
|
||||
'has_ended': course.has_ended(),
|
||||
}
|
||||
|
||||
return render_to_response('courseware/dates.html', context)
|
||||
raise Redirect(get_learning_mfe_home_url(course_key=course_id, url_fragment='dates', params=request.GET))
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
<%page expression_filter="h"/>
|
||||
<%inherit file="/main.html" />
|
||||
<%namespace name='static' file='/static_content.html'/>
|
||||
<%!
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from lms.djangoapps.courseware.date_summary import CourseAssignmentDate, TodaysDate, VerificationDeadlineDate, VerifiedUpgradeDeadlineDate
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
%>
|
||||
|
||||
<%block name="bodyclass">view-in-course view-progress</%block>
|
||||
|
||||
<%block name="headextra">
|
||||
<%static:css group='style-course-vendor'/>
|
||||
<%static:css group='style-course'/>
|
||||
</%block>
|
||||
|
||||
<%block name="pagetitle">${_("{course.display_number_with_default} Course Info").format(course=course)}</%block>
|
||||
|
||||
<%include file="/courseware/course_navigation.html" args="active_page='dates'" />
|
||||
|
||||
<main id="main" aria-label="Content" tabindex="-1">
|
||||
<div class="container">
|
||||
<div class="date-wrapper">
|
||||
<section class="course-info" id="course-info-dates">
|
||||
<h2 class="hd hd-2 date-title">
|
||||
${_("Important Dates")}
|
||||
</h2>
|
||||
<%include file="/dates_banner.html" />
|
||||
<% due_next_set = False %>
|
||||
% for block in course_date_blocks:
|
||||
<% block_is_verified = (hasattr(block, 'contains_gated_content') and block.contains_gated_content) or isinstance(block, VerificationDeadlineDate) %>
|
||||
<% learner_has_access = not block_is_verified or learner_is_full_access %>
|
||||
<% access_class = '' if learner_has_access else 'no-access' %>
|
||||
<% is_assignment = isinstance(block, CourseAssignmentDate) %>
|
||||
<% assignment_type = is_assignment and block.assignment_type %>
|
||||
<% todays_date = 'todays-date' if isinstance(block, TodaysDate) else '' %>
|
||||
<% past_date = 'past-date' if block.date and block.date < block.current_time else '' %>
|
||||
<% past_due = 'past-due' if learner_is_full_access and is_assignment and block.past_due else '' %>
|
||||
<% due_in_future = True if learner_is_full_access and is_assignment and block.date and block.date >= block.current_time else False %>
|
||||
<% not_released = 'not-released' if learner_is_full_access and is_assignment and not block.title_html else '' %>
|
||||
% if not (learner_is_full_access and isinstance(block, VerifiedUpgradeDeadlineDate)):
|
||||
<div class="timeline-item">
|
||||
<div class="date-circle ${todays_date} ${past_date} ${past_due}"></div>
|
||||
<div class="date-content ${todays_date}">
|
||||
<div class="timeline-date-content ${not_released}">
|
||||
% if block.date:
|
||||
<div class="timeline-date">
|
||||
<div class="course-date localized_datetime" aria-hidden="true" data-format="shortDate" data-datetime="${block.date}" data-language="${user_language}" data-timezone="${user_timezone}"></div>
|
||||
</div>
|
||||
% if todays_date:
|
||||
<div class="pill today">${_('Today')}</div>
|
||||
% endif
|
||||
% if not learner_has_access:
|
||||
<div class="pill verified"><span class="fa fa-lock verified-icon" aria-hidden="true"></span>${_('Verified Only')}</div>
|
||||
% else:
|
||||
% if is_assignment and block.complete:
|
||||
<div class="pill completed">${_('Completed')}</div>
|
||||
% elif is_assignment and block.past_due:
|
||||
<div class="pill past-due">${_('Past Due')}</div>
|
||||
% elif is_assignment and due_in_future and not due_next_set:
|
||||
<div class="pill due-next">${_('Due Next')}</div>
|
||||
<% due_next_set = True %>
|
||||
% endif
|
||||
% if not_released:
|
||||
<div class="pill not-released">${_('Not yet released')}</div>
|
||||
% endif
|
||||
%endif
|
||||
% endif
|
||||
</div>
|
||||
% if not todays_date:
|
||||
<div class="timeline-title ${access_class} ${not_released}">
|
||||
% if assignment_type:
|
||||
${assignment_type}:
|
||||
% endif
|
||||
% if block.title_html and is_assignment and learner_has_access:
|
||||
${block.title_html}
|
||||
% else:
|
||||
${block.title}
|
||||
% endif
|
||||
</div>
|
||||
<div class="timeline-description ${access_class} ${not_released}">
|
||||
${block.description}
|
||||
</div>
|
||||
% if block.extra_info:
|
||||
<div class="timeline-extra-info ${access_class} ${not_released}">
|
||||
${block.extra_info}
|
||||
</div>
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
% endfor
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory">
|
||||
DateUtilFactory.transform(iterationKey=".localized_datetime");
|
||||
</%static:require_module_async>
|
||||
|
||||
<%static:require_module_async module_name="js/commerce/track_ecommerce_events" class_name="TrackECommerceEvents">
|
||||
var personalizedLearnerSchedulesLink = $(".personalized_learner_schedules_button");
|
||||
|
||||
TrackECommerceEvents.trackUpsellClick(personalizedLearnerSchedulesLink, 'dates_upgrade', {
|
||||
pageName: "dates_tab",
|
||||
linkType: "button",
|
||||
linkCategory: "personalized_learner_schedules"
|
||||
});
|
||||
|
||||
</%static:require_module_async>
|
||||
11
lms/urls.py
11
lms/urls.py
@@ -57,7 +57,6 @@ from common.djangoapps.util import views as util_views
|
||||
RESET_COURSE_DEADLINES_NAME = 'reset_course_deadlines'
|
||||
RENDER_XBLOCK_NAME = 'render_xblock'
|
||||
RENDER_VIDEO_XBLOCK_NAME = 'render_public_video_xblock'
|
||||
COURSE_DATES_NAME = 'dates'
|
||||
COURSE_PROGRESS_NAME = 'progress'
|
||||
|
||||
if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
|
||||
@@ -507,14 +506,8 @@ urlpatterns += [
|
||||
name=COURSE_PROGRESS_NAME,
|
||||
),
|
||||
|
||||
# dates page
|
||||
re_path(
|
||||
r'^courses/{}/dates'.format(
|
||||
settings.COURSE_ID_PATTERN,
|
||||
),
|
||||
courseware_views.dates,
|
||||
name=COURSE_DATES_NAME,
|
||||
),
|
||||
# dates page (no longer functional, just redirects to MFE)
|
||||
re_path(r'^courses/{}/dates'.format(settings.COURSE_ID_PATTERN), courseware_views.dates, name='dates'),
|
||||
|
||||
# Takes optional student_id for instructor use--shows profile as that student sees it.
|
||||
re_path(
|
||||
|
||||
@@ -3,8 +3,6 @@ Views for Course Experience API.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext as _
|
||||
from eventtracking import tracker
|
||||
@@ -21,7 +19,6 @@ from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from lms.djangoapps.course_api.api import course_detail
|
||||
from lms.djangoapps.course_goals.models import UserActivity
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_legacy_is_active
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade
|
||||
@@ -95,10 +92,7 @@ def reset_course_deadlines(request):
|
||||
})
|
||||
tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data)
|
||||
|
||||
if course_home_legacy_is_active(course_key):
|
||||
body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)]))
|
||||
else:
|
||||
body_link = get_learning_mfe_home_url(course_key=str(course_key), url_fragment='dates')
|
||||
body_link = get_learning_mfe_home_url(course_key=course_key, url_fragment='dates')
|
||||
|
||||
return Response({
|
||||
'body': format_html('<a href="{}">{}</a>', body_link, _('View all dates')),
|
||||
|
||||
@@ -6,7 +6,6 @@ Fragment for rendering the course dates sidebar.
|
||||
from django.db import transaction
|
||||
from django.http import Http404
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import get_language_bidi
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -14,7 +13,6 @@ from web_fragments.fragment import Fragment
|
||||
|
||||
from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_with_access
|
||||
from lms.djangoapps.courseware.tabs import DatesTab
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_legacy_is_active
|
||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
|
||||
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||
|
||||
@@ -34,10 +32,7 @@ class CourseDatesFragmentView(EdxFragmentView):
|
||||
course_date_blocks = get_course_date_blocks(course, request.user, request, num_assignments=1)
|
||||
|
||||
dates_tab_enabled = DatesTab.is_enabled(course, request.user)
|
||||
if course_home_legacy_is_active(course_key):
|
||||
dates_tab_link = reverse('dates', args=[course.id])
|
||||
else:
|
||||
dates_tab_link = get_learning_mfe_home_url(course_key=course.id, url_fragment='dates')
|
||||
dates_tab_link = get_learning_mfe_home_url(course_key=course.id, url_fragment='dates')
|
||||
|
||||
context = {
|
||||
'course_date_blocks': [block for block in course_date_blocks if block.title != 'current_datetime'],
|
||||
|
||||
Reference in New Issue
Block a user