Commit f0547b5a by Waheed Ahmed Committed by GitHub

Merge pull request #382 from edx/waheed/ecom-5175-help-text-course-run

Added new course run form.
parents 2cfb7f9a 834b7900
......@@ -5,6 +5,7 @@ from django.contrib.auth.models import Group
from django import forms
from django.utils.translation import ugettext_lazy as _
from course_discovery.apps.course_metadata.choices import CourseRunPacing
from course_discovery.apps.course_metadata.models import Person
from course_discovery.apps.publisher.models import Course, CourseRun, Seat, User
......@@ -49,8 +50,8 @@ class CustomCourseForm(CourseForm):
""" Course Form. """
institution = forms.ModelChoiceField(queryset=Group.objects.all(), required=True)
title = forms.CharField(label='Course Title', required=True, max_length=255)
number = forms.CharField(label='Course Number', required=True, max_length=255)
title = forms.CharField(label=_('Course Title'), required=True)
number = forms.CharField(label=_('Course Number'), required=True)
team_admin = forms.ModelChoiceField(queryset=User.objects.filter(is_staff=True), required=True)
class Meta(CourseForm.Meta):
......@@ -63,6 +64,28 @@ class CustomCourseForm(CourseForm):
)
class UpdateCourseForm(BaseCourseForm):
""" Course form to update specific fields for already created course. """
number = forms.CharField(label=_('Course Number'), required=True)
team_admin = forms.ModelChoiceField(queryset=User.objects.filter(is_staff=True), required=True)
class Meta:
model = Course
fields = ('number', 'team_admin',)
def save(self, commit=True, changed_by=None): # pylint: disable=arguments-differ
course = super(UpdateCourseForm, self).save(commit=False)
if changed_by:
course.changed_by = changed_by
if commit:
course.save()
return course
class CourseRunForm(BaseCourseForm):
""" Course Run Form. """
......@@ -78,7 +101,8 @@ class CustomCourseRunForm(CourseRunForm):
contacted_partner_manager = forms.BooleanField(
widget=forms.RadioSelect(choices=((1, _("Yes")), (0, _("No")))), initial=0, required=False
)
start = forms.DateTimeField(required=True)
start = forms.DateTimeField(label=_('Course start date'), required=True)
end = forms.DateTimeField(label=_('Course end date'), required=False)
staff = forms.ModelMultipleChoiceField(
queryset=Person.objects.all(), widget=forms.SelectMultiple, required=False
)
......@@ -86,14 +110,36 @@ class CustomCourseRunForm(CourseRunForm):
widget=forms.RadioSelect(
choices=((1, _("Yes")), (0, _("No")))), initial=0, required=False
)
is_self_paced = forms.BooleanField(label=_('Yes, course will be Self-Paced'), required=False)
class Meta(CourseRunForm.Meta):
fields = (
'length', 'transcript_languages', 'language', 'min_effort', 'max_effort',
'contacted_partner_manager', 'target_content', 'pacing_type',
'video_language', 'staff', 'start', 'end',
'video_language', 'staff', 'start', 'end', 'is_self_paced',
)
def clean(self):
super(CustomCourseRunForm, self).clean()
self.cleaned_data['pacing_type'] = CourseRunPacing.Self if self.cleaned_data['is_self_paced']\
else CourseRunPacing.Instructor
return self.cleaned_data
def save(self, commit=True, course=None, changed_by=None): # pylint: disable=arguments-differ
course_run = super(CustomCourseRunForm, self).save(commit=False)
if course:
course_run.course = course
if changed_by:
course_run.changed_by = changed_by
if commit:
course_run.save()
return course_run
class SeatForm(BaseCourseForm):
""" Course Seat Form. """
......@@ -103,7 +149,7 @@ class SeatForm(BaseCourseForm):
fields = '__all__'
exclude = ('currency', 'changed_by',)
def save(self, commit=True):
def save(self, commit=True, course_run=None, changed_by=None): # pylint: disable=arguments-differ
seat = super(SeatForm, self).save(commit=False)
if seat.type in [Seat.HONOR, Seat.AUDIT]:
seat.price = 0.00
......@@ -118,6 +164,12 @@ class SeatForm(BaseCourseForm):
seat.credit_provider = ''
seat.credit_hours = None
if course_run:
seat.course_run = course_run
if changed_by:
seat.changed_by = changed_by
if commit:
seat.save()
......
# pylint: disable=no-member
import json
from datetime import datetime
import ddt
import factory
from mock import patch
from django.db import IntegrityError
......@@ -12,6 +14,7 @@ from django.core.urlresolvers import reverse
from django.forms import model_to_dict
from django.test import TestCase
from guardian.shortcuts import assign_perm
from testfixtures import LogCapture
from course_discovery.apps.core.models import User
from course_discovery.apps.core.tests.factories import UserFactory, USER_PASSWORD
......@@ -21,7 +24,7 @@ from course_discovery.apps.publisher.models import Course, CourseRun, Seat, Stat
from course_discovery.apps.publisher.tests import factories, JSON_CONTENT_TYPE
from course_discovery.apps.publisher.tests.utils import create_non_staff_user_and_login
from course_discovery.apps.publisher.utils import is_email_notification_enabled
from course_discovery.apps.publisher.views import CourseRunDetailView
from course_discovery.apps.publisher.views import CourseRunDetailView, logger as publisher_views_logger
from course_discovery.apps.publisher.wrappers import CourseRunWrapper
from course_discovery.apps.publisher_comments.tests.factories import CommentFactory
......@@ -43,7 +46,7 @@ class CreateUpdateCourseViewTests(TestCase):
self.site = Site.objects.get(pk=settings.SITE_ID)
self.client.login(username=self.user.username, password=USER_PASSWORD)
self.group_2 = factories.GroupFactory()
self.start_date_time = '2050-07-08 05:59:53'
self.start_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def test_course_form_without_login(self):
""" Verify that user can't access new course form page when not logged in. """
......@@ -299,8 +302,13 @@ class CreateUpdateCourseRunViewTests(TestCase):
def setUp(self):
super(CreateUpdateCourseRunViewTests, self).setUp()
self.user = UserFactory(is_staff=True, is_superuser=True)
self.course = factories.CourseFactory(team_admin=self.user)
self.course_run = factories.CourseRunFactory()
self.course_run_dict = model_to_dict(self.course_run)
self.course_run_dict.update(
{'number': self.course.number, 'team_admin': self.course.team_admin.id, 'is_self_paced': True}
)
self._pop_valuse_from_dict(
self.course_run_dict,
[
......@@ -308,7 +316,7 @@ class CreateUpdateCourseRunViewTests(TestCase):
'priority', 'certificate_generation', 'video_language'
]
)
self.user = UserFactory(is_staff=True, is_superuser=True)
self.course_run_dict['start'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.site = Site.objects.get(pk=settings.SITE_ID)
self.client.login(username=self.user.username, password=USER_PASSWORD)
......@@ -316,47 +324,113 @@ class CreateUpdateCourseRunViewTests(TestCase):
for key in key_list:
data_dict.pop(key)
def test_courserun_form_with_login(self):
""" Verify that user can access new course run form page when logged in. """
response = self.client.get(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id})
)
self.assertEqual(response.status_code, 200)
def test_courserun_form_without_login(self):
""" Verify that user can't access new course run form page when not logged in. """
self.client.logout()
response = self.client.get(reverse('publisher:publisher_course_runs_new'))
response = self.client.get(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id})
)
self.assertRedirects(
response,
expected_url='{url}?next={next}'.format(
url=reverse('login'),
next=reverse('publisher:publisher_course_runs_new')
next=reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id})
),
status_code=302,
target_status_code=302
)
def test_create_course_run(self):
""" Verify that we can create a new course run. """
lms_course_id = 'course-v1:testX+AS12131+2016_q4'
self.course_run_dict['lms_course_id'] = lms_course_id
self.course_run_dict['start'] = '2050-07-08 05:59:53'
response = self.client.post(reverse('publisher:publisher_course_runs_new'), self.course_run_dict)
def test_create_course_run_and_seat_with_errors(self):
""" Verify that without providing required data course run and seat
cannot be created.
"""
response = self.client.post(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}),
self.course_run_dict
)
self.assertEqual(response.status_code, 400)
post_data = model_to_dict(self.course)
post_data.update(self.course_run_dict)
post_data.update(factory.build(dict, FACTORY_CLASS=factories.SeatFactory))
self._pop_valuse_from_dict(post_data, ['id', 'upgrade_deadline', 'image', 'team_admin'])
response = self.client.post(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}),
post_data
)
self.assertEqual(response.status_code, 400)
with patch('django.forms.models.BaseModelForm.is_valid') as mocked_is_valid:
mocked_is_valid.return_value = True
with LogCapture(publisher_views_logger.name) as log_capture:
response = self.client.post(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}),
post_data
)
self.assertEqual(response.status_code, 400)
log_capture.check(
(
publisher_views_logger.name,
'ERROR',
'Unable to create course run and seat for course [{}].'.format(self.course.id)
)
)
def test_create_course_run_and_seat(self):
""" Verify that we can create a new course run with seat. """
updated_course_number = '{number}.2'.format(number=self.course.number)
new_price = 450
post_data = self.course_run_dict
seat = factories.SeatFactory(course_run=self.course_run, type=Seat.HONOR, price=0)
post_data.update(**model_to_dict(seat))
post_data.update(
{
'number': updated_course_number,
'type': Seat.VERIFIED,
'price': new_price
}
)
self._pop_valuse_from_dict(post_data, ['id', 'course', 'course_run'])
response = self.client.post(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}),
post_data
)
course_run = CourseRun.objects.get(course=self.course_run.course, lms_course_id=lms_course_id)
new_seat = Seat.objects.get(type=post_data['type'], price=post_data['price'])
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_course_runs_edit', kwargs={'pk': course_run.id}),
expected_url=reverse('publisher:publisher_course_run_detail', kwargs={'pk': new_seat.course_run.id}),
status_code=302,
target_status_code=200
)
self.assertEqual(course_run.lms_course_id, lms_course_id)
# Verify that new seat and new course run are unique
self.assertNotEqual(new_seat.type, seat.type)
self.assertEqual(new_seat.type, Seat.VERIFIED)
self.assertNotEqual(new_seat.price, seat.price)
self.assertEqual(new_seat.price, new_price)
self.assertNotEqual(new_seat.course_run, self.course_run)
response = self.client.get(reverse('publisher:publisher_course_runs_new'))
self.assertNotContains(response, 'Add new comment')
self.assertNotContains(response, 'Total Comments')
self.course = new_seat.course_run.course
# Verify that number is updated for parent course
self.assertEqual(self.course.number, updated_course_number)
def test_update_course_run_with_staff(self):
""" Verify that staff user can update an existing course run. """
updated_lms_course_id = 'course-v1:testX+AS121+2018_q1'
self.course_run_dict['lms_course_id'] = updated_lms_course_id
self.course_run_dict['start'] = '2050-07-08 05:59:53'
self.assertNotEqual(self.course_run.lms_course_id, updated_lms_course_id)
self.assertNotEqual(self.course_run.changed_by, self.user)
......@@ -390,7 +464,6 @@ class CreateUpdateCourseRunViewTests(TestCase):
updated_lms_course_id = 'course-v1:testX+AS121+2018_q1'
self.course_run_dict['lms_course_id'] = updated_lms_course_id
self.course_run_dict['start'] = '2050-07-08 05:59:53'
self.assertNotEqual(self.course_run.lms_course_id, updated_lms_course_id)
response = self.client.get(
......@@ -414,7 +487,6 @@ class CreateUpdateCourseRunViewTests(TestCase):
non_staff_user, group = create_non_staff_user_and_login(self)
updated_lms_course_id = 'course-v1:testX+AS121+2018_q1'
self.course_run_dict['start'] = '2050-07-08 05:59:53'
self.course_run_dict['lms_course_id'] = updated_lms_course_id
self.assertNotEqual(self.course_run.lms_course_id, updated_lms_course_id)
......
......@@ -10,15 +10,19 @@ urlpatterns = [
url(r'^courses/new$', views.CreateCourseView.as_view(), name='publisher_courses_new'),
url(r'^courses/(?P<pk>\d+)/view/$', views.ReadOnlyView.as_view(), name='publisher_courses_readonly'),
url(r'^courses/(?P<pk>\d+)/edit/$', views.UpdateCourseView.as_view(), name='publisher_courses_edit'),
url(
r'^courses/(?P<parent_course_id>\d+)/course_runs/new/$',
views.CreateCourseRunView.as_view(),
name='publisher_course_runs_new'
),
url(r'^course_runs/(?P<pk>\d+)/$', views.CourseRunDetailView.as_view(), name='publisher_course_run_detail'),
url(r'^course_runs/new$', views.CreateCourseRunView.as_view(), name='publisher_course_runs_new'),
url(r'^course_runs/(?P<pk>\d+)/edit/$', views.UpdateCourseRunView.as_view(), name='publisher_course_runs_edit'),
url(
r'^course_runs/(?P<course_run_id>\d+)/change_state/$',
views.ChangeStateView.as_view(),
name='publisher_change_state'
),
url(r'^seats/new$', views.CreateSeatView.as_view(), name='publisher_seats_new'),
url(r'^seats/new/$', views.CreateSeatView.as_view(), name='publisher_seats_new'),
url(r'^seats/(?P<pk>\d+)/edit/$', views.UpdateSeatView.as_view(), name='publisher_seats_edit'),
url(
r'^user/toggle/email_settings/$',
......
......@@ -2,6 +2,7 @@
Course publisher views.
"""
import json
import logging
from datetime import datetime, timedelta
from django.contrib import messages
......@@ -11,23 +12,23 @@ from django.db import transaction
from django.http import HttpResponseRedirect, HttpResponseForbidden, JsonResponse
from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.views.generic import View
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.list import ListView
from django.views.generic import View, CreateView, UpdateView, DetailView, ListView
from django_fsm import TransitionNotAllowed
from guardian.shortcuts import get_objects_for_user
from rest_framework.generics import UpdateAPIView
from course_discovery.apps.publisher.forms import (
CourseForm, CourseRunForm, SeatForm, CustomCourseForm, CustomCourseRunForm, CustomSeatForm
)
CourseForm, CourseRunForm, SeatForm, CustomCourseForm, CustomCourseRunForm, CustomSeatForm,
UpdateCourseForm)
from course_discovery.apps.publisher import mixins
from course_discovery.apps.publisher.models import Course, CourseRun, Seat, State, UserAttributes
from course_discovery.apps.publisher.serializers import UpdateCourseKeySerializer
from course_discovery.apps.publisher.wrappers import CourseRunWrapper
logger = logging.getLogger(__name__)
SEATS_HIDDEN_FIELDS = ['price', 'currency', 'upgrade_deadline', 'credit_provider', 'credit_hours']
......@@ -183,15 +184,74 @@ class ReadOnlyView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, Detail
return context
class CreateCourseRunView(mixins.LoginRequiredMixin, mixins.FormValidMixin, CreateView):
class CreateCourseRunView(mixins.LoginRequiredMixin, CreateView):
""" Create Course Run View."""
model = CourseRun
form_class = CourseRunForm
template_name = 'publisher/course_run_form.html'
success_url = 'publisher:publisher_course_runs_edit'
course_form = UpdateCourseForm
run_form = CustomCourseRunForm
seat_form = CustomSeatForm
template_name = 'publisher/add_courserun_form.html'
success_url = 'publisher:publisher_course_run_detail'
parent_course = None
fields = ()
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
def get_parent_course(self):
if not self.parent_course:
self.parent_course = get_object_or_404(Course, pk=self.kwargs.get('parent_course_id'))
return self.parent_course
def get_context_data(self, **kwargs):
parent_course = self.get_parent_course()
course_form = self.course_form(instance=parent_course)
context = {
'parent_course': parent_course,
'course_form': course_form,
'run_form': self.run_form,
'seat_form': self.seat_form,
'is_team_admin_hidden': parent_course.team_admin and 'team_admin' not in course_form.errors
}
return context
def post(self, request, *args, **kwargs):
user = request.user
parent_course = self.get_parent_course()
course_form = self.course_form(request.POST, instance=self.get_parent_course())
run_form = self.run_form(request.POST)
seat_form = self.seat_form(request.POST)
if course_form.is_valid() and run_form.is_valid() and seat_form.is_valid():
try:
with transaction.atomic():
course = course_form.save(changed_by=user)
course_run = run_form.save(course=course, changed_by=user)
seat_form.save(course_run=course_run, changed_by=user)
# pylint: disable=no-member
success_msg = _('Course run created successfully for course "{course_title}".').format(
course_title=course.title
)
messages.success(request, success_msg)
return HttpResponseRedirect(reverse(self.success_url, kwargs={'pk': course_run.id}))
except Exception as error: # pylint: disable=broad-except
# pylint: disable=no-member
error_msg = _('There was an error saving course run, {error}').format(error=error)
messages.error(request, error_msg)
logger.exception('Unable to create course run and seat for course [%s].', parent_course.id)
else:
messages.error(request, _('Please fill all required fields.'))
context = self.get_context_data()
context.update(
{
'course_form': course_form,
'run_form': run_form,
'seat_form': seat_form,
'is_team_admin_hidden': parent_course.team_admin and 'team_admin' not in course_form.errors
}
)
return render(request, self.template_name, context, status=400)
class UpdateCourseRunView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixins.FormValidMixin, UpdateView):
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-17 23:20+0500\n"
"POT-Creation-Date: 2016-11-18 17:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -17,7 +17,6 @@ msgstr ""
"Language: \n"
#: apps/api/filters.py
#, python-brace-format
msgid "No user with the username [{username}] exists."
msgstr ""
......@@ -111,7 +110,6 @@ msgstr ""
#. Translators: 'period_choices' is a list of possible values, like ('second',
#. 'minute', 'hour')
#: apps/core/forms.py
#, python-brace-format
msgid "period must be one of {period_choices}."
msgstr ""
......@@ -410,7 +408,6 @@ msgid "JSON string containing an elasticsearch function score config."
msgstr ""
#: apps/publisher/emails.py
#, python-brace-format
msgid "Course Run {title}-{pacing_type}-{start} state has been changed."
msgstr ""
......@@ -418,6 +415,16 @@ msgstr ""
msgid "Studio instance created"
msgstr ""
#: apps/publisher/forms.py templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Course Title"
msgstr ""
#: apps/publisher/forms.py templates/publisher/add_course_form.html
#: templates/publisher/dashboard/_studio_requests.html
msgid "Course Number"
msgstr ""
#: apps/publisher/forms.py
msgid "Yes"
msgstr ""
......@@ -427,6 +434,18 @@ msgid "No"
msgstr ""
#: apps/publisher/forms.py
msgid "Course start date"
msgstr ""
#: apps/publisher/forms.py
msgid "Course end date"
msgstr ""
#: apps/publisher/forms.py
msgid "Yes, course will be Self-Paced"
msgstr ""
#: apps/publisher/forms.py
msgid "Only honor/audit seats can be without price."
msgstr ""
......@@ -546,7 +565,18 @@ msgid "Please fill all required field."
msgstr ""
#: apps/publisher/views.py
#, python-brace-format
msgid "Course run created successfully for course \"{course_title}\"."
msgstr ""
#: apps/publisher/views.py
msgid "There was an error saving course run, {error}"
msgstr ""
#: apps/publisher/views.py
msgid "Please fill all required fields."
msgstr ""
#: apps/publisher/views.py
msgid "Content moved to `{state}` successfully."
msgstr ""
......@@ -571,12 +601,10 @@ msgid "Publish"
msgstr ""
#: apps/publisher_comments/emails.py
#, python-brace-format
msgid "New comment added in course run: {title}-{pacing_type}-{start}"
msgstr ""
#: apps/publisher_comments/emails.py
#, python-brace-format
msgid "New comment added in Course: {title}"
msgstr ""
......@@ -706,34 +734,37 @@ msgid ""
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "required"
msgstr ""
#: templates/publisher/add_course_form.html
msgid "Course Title"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Best Practices"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Example"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Concise 70 characters maximum; < 50 chars. recommended."
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Descriptive - clearly indicates what the course is about."
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "SEO-optimized and targeted to a global audience."
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid ""
"If the course falls in a sequence, our titling convention is: \"Course "
"Title: Subtitle\""
......@@ -744,14 +775,17 @@ msgid "English Grammar and Essay Writing Sequence Courses:"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Introduction to Statistics"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Statistics: Inference"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Statistics: Probability"
msgstr ""
......@@ -786,16 +820,12 @@ msgid "Pacing Type"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid ""
"Will your course be open to students at the same time as it is announced?"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/dashboard/_studio_requests.html
msgid "Course Number"
msgstr ""
#: templates/publisher/add_course_form.html
msgid ""
"Courses split into several modules can be denoted by adding .1, .2, etc. at "
"the end of the course number before the “x”"
......@@ -808,6 +838,7 @@ msgid ""
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "About page information"
msgstr ""
......@@ -819,6 +850,7 @@ msgid "End Date"
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid ""
"The date when this self-paced course run will end, replaced by an updated "
"version of the course"
......@@ -1044,9 +1076,109 @@ msgid ""
msgstr ""
#: templates/publisher/add_course_form.html
#: templates/publisher/add_courserun_form.html
msgid "Save Draft"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "New Course Run"
msgstr ""
#: templates/publisher/add_courserun_form.html
#, python-format
msgid ""
"\n"
" The fields below will only affect this new course run. If you feel the need edit information from the parent course then you may do so on the %(link_start)s%(course_url)s%(link_middle)sparent course for this run%(link_end)s.\n"
" "
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "Studio instance information"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid ""
"\n"
" The information in this section is required to create a course studio instance. You must fill all required information but are welcome to come back and enter the rest of the information when you are ready to announce the course, or you can do it all at once if you are ready to do so.\n"
" "
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "COURSE TITLE"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "English Grammar and Essay Writing"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "Sequence Courses:"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "Institution Course Admin"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "Change"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "COURSE START DATE"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid ""
"\n"
" Start on a weekday (preferably Tuesday, Wednesday, or Thursday) and avoid major U.S. holidays\n"
" for best access to edX staff.\n"
" "
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid ""
"\n"
" Approximate dates are acceptable; If you are unable to give an exact date, please identify a\n"
" month in which the course will be offered.\n"
" "
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "COURSE NUMBER"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid ""
"\n"
" Courses split into several modules can be denoted by adding .1, .2, etc. at the end of the\n"
" course number before the “x”\n"
" No special html characters, accents, spaces, dashes, or underscores\n"
" 10 character limit\n"
" "
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "Example:"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "etc."
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "COURSE END DATE"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid "CERTIFICATE TYPE AND PRICE"
msgstr ""
#: templates/publisher/add_courserun_form.html
msgid ""
"If Verified or Professional Ed, indicate certificate price in US dollars "
"(minimum of $49)"
msgstr ""
#: templates/publisher/course_form.html
msgid "Add Course Run"
msgstr ""
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-17 23:20+0500\n"
"POT-Creation-Date: 2016-11-18 17:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-17 23:20+0500\n"
"POT-Creation-Date: 2016-11-18 17:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
$(".administration-nav .tab-container > button").click(function(event) {
event.preventDefault();
$(this).addClass("selected");
$(this).siblings().removeClass("selected");
var tab = $(this).data("tab");
$(".tab-content").not(tab).css("display", "none");
$(tab).fadeIn();
});
$(document).ready(function(){
$(".administration-nav .tab-container > button").click(function(event) {
event.preventDefault();
$(this).addClass("selected");
$(this).siblings().removeClass("selected");
var tab = $(this).data("tab");
$(".tab-content").not(tab).css("display", "none");
$(tab).fadeIn();
});
$('ul.tabs .course-tabs').click(function(){
var tab_id = $(this).attr('data-tab');
$('ul.tabs .course-tabs').removeClass('active');
$('.content').removeClass('active');
var tab_id = $(this).attr('data-tab'),
$tabContent = $("#"+tab_id);
$(this).parent().find('.course-tabs').removeClass('active');
$tabContent.parent().find('.content').removeClass('active');
$(this).addClass('active');
$("#"+tab_id).addClass('active');
})
$tabContent.addClass('active');
});
$("#change-admin").click(function (e) {
e.preventDefault();
$(".field-admin-name").hide();
$("#field-team-admin").show();
});
});
......@@ -47,6 +47,7 @@ $light-gray: rgba(204, 204, 204, 1);
height: auto;
position: absolute;
width: 340px;
z-index: 10000;
&.is-shown {
display: block;
......@@ -266,6 +267,7 @@ $light-gray: rgba(204, 204, 204, 1);
}
.tabs {
@include margin-left(0);
width: 100%;
display: inline-block;
}
......@@ -444,24 +446,27 @@ select {
border-bottom: 1px solid rgb(51, 51, 51);
padding-bottom: 10px;
margin-bottom: 20px;
font-weight: bold;
margin-top: 20px;
}
.field-label {
font-weight: bold;
}
.course-tabs{
list-style: none;
@include float(left);
@include margin-right(10px);
padding: 10px;
border-bottom: 2px solid #ccc;
border-bottom: 3px solid #ccc;
color: #ccc;
text-align: center;
&:hover{
color: #337ab7;
border-bottom: 2px solid #337ab7;
border-bottom: 3px solid #337ab7;
}
}
.course-tabs.active{
border-bottom: 2px solid #337ab7;
border-bottom: 3px solid #337ab7;
color: #337ab7;
}
.content{
......@@ -477,6 +482,12 @@ select {
display: inline-block;
}
#number-example {
p:first-of-type{
margin-bottom: 0;
}
}
.info-item {
margin-bottom: 15px;
......@@ -621,3 +632,11 @@ select {
margin: 0;
}
}
.margin-top20 {
margin-top: 20px;
}
.hidden {
display: none;
}
{% if messages %}
<div class="alert-messages">
{% for message in messages %}
<div class="alert alert-{{ message.tags }}" role="alert" aria-labelledby="alert-title-{{ message.tags }}" tabindex="-1">
<div class="alert-message-with-action">
<p class="alert-copy">
{{ message }}
</p>
</div>
</div>
{% endfor %}
</div>
{% endif %}
......@@ -5,7 +5,7 @@
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="layout-full layout publisher-layout">
<div class="publisher-container">
<div class="course-information">
<h4 class="hd-4">{% trans "Course Form" %}</h4>
......@@ -21,7 +21,7 @@
</div>
<div class="comment-container">
{% if object.id %}
<a href="{% url 'publisher:publisher_course_runs_new' %}" class="btn btn-neutral btn-add">
<a href="{% url 'publisher:publisher_course_runs_new' object.id %}" class="btn btn-neutral btn-add">
{% trans "Add Course Run" %}
</a>
{% endif %}
......
......@@ -23,19 +23,8 @@
<span class="course-name">{{ object.title }}</span>
</h2>
</div>
<div class="alert-messages">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}" role="alert" aria-labelledby="alert-title-{{ message.tags }}" tabindex="-1">
<div class="alert-message-with-action">
<p class="alert-copy">
{{ message }}
</p>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% include 'alert_messages.html' %}
<div class="status-information">
<div class="info-item">
......
......@@ -5,7 +5,7 @@
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="layout-full layout publisher-layout">
<div class="publisher-container">
<div class="course-information">
<h4 class="hd-4">{% trans "Course Run Form" %}</h4>
......
......@@ -6,7 +6,7 @@
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="layout-full layout publisher-layout">
<div class="publisher-container">
<div class="course-information">
<h4 class="hd-4">{% trans "Seat Form" %}</h4>
......
......@@ -5,19 +5,7 @@
{% endblock title %}
{% block content %}
<div class="alert-messages">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}" role="alert" aria-labelledby="alert-title-{{ message.tags }}" tabindex="-1">
<div class="alert-message-with-action">
<p class="alert-copy">
{{ message }}
</p>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% include 'alert_messages.html' %}
<div class="layout-full publisher-layout layout">
<h2 class="layout-title">{% trans "Base information" %}</h2>
......
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