Skip to content

Commit

Permalink
refactor: Remove broken Force-Publish UI from Studio
Browse files Browse the repository at this point in the history
Co-Authored-By: Feanil Patel <feanil@axim.org>
  • Loading branch information
kdmccormick and feanil committed Feb 17, 2025
1 parent 7cef295 commit 38254dd
Show file tree
Hide file tree
Showing 6 changed files with 1 addition and 355 deletions.
119 changes: 1 addition & 118 deletions cms/djangoapps/maintenance/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@
"""


import json

import ddt
from django.conf import settings
from django.urls import reverse

from cms.djangoapps.contentstore.management.commands.utils import get_course_versions
from common.djangoapps.student.tests.factories import AdminFactory, UserFactory
from openedx.features.announcements.models import Announcement
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory # lint-amnesty, pylint: disable=wrong-import-order

from .views import COURSE_KEY_ERROR_MESSAGES, MAINTENANCE_VIEWS
from .views import MAINTENANCE_VIEWS

# This list contains URLs of all maintenance app views.
MAINTENANCE_URLS = [reverse(view['url']) for view in MAINTENANCE_VIEWS.values()]
Expand Down Expand Up @@ -122,118 +117,6 @@ def test_non_global_staff_access(self, url):
)


@ddt.ddt
class TestForcePublish(MaintenanceViewTestCase):
"""
Tests for the force publish view.
"""

def setUp(self):
super().setUp()
self.view_url = reverse('maintenance:force_publish_course')

def setup_test_course(self):
"""
Creates the course and add some changes to it.
Returns:
course: a course object
"""
course = CourseFactory.create()
# Add some changes to course
chapter = BlockFactory.create(category='chapter', parent_location=course.location)
self.store.create_child(
self.user.id,
chapter.location,
'html',
block_id='html_component'
)
# verify that course has changes.
self.assertTrue(self.store.has_changes(self.store.get_item(course.location)))
return course

@ddt.data(
('', COURSE_KEY_ERROR_MESSAGES['empty_course_key']),
('edx', COURSE_KEY_ERROR_MESSAGES['invalid_course_key']),
('course-v1:e+d+X', COURSE_KEY_ERROR_MESSAGES['course_key_not_found']),
)
@ddt.unpack
def test_invalid_course_key_messages(self, course_key, error_message):
"""
Test all error messages for invalid course keys.
"""
# validate that course key contains error message
self.verify_error_message(
data={'course-id': course_key},
error_message=error_message
)

def test_already_published(self):
"""
Test that when a course is forcefully publish, we get a 'course is already published' message.
"""
course = self.setup_test_course()

# publish the course
source_store = modulestore()._get_modulestore_for_courselike(course.id) # pylint: disable=protected-access
source_store.force_publish_course(course.id, self.user.id, commit=True)

# now course is published, we should get `already published course` error.
self.verify_error_message(
data={'course-id': str(course.id)},
error_message='Course is already in published state.'
)

def verify_versions_are_different(self, course):
"""
Verify draft and published versions point to different locations.
Arguments:
course (object): a course object.
"""
# get draft and publish branch versions
versions = get_course_versions(str(course.id))

# verify that draft and publish point to different versions
self.assertNotEqual(versions['draft-branch'], versions['published-branch'])

def get_force_publish_course_response(self, course):
"""
Get force publish the course response.
Arguments:
course (object): a course object.
Returns:
response : response from force publish post view.
"""
# Verify versions point to different locations initially
self.verify_versions_are_different(course)

# force publish course view
data = {
'course-id': str(course.id)
}
response = self.client.post(self.view_url, data=data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
response_data = json.loads(response.content.decode('utf-8'))
return response_data

def test_force_publish_dry_run(self):
"""
Test that dry run does not publishes the course but shows possible outcome if force published is executed.
"""
course = self.setup_test_course()
response = self.get_force_publish_course_response(course)

self.assertIn('current_versions', response)

# verify that course still has changes as we just dry ran force publish course.
self.assertTrue(self.store.has_changes(self.store.get_item(course.location)))

# verify that both branch versions are still different
self.verify_versions_are_different(course)


@ddt.ddt
class TestAnnouncementsViews(MaintenanceViewTestCase):
"""
Expand Down
2 changes: 0 additions & 2 deletions cms/djangoapps/maintenance/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
AnnouncementDeleteView,
AnnouncementEditView,
AnnouncementIndexView,
ForcePublishCourseView,
MaintenanceIndexView
)

app_name = 'cms.djangoapps.maintenance'

urlpatterns = [
path('', MaintenanceIndexView.as_view(), name='maintenance_index'),
re_path(r'^force_publish_course/?$', ForcePublishCourseView.as_view(), name='force_publish_course'),
re_path(r'^announcements/(?P<page>\d+)?$', AnnouncementIndexView.as_view(), name='announcement_index'),
path('announcements/create', AnnouncementCreateView.as_view(), name='announcement_create'),
re_path(r'^announcements/edit/(?P<pk>\d+)?$', AnnouncementEditView.as_view(), name='announcement_edit'),
Expand Down
111 changes: 0 additions & 111 deletions cms/djangoapps/maintenance/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@
import logging

from django.core.validators import ValidationError
from django.db import transaction
from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator
from django.utils.translation import gettext as _
from django.views.generic import View
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.views.generic.list import ListView
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey

from cms.djangoapps.contentstore.management.commands.utils import get_course_versions
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.util.json_request import JsonResponse
from common.djangoapps.util.views import require_global_staff
Expand All @@ -30,16 +27,6 @@

# This dict maintains all the views that will be used Maintenance app.
MAINTENANCE_VIEWS = {
'force_publish_course': {
'url': 'maintenance:force_publish_course',
'name': _('Force Publish Course'),
'slug': 'force_publish_course',
'description': _(
'Sometimes the draft and published branches of a course can get out of sync. Force publish course command '
'resets the published branch of a course to point to the draft branch, effectively force publishing the '
'course. This view dry runs the force publish command'
),
},
'announcement_index': {
'url': 'maintenance:announcement_index',
'name': _('Edit Announcements'),
Expand Down Expand Up @@ -131,104 +118,6 @@ def validate_course_key(self, course_key, branch=ModuleStoreEnum.BranchName.draf
return course_usage_key


class ForcePublishCourseView(MaintenanceBaseView):
"""
View for force publishing state of the course, used by the global staff.
This view uses `force_publish_course` method of modulestore which publishes the draft state of the course. After
the course has been forced published, both draft and publish draft point to same location.
"""

def __init__(self):
super().__init__(MAINTENANCE_VIEWS['force_publish_course'])
self.context.update({
'current_versions': [],
'updated_versions': [],
'form_data': {
'course_id': '',
'is_dry_run': True
}
})

def get_course_branch_versions(self, versions):
"""
Returns a dict containing unicoded values of draft and published draft versions.
"""
return {
'draft-branch': str(versions['draft-branch']),
'published-branch': str(versions['published-branch'])
}

@transaction.atomic
@method_decorator(require_global_staff)
def post(self, request):
"""
This method force publishes a course if dry-run argument is not selected. If dry-run is selected, this view
shows possible outcome if the `force_publish_course` modulestore method is executed.
Arguments:
course_id (string): a request parameter containing course id
is_dry_run (string): a request parameter containing dry run value.
It is obtained from checkbox so it has either values 'on' or ''.
"""
course_id = request.POST.get('course-id')

self.context.update({
'form_data': {
'course_id': course_id
}
})

try:
course_usage_key = self.validate_course_key(course_id)
except InvalidKeyError:
self.context['error'] = True
self.context['msg'] = COURSE_KEY_ERROR_MESSAGES['invalid_course_key']
except ItemNotFoundError as exc:
self.context['error'] = True
self.context['msg'] = str(exc)
except ValidationError as exc:
self.context['error'] = True
self.context['msg'] = str(exc)

if self.context['error']:
return self.render_response()

source_store = modulestore()._get_modulestore_for_courselike(course_usage_key) # pylint: disable=protected-access
if not hasattr(source_store, 'force_publish_course'):
self.context['msg'] = _('Force publishing course is not supported with old mongo courses.')
log.warning(
'Force publishing course is not supported with old mongo courses. \
%s attempted to force publish the course %s.',
request.user,
course_id,
exc_info=True
)
return self.render_response()

current_versions = self.get_course_branch_versions(get_course_versions(course_id))

# if publish and draft are NOT different
if current_versions['published-branch'] == current_versions['draft-branch']:
self.context['msg'] = _('Course is already in published state.')
log.warning(
'Course is already in published state. %s attempted to force publish the course %s.',
request.user,
course_id,
exc_info=True
)
return self.render_response()

self.context['current_versions'] = current_versions
log.info(
'%s dry ran force publish the course %s.',
request.user,
course_id,
exc_info=True
)
return self.render_response()


class AnnouncementBaseView(View):
"""
Base view for Announcements pages
Expand Down
83 changes: 0 additions & 83 deletions cms/static/js/maintenance/force_publish_course.js

This file was deleted.

Loading

0 comments on commit 38254dd

Please sign in to comment.