Commit 86762516 by Awais Committed by Awais Qureshi

Import page in publisher app for importing course in batch size of 10.

Added a import page for super users onliny in publisher app. It will import the data in
small batch and avaoid the performance issue.

ECOM-7845
parent 9a85c583
...@@ -491,3 +491,10 @@ class CourseRunAdminForm(forms.ModelForm): ...@@ -491,3 +491,10 @@ class CourseRunAdminForm(forms.ModelForm):
return lms_course_id return lms_course_id
return None return None
class AdminImportCourseForm(forms.Form):
start_id = forms.IntegerField(min_value=1, label='This course id will import along with next 9 courses.')
class Meta:
fields = ('start_id',)
...@@ -22,7 +22,7 @@ from course_discovery.apps.core.models import User ...@@ -22,7 +22,7 @@ from course_discovery.apps.core.models import User
from course_discovery.apps.core.tests.factories import USER_PASSWORD, UserFactory from course_discovery.apps.core.tests.factories import USER_PASSWORD, UserFactory
from course_discovery.apps.core.tests.helpers import make_image_file from course_discovery.apps.core.tests.helpers import make_image_file
from course_discovery.apps.course_metadata.tests import toggle_switch from course_discovery.apps.course_metadata.tests import toggle_switch
from course_discovery.apps.course_metadata.tests.factories import OrganizationFactory, PersonFactory from course_discovery.apps.course_metadata.tests.factories import CourseFactory, OrganizationFactory, PersonFactory
from course_discovery.apps.ietf_language_tags.models import LanguageTag from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole
from course_discovery.apps.publisher.constants import (ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME, from course_discovery.apps.publisher.constants import (ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME,
...@@ -3008,3 +3008,64 @@ class CreateRunFromDashboardViewTests(TestCase): ...@@ -3008,3 +3008,64 @@ class CreateRunFromDashboardViewTests(TestCase):
self.assertEqual([self.course.project_coordinator.email], mail.outbox[0].to) self.assertEqual([self.course.project_coordinator.email], mail.outbox[0].to)
expected_subject = 'Studio URL requested: {title}'.format(title=self.course.title) expected_subject = 'Studio URL requested: {title}'.format(title=self.course.title)
self.assertEqual(str(mail.outbox[0].subject), expected_subject) self.assertEqual(str(mail.outbox[0].subject), expected_subject)
class CreateAdminImportCourseTest(TestCase):
""" Tests for the publisher `CreateAdminImportCourse`. """
def setUp(self):
super(CreateAdminImportCourseTest, self).setUp()
self.user = UserFactory()
self.client.login(username=self.user.username, password=USER_PASSWORD)
self.page_url = reverse('publisher:publisher_admin_import_course')
self.course = CourseFactory()
def test_page_without_login(self):
""" Verify that user can't access page when not logged in. """
self.client.logout()
response = self.client.get(self.page_url)
self.assertRedirects(
response,
expected_url='{url}?next={next}'.format(
url=reverse('login'),
next=self.page_url
),
status_code=302,
target_status_code=302
)
def test_page_without_superuser(self):
""" Verify that user can't access page when not logged in. """
response = self.client.get(self.page_url)
self.assertEqual(response.status_code, 404)
def test_page_with_superuser_and_waffle(self):
""" Verify that user can't access page when not logged in. """
response = self._make_users_valid(True)
self.assertEqual(response.status_code, 200)
def test_page_with_superuser_without_waffle(self):
""" Verify that user can't access page when not logged in. """
response = self._make_users_valid(False)
self.assertEqual(response.status_code, 404)
def test_page_with_post(self):
""" Verify post from page. """
self._make_users_valid(True)
post_data = {'start_id': self.course.pk}
response = self.client.post(self.page_url, post_data)
self.assertEqual(response.status_code, 200)
def _make_users_valid(self, switch):
""" make user eligible for the page."""
self.client.logout()
self.user.is_superuser = True
self.user.save()
toggle_switch('publisher_enable_course_import', switch)
self.client.login(username=self.user.username, password=USER_PASSWORD)
return self.client.get(self.page_url)
...@@ -32,4 +32,6 @@ urlpatterns = [ ...@@ -32,4 +32,6 @@ urlpatterns = [
), ),
url(r'^courses/(?P<pk>\d+)/revisions/(?P<revision_id>\d+)/$', views.CourseRevisionView.as_view(), url(r'^courses/(?P<pk>\d+)/revisions/(?P<revision_id>\d+)/$', views.CourseRevisionView.as_view(),
name='publisher_course_revision'), name='publisher_course_revision'),
url(r'^admin/importcourses/$', views.AdminImportCourse.as_view(), name='publisher_admin_import_course'),
] ]
...@@ -16,7 +16,7 @@ from django.http import Http404, HttpResponseRedirect, JsonResponse ...@@ -16,7 +16,7 @@ from django.http import Http404, HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, DetailView, ListView, UpdateView, View from django.views.generic import CreateView, DetailView, ListView, TemplateView, UpdateView, View
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
from course_discovery.apps.core.models import User from course_discovery.apps.core.models import User
...@@ -24,8 +24,9 @@ from course_discovery.apps.course_metadata.models import Person ...@@ -24,8 +24,9 @@ from course_discovery.apps.course_metadata.models import Person
from course_discovery.apps.ietf_language_tags.models import LanguageTag from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher import emails, mixins from course_discovery.apps.publisher import emails, mixins
from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole
from course_discovery.apps.publisher.forms import (CourseSearchForm, CustomCourseForm, CustomCourseRunForm, from course_discovery.apps.publisher.dataloader.create_courses import process_course
CustomSeatForm) from course_discovery.apps.publisher.forms import (AdminImportCourseForm, CourseSearchForm, CustomCourseForm,
CustomCourseRunForm, CustomSeatForm)
from course_discovery.apps.publisher.models import (Course, CourseRun, CourseRunState, CourseState, CourseUserRole, from course_discovery.apps.publisher.models import (Course, CourseRun, CourseRunState, CourseState, CourseUserRole,
OrganizationExtension, Seat, UserAttributes) OrganizationExtension, Seat, UserAttributes)
from course_discovery.apps.publisher.utils import (get_internal_users, has_role_for_course, is_internal_user, from course_discovery.apps.publisher.utils import (get_internal_users, has_role_for_course, is_internal_user,
...@@ -856,3 +857,42 @@ def get_course_role_widgets_data(user, course, state_object, change_state_url, p ...@@ -856,3 +857,42 @@ def get_course_role_widgets_data(user, course, state_object, change_state_url, p
role_widgets.append(role_widget) role_widgets.append(role_widget)
return role_widgets return role_widgets
class AdminImportCourse(mixins.LoginRequiredMixin, TemplateView):
"""Admin page to import course from course-metadata to publisher. """
# page is accessible to the admin users and also if the waffle switch is enable.
model = Course
template_name = 'publisher/admin/import_course.html'
def get_context_data(self, **kwargs):
context = super(AdminImportCourse, self).get_context_data(**kwargs)
context['form'] = AdminImportCourseForm()
return context
def get(self, request, *args, **kwargs):
"""Get method for import page."""
if self.request.user.is_superuser and waffle.switch_is_active('publisher_enable_course_import'):
return super(AdminImportCourse, self).get(request, args, **kwargs)
else:
raise Http404
def post(self, request, *args, **kwargs):
"""Post method for import page."""
# inline import to avoid any circular issues.
from course_discovery.apps.course_metadata.models import Course as metadata_course
if not (self.request.user.is_superuser and waffle.switch_is_active('publisher_enable_course_import')):
raise Http404
form = AdminImportCourseForm(request.POST)
if form.is_valid():
start_id = self.request.POST.get('start_id')
for course in metadata_course.objects.filter(id__range=(start_id, int(start_id) + 9)):
process_course(course)
return super(AdminImportCourse, self).get(request, args, **kwargs,)
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-05-30 14:29+0500\n" "POT-Creation-Date: 2017-05-30 16:22+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: apps/api/filters.py #: apps/api/filters.py
#, python-brace-format #, python-brace-format
...@@ -1547,6 +1547,15 @@ msgid "" ...@@ -1547,6 +1547,15 @@ msgid ""
"more user options." "more user options."
msgstr "" msgstr ""
#: templates/publisher/admin/import_course.html
#: templates/publisher/course_detail.html
msgid "Course Detail"
msgstr ""
#: templates/publisher/admin/import_course.html
msgid "Import COURSE"
msgstr ""
#: templates/publisher/base.html templates/publisher/dashboard.html #: templates/publisher/base.html templates/publisher/dashboard.html
msgid "Dashboard" msgid "Dashboard"
msgstr "" msgstr ""
...@@ -1556,10 +1565,6 @@ msgid "Courses" ...@@ -1556,10 +1565,6 @@ msgid "Courses"
msgstr "" msgstr ""
#: templates/publisher/course_detail.html #: templates/publisher/course_detail.html
msgid "Course Detail"
msgstr ""
#: templates/publisher/course_detail.html
#: templates/publisher/course_run_detail/_widgets.html #: templates/publisher/course_run_detail/_widgets.html
msgid "EDIT" msgid "EDIT"
msgstr "" msgstr ""
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-05-30 14:29+0500\n" "POT-Creation-Date: 2017-05-30 16:22+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: static/js/catalogs-change-form.js #: static/js/catalogs-change-form.js
msgid "Preview" msgid "Preview"
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-05-30 14:29+0500\n" "POT-Creation-Date: 2017-05-30 16:22+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: apps/api/filters.py #: apps/api/filters.py
...@@ -1812,6 +1812,15 @@ msgstr "" ...@@ -1812,6 +1812,15 @@ msgstr ""
"Fïrst, éntér ä üsérnämé änd séléçt ä gröüp. Thén, ýöü'll ßé äßlé tö édït " "Fïrst, éntér ä üsérnämé änd séléçt ä gröüp. Thén, ýöü'll ßé äßlé tö édït "
"möré üsér öptïöns. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" "möré üsér öptïöns. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#"
#: templates/publisher/admin/import_course.html
#: templates/publisher/course_detail.html
msgid "Course Detail"
msgstr "Çöürsé Détäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: templates/publisher/admin/import_course.html
msgid "Import COURSE"
msgstr "Ìmpört ÇÖÛRSÉ Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: templates/publisher/base.html templates/publisher/dashboard.html #: templates/publisher/base.html templates/publisher/dashboard.html
msgid "Dashboard" msgid "Dashboard"
msgstr "Däshßöärd Ⱡ'σяєм ιρѕυм ∂σł#" msgstr "Däshßöärd Ⱡ'σяєм ιρѕυм ∂σł#"
...@@ -1821,10 +1830,6 @@ msgid "Courses" ...@@ -1821,10 +1830,6 @@ msgid "Courses"
msgstr "Çöürsés Ⱡ'σяєм ιρѕυм #" msgstr "Çöürsés Ⱡ'σяєм ιρѕυм #"
#: templates/publisher/course_detail.html #: templates/publisher/course_detail.html
msgid "Course Detail"
msgstr "Çöürsé Détäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: templates/publisher/course_detail.html
#: templates/publisher/course_run_detail/_widgets.html #: templates/publisher/course_run_detail/_widgets.html
msgid "EDIT" msgid "EDIT"
msgstr "ÉDÌT Ⱡ'σяєм ι#" msgstr "ÉDÌT Ⱡ'σяєм ι#"
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-05-30 14:29+0500\n" "POT-Creation-Date: 2017-05-30 16:22+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/js/catalogs-change-form.js #: static/js/catalogs-change-form.js
......
{% extends 'publisher/base.html' %}
{% load i18n %}
{% load static %}
{% block title %}
{% trans "Course Detail" %}
{% endblock title %}
{% block page_content %}
<form method="post" action="">
{% csrf_token %}
<div class="col col-6 help-text">
<label class="field-label ">{{ form.start_id.label }}</label>
{{ form.start_id }}
<button class="btn-brand btn-base btn-save" type="submit">{% trans "Import COURSE" %}</button>
</div>
</form>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment