Commit a97a3492 by Waheed Ahmed

Created course about form.

ECOM-4885
parent 5d48d785
...@@ -12,21 +12,26 @@ sudo: false ...@@ -12,21 +12,26 @@ sudo: false
cache: cache:
- directories: - directories:
- $HOME/.cache/pip - $HOME/.cache/pip
- node_modules
- course_discovery/static/bower_components
before_install: before_install:
- "export DISPLAY=:99.0" - "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start" - "sh -e /etc/init.d/xvfb start"
- "export DJANGO_SETTINGS_MODULE=course_discovery.settings.test"
- docker run --detach --publish 9200:9200 --publish 9300:9300 elasticsearch:1.5.2 - docker run --detach --publish 9200:9200 --publish 9300:9300 elasticsearch:1.5.2
install: install:
- pip install -U pip wheel codecov - pip install -U pip wheel codecov
- pip install -r requirements/test.txt - pip install -r requirements/test.txt
- make requirements.js
before_script: before_script:
# Give Elasticsearch time to start # Give Elasticsearch time to start
- sleep 10 - sleep 10
script: script:
- make static -e DJANGO_SETTINGS_MODULE="course_discovery.settings.test"
- make validate - make validate
after_success: after_success:
......
...@@ -21,6 +21,7 @@ help: ...@@ -21,6 +21,7 @@ help:
@echo " quality run PEP8 and Pylint" @echo " quality run PEP8 and Pylint"
@echo " production-requirements install requirements for production" @echo " production-requirements install requirements for production"
@echo " requirements install requirements for local development" @echo " requirements install requirements for local development"
@echo " requirements.js install JS requirements for local development and production"
@echo " test run tests and generate coverage report" @echo " test run tests and generate coverage report"
@echo " validate run tests and quality checks" @echo " validate run tests and quality checks"
@echo " static gather all static assets for production" @echo " static gather all static assets for production"
...@@ -32,15 +33,16 @@ help: ...@@ -32,15 +33,16 @@ help:
static: static:
$(NODE_BIN)/r.js -o build.js $(NODE_BIN)/r.js -o build.js
python manage.py collectstatic --noinput python manage.py collectstatic --noinput
python manage.py compress
clean_static: clean_static:
rm -rf assets/ course_discovery/static/build rm -rf course_discovery/assets/ course_discovery/static/build/
clean: clean_static clean:
find . -name '*.pyc' -delete find . -name '*.pyc' -delete
coverage erase coverage erase
requirement.js: requirements.js:
npm install npm install
$(NODE_BIN)/bower install $(NODE_BIN)/bower install
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
"tests" "tests"
], ],
"dependencies": { "dependencies": {
"edx-pattern-library": "0.16.1" "edx-pattern-library": "0.16.3",
"underscore": "~1.8.3",
"moment": "~2.10.3",
"pikaday": "https://github.com/owenmead/Pikaday.git#1.4.0"
} }
} }
...@@ -7,5 +7,5 @@ def core(_request): ...@@ -7,5 +7,5 @@ def core(_request):
""" Site-wide context processor. """ """ Site-wide context processor. """
return { return {
'platform_name': settings.PLATFORM_NAME, 'platform_name': settings.PLATFORM_NAME,
'language_bidi': 'rtl' if get_language_bidi() else 'ltr' 'language_bidi': get_language_bidi()
} }
...@@ -13,4 +13,4 @@ class CoreContextProcessorTests(TestCase): ...@@ -13,4 +13,4 @@ class CoreContextProcessorTests(TestCase):
@override_settings(PLATFORM_NAME=PLATFORM_NAME) @override_settings(PLATFORM_NAME=PLATFORM_NAME)
def test_core(self): def test_core(self):
request = RequestFactory().get('/') request = RequestFactory().get('/')
self.assertDictEqual(core(request), {'platform_name': PLATFORM_NAME, 'language_bidi': 'ltr'}) self.assertDictEqual(core(request), {'platform_name': PLATFORM_NAME, 'language_bidi': False})
"""
Course publisher forms.
"""
from django import forms
from course_discovery.apps.publisher.models import Course, CourseRun, Seat
class BaseCourseForm(forms.ModelForm):
""" Base Course Form. """
def __init__(self, *args, **kwargs):
super(BaseCourseForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field_classes = 'field-input input-text'
if isinstance(field, forms.Textarea):
field_classes = 'field-textarea input-textarea'
if isinstance(field, (forms.ModelChoiceField, forms.TypedChoiceField,)):
field_classes = 'field-input input-select'
if isinstance(field, forms.BooleanField):
field_classes = 'field-input input-checkbox'
if isinstance(field, forms.DateTimeField):
field_classes = '{} add-pikaday'.format(field_classes)
field.input_formats = ['YYYY-MM-DDTHH:mm:ss']
if isinstance(field, forms.ModelMultipleChoiceField):
field_classes = 'field-input'
if field_name in self.errors:
field_classes = '{} has-error'.format(field_classes)
field.widget.attrs['class'] = field_classes
class CourseForm(BaseCourseForm):
""" Course Form. """
class Meta:
model = Course
fields = '__all__'
class CourseRunForm(BaseCourseForm):
""" Course Run Form. """
class Meta:
model = CourseRun
fields = '__all__'
class SeatForm(BaseCourseForm):
""" Course Seat Form. """
class Meta:
model = Seat
fields = '__all__'
exclude = ('currency',)
def save(self, commit=True):
seat = super(SeatForm, self).save(commit=False)
if seat.type in [Seat.HONOR, Seat.AUDIT]:
seat.price = 0.00
seat.upgrade_deadline = None
seat.credit_provider = ''
seat.credit_hours = None
if seat.type == Seat.VERIFIED:
seat.credit_provider = ''
seat.credit_hours = None
if seat.type in [Seat.PROFESSIONAL, Seat.NO_ID_PROFESSIONAL]:
seat.upgrade_deadline = None
seat.credit_provider = ''
seat.credit_hours = None
if commit:
seat.save()
return seat
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import sortedm2m.fields
class Migration(migrations.Migration):
dependencies = [
('publisher', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='course',
name='expected_learnings',
field=models.TextField(verbose_name="What you'll learn", default=None, blank=True, null=True),
),
migrations.AlterField(
model_name='course',
name='full_description',
field=models.TextField(verbose_name='About this course', default=None, blank=True, null=True),
),
migrations.AlterField(
model_name='course',
name='level_type',
field=models.ForeignKey(blank=True, to='course_metadata.LevelType', verbose_name='Course level', default=None, null=True, related_name='publisher_courses'),
),
migrations.AlterField(
model_name='course',
name='number',
field=models.CharField(verbose_name='Course number', max_length=50, blank=True, null=True),
),
migrations.AlterField(
model_name='course',
name='organizations',
field=models.ManyToManyField(verbose_name='Partner Name', related_name='publisher_courses', blank=True, to='course_metadata.Organization', null=True),
),
migrations.AlterField(
model_name='course',
name='primary_subject',
field=models.ForeignKey(blank=True, to='course_metadata.Subject', null=True, default=None, related_name='publisher_courses_primary'),
),
migrations.AlterField(
model_name='course',
name='secondary_subject',
field=models.ForeignKey(blank=True, to='course_metadata.Subject', null=True, default=None, related_name='publisher_courses_secondary'),
),
migrations.AlterField(
model_name='course',
name='short_description',
field=models.CharField(verbose_name='Course subtitle', default=None, max_length=255, blank=True, null=True),
),
migrations.AlterField(
model_name='course',
name='tertiary_subject',
field=models.ForeignKey(blank=True, to='course_metadata.Subject', null=True, default=None, related_name='publisher_courses_tertiary'),
),
migrations.AlterField(
model_name='course',
name='title',
field=models.CharField(verbose_name='Course title', default=None, max_length=255, blank=True, null=True),
),
migrations.AlterField(
model_name='courserun',
name='micromasters_name',
field=models.CharField(null=True, blank=True, max_length=255),
),
migrations.AlterField(
model_name='courserun',
name='staff',
field=sortedm2m.fields.SortedManyToManyField(null=True, related_name='publisher_course_runs_staffed', blank=True, to='course_metadata.Person', help_text=None),
),
migrations.AlterField(
model_name='courserun',
name='xseries_name',
field=models.CharField(null=True, blank=True, max_length=255),
),
migrations.AlterField(
model_name='historicalcourse',
name='expected_learnings',
field=models.TextField(verbose_name="What you'll learn", default=None, blank=True, null=True),
),
migrations.AlterField(
model_name='historicalcourse',
name='full_description',
field=models.TextField(verbose_name='About this course', default=None, blank=True, null=True),
),
migrations.AlterField(
model_name='historicalcourse',
name='number',
field=models.CharField(verbose_name='Course number', max_length=50, blank=True, null=True),
),
migrations.AlterField(
model_name='historicalcourse',
name='short_description',
field=models.CharField(verbose_name='Course subtitle', default=None, max_length=255, blank=True, null=True),
),
migrations.AlterField(
model_name='historicalcourse',
name='title',
field=models.CharField(verbose_name='Course title', default=None, max_length=255, blank=True, null=True),
),
migrations.AlterField(
model_name='historicalcourserun',
name='micromasters_name',
field=models.CharField(null=True, blank=True, max_length=255),
),
migrations.AlterField(
model_name='historicalcourserun',
name='xseries_name',
field=models.CharField(null=True, blank=True, max_length=255),
),
migrations.AlterField(
model_name='historicalseat',
name='type',
field=models.CharField(choices=[('honor', 'Honor'), ('audit', 'Audit'), ('verified', 'Verified'), ('professional', 'Professional (with ID verification)'), ('no-id-professional', 'Professional (no ID verifiation)'), ('credit', 'Credit')], verbose_name='Seat type', max_length=63),
),
migrations.AlterField(
model_name='seat',
name='currency',
field=models.ForeignKey(to='core.Currency', related_name='publisher_seats', default='USD'),
),
migrations.AlterField(
model_name='seat',
name='type',
field=models.CharField(choices=[('honor', 'Honor'), ('audit', 'Audit'), ('verified', 'Verified'), ('professional', 'Professional (with ID verification)'), ('no-id-professional', 'Professional (no ID verifiation)'), ('credit', 'Credit')], verbose_name='Seat type', max_length=63),
),
]
...@@ -21,20 +21,32 @@ class ChangedByMixin(object): ...@@ -21,20 +21,32 @@ class ChangedByMixin(object):
class Course(TimeStampedModel, ChangedByMixin): class Course(TimeStampedModel, ChangedByMixin):
""" Publisher Course model. It contains fields related to the course intake form.""" """ Publisher Course model. It contains fields related to the course intake form."""
title = models.CharField(max_length=255, default=None, null=True, blank=True) title = models.CharField(max_length=255, default=None, null=True, blank=True, verbose_name=_('Course title'))
number = models.CharField(max_length=50, null=True, blank=True) number = models.CharField(max_length=50, null=True, blank=True, verbose_name=_('Course number'))
short_description = models.CharField(max_length=255, default=None, null=True, blank=True) short_description = models.CharField(
full_description = models.TextField(default=None, null=True, blank=True) max_length=255, default=None, null=True, blank=True, verbose_name=_('Course subtitle')
organizations = models.ManyToManyField(Organization, blank=True, related_name='publisher_courses') )
level_type = models.ForeignKey(LevelType, default=None, null=True, blank=True, related_name='publisher_courses') full_description = models.TextField(default=None, null=True, blank=True, verbose_name=_('About this course'))
expected_learnings = models.TextField(default=None, null=True, blank=True) organizations = models.ManyToManyField(
Organization, null=True, blank=True, related_name='publisher_courses', verbose_name=_('Partner Name')
)
level_type = models.ForeignKey(
LevelType, default=None, null=True, blank=True, related_name='publisher_courses', verbose_name=_('Course level')
)
expected_learnings = models.TextField(default=None, null=True, blank=True, verbose_name=_("What you'll learn"))
syllabus = models.TextField(default=None, null=True, blank=True) syllabus = models.TextField(default=None, null=True, blank=True)
prerequisites = models.TextField(default=None, null=True, blank=True) prerequisites = models.TextField(default=None, null=True, blank=True)
learner_testimonial = models.CharField(max_length=50, null=True, blank=True) learner_testimonial = models.CharField(max_length=50, null=True, blank=True)
primary_subject = models.ForeignKey(Subject, related_name='publisher_courses_primary') primary_subject = models.ForeignKey(
secondary_subject = models.ForeignKey(Subject, related_name='publisher_courses_secondary') Subject, default=None, null=True, blank=True, related_name='publisher_courses_primary'
tertiary_subject = models.ForeignKey(Subject, related_name='publisher_courses_tertiary') )
secondary_subject = models.ForeignKey(
Subject, default=None, null=True, blank=True, related_name='publisher_courses_secondary'
)
tertiary_subject = models.ForeignKey(
Subject, default=None, null=True, blank=True, related_name='publisher_courses_tertiary'
)
history = HistoricalRecords() history = HistoricalRecords()
...@@ -69,7 +81,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin): ...@@ -69,7 +81,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
pacing_type = models.CharField( pacing_type = models.CharField(
max_length=255, choices=CourseMetadataCourseRun.PACING_CHOICES, db_index=True, null=True, blank=True max_length=255, choices=CourseMetadataCourseRun.PACING_CHOICES, db_index=True, null=True, blank=True
) )
staff = SortedManyToManyField(Person, blank=True, related_name='publisher_course_runs_staffed') staff = SortedManyToManyField(Person, null=True, blank=True, related_name='publisher_course_runs_staffed')
min_effort = models.PositiveSmallIntegerField( min_effort = models.PositiveSmallIntegerField(
null=True, blank=True, null=True, blank=True,
help_text=_('Estimated minimum number of hours per week needed to complete a course run.')) help_text=_('Estimated minimum number of hours per week needed to complete a course run.'))
...@@ -87,9 +99,9 @@ class CourseRun(TimeStampedModel, ChangedByMixin): ...@@ -87,9 +99,9 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
is_re_run = models.BooleanField(default=False) is_re_run = models.BooleanField(default=False)
is_xseries = models.BooleanField(default=False) is_xseries = models.BooleanField(default=False)
xseries_name = models.CharField(max_length=255) xseries_name = models.CharField(max_length=255, null=True, blank=True)
is_micromasters = models.BooleanField(default=False) is_micromasters = models.BooleanField(default=False)
micromasters_name = models.CharField(max_length=255) micromasters_name = models.CharField(max_length=255, null=True, blank=True)
contacted_partner_manager = models.BooleanField(default=False) contacted_partner_manager = models.BooleanField(default=False)
seo_review = models.TextField( seo_review = models.TextField(
default=None, null=True, blank=True, help_text=_("SEO review on your course title and short description") default=None, null=True, blank=True, help_text=_("SEO review on your course title and short description")
...@@ -146,9 +158,9 @@ class Seat(TimeStampedModel, ChangedByMixin): ...@@ -146,9 +158,9 @@ class Seat(TimeStampedModel, ChangedByMixin):
'default': 0.00, 'default': 0.00,
} }
course_run = models.ForeignKey(CourseRun, related_name='seats') course_run = models.ForeignKey(CourseRun, related_name='seats')
type = models.CharField(max_length=63, choices=SEAT_TYPE_CHOICES) type = models.CharField(max_length=63, choices=SEAT_TYPE_CHOICES, verbose_name='Seat type')
price = models.DecimalField(**PRICE_FIELD_CONFIG) price = models.DecimalField(**PRICE_FIELD_CONFIG)
currency = models.ForeignKey(Currency, related_name='publisher_seats') currency = models.ForeignKey(Currency, default='USD', related_name='publisher_seats')
upgrade_deadline = models.DateTimeField(null=True, blank=True) upgrade_deadline = models.DateTimeField(null=True, blank=True)
credit_provider = models.CharField(max_length=255, null=True, blank=True) credit_provider = models.CharField(max_length=255, null=True, blank=True)
credit_hours = models.IntegerField(null=True, blank=True) credit_hours = models.IntegerField(null=True, blank=True)
......
from django.core.urlresolvers import reverse
from django.forms import model_to_dict
from django.test import TestCase
from course_discovery.apps.publisher.models import Course, CourseRun, Seat
from course_discovery.apps.publisher.tests import factories
class CreateUpdateCourseViewTests(TestCase):
""" Tests for the publisher `CreateCourseView` and `UpdateCourseView`. """
def setUp(self):
super(CreateUpdateCourseViewTests, self).setUp()
self.course = factories.CourseFactory()
def test_create_course(self):
""" Verify that we can create a new course. """
# Create unique course number
course_number = '{}.1.456'.format(self.course.number)
course_dict = model_to_dict(self.course)
course_dict['number'] = course_number
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict)
course = Course.objects.get(number=course_number)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_courses_edit', kwargs={'pk': course.id}),
status_code=302,
target_status_code=200
)
self.assertEqual(course.number, course_number)
def test_update_course(self):
""" Verify that we can update an existing course. """
course_dict = model_to_dict(self.course)
updated_course_title = 'Updated {}'.format(self.course.title)
course_dict['title'] = updated_course_title
self.assertNotEqual(self.course.title, updated_course_title)
response = self.client.post(
reverse('publisher:publisher_courses_edit', kwargs={'pk': self.course.id}),
course_dict
)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_courses_edit', kwargs={'pk': self.course.id}),
status_code=302,
target_status_code=200
)
course = Course.objects.get(id=self.course.id)
# Assert that course is updated.
self.assertEqual(course.title, updated_course_title)
class CreateUpdateCourseRunViewTests(TestCase):
""" Tests for the publisher `CreateCourseRunView` and `UpdateCourseRunView`. """
def setUp(self):
super(CreateUpdateCourseRunViewTests, self).setUp()
self.course_run = factories.CourseRunFactory()
self.course_run_dict = model_to_dict(self.course_run)
self._pop_valuse_from_dict(
self.course_run_dict,
['start', 'end', 'enrollment_start', 'enrollment_end', 'priority', 'certificate_generation']
)
def _pop_valuse_from_dict(self, data_dict, key_list):
for key in key_list:
data_dict.pop(key)
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
response = self.client.post(reverse('publisher:publisher_course_runs_new'), self.course_run_dict)
course_run = CourseRun.objects.get(course=self.course_run.course, lms_course_id=lms_course_id)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_course_runs_edit', kwargs={'pk': course_run.id}),
status_code=302,
target_status_code=200
)
self.assertEqual(course_run.lms_course_id, lms_course_id)
def test_update_course_run(self):
""" Verify that we 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.assertNotEqual(self.course_run.lms_course_id, updated_lms_course_id)
response = self.client.post(
reverse('publisher:publisher_course_runs_edit', kwargs={'pk': self.course_run.id}),
self.course_run_dict
)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_course_runs_edit', kwargs={'pk': self.course_run.id}),
status_code=302,
target_status_code=200
)
course_run = CourseRun.objects.get(id=self.course_run.id)
# Assert that course run is updated.
self.assertEqual(course_run.lms_course_id, updated_lms_course_id)
class SeatsCreateUpdateViewTests(TestCase):
""" Tests for the publisher `CreateSeatView` and `UpdateSeatView`. """
def setUp(self):
super(SeatsCreateUpdateViewTests, self).setUp()
self.seat = factories.SeatFactory(type=Seat.PROFESSIONAL, credit_hours=0)
self.seat_dict = model_to_dict(self.seat)
self.seat_dict.pop('upgrade_deadline')
def test_seat_view_page(self):
""" Verify that we can open new seat page. """
response = self.client.get(reverse('publisher:publisher_seats_new'))
# Assert that we can load seat page.
self.assertEqual(response.status_code, 200)
def test_create_seat(self):
""" Verify that we can create a new seat. """
seat_price = 670.00
self.seat_dict['price'] = seat_price
response = self.client.post(reverse('publisher:publisher_seats_new'), self.seat_dict)
seat = Seat.objects.get(course_run=self.seat.course_run, price=seat_price)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_seats_edit', kwargs={'pk': seat.id}),
status_code=302,
target_status_code=200
)
self.assertEqual(seat.price, seat_price)
def test_update_seat(self):
""" Verify that we can update an existing seat. """
self.assertEqual(self.seat.type, Seat.PROFESSIONAL)
updated_seat_price = 470.00
self.seat_dict['price'] = updated_seat_price
self.seat_dict['type'] = Seat.VERIFIED
self.assertNotEqual(self.seat.price, updated_seat_price)
response = self.client.post(
reverse('publisher:publisher_seats_edit', kwargs={'pk': self.seat.id}),
self.seat_dict
)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_seats_edit', kwargs={'pk': self.seat.id}),
status_code=302,
target_status_code=200
)
seat = Seat.objects.get(id=self.seat.id)
# Assert that seat is updated.
self.assertEqual(seat.price, updated_seat_price)
self.assertEqual(seat.type, Seat.VERIFIED)
self.seat_dict['type'] = Seat.HONOR
response = self.client.post(
reverse('publisher:publisher_seats_edit', kwargs={'pk': self.seat.id}),
self.seat_dict
)
seat = Seat.objects.get(id=self.seat.id)
# Assert that we change seat type.
self.assertEqual(seat.type, Seat.HONOR)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_seats_edit', kwargs={'pk': self.seat.id}),
status_code=302,
target_status_code=200
)
"""
URLs for the course publisher views.
"""
from django.conf.urls import url
from course_discovery.apps.publisher import views
urlpatterns = [
url(r'^courses/new$', views.CreateCourseView.as_view(), name='publisher_courses_new'),
url(r'^courses/(?P<pk>\d+)/edit/$', views.UpdateCourseView.as_view(), name='publisher_courses_edit'),
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'^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'),
]
"""
Course publisher views.
"""
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.views.generic import edit
from course_discovery.apps.publisher.forms import CourseForm, CourseRunForm, SeatForm
from course_discovery.apps.publisher.models import Course, CourseRun, Seat
SEATS_HIDDEN_FIELDS = ['price', 'currency', 'upgrade_deadline', 'credit_provider', 'credit_hours']
# pylint: disable=attribute-defined-outside-init
class CreateCourseView(edit.CreateView):
""" Create Course View."""
model = Course
form_class = CourseForm
template_name = 'publisher/course_form.html'
success_url = 'publisher:publisher_courses_edit'
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
class UpdateCourseView(edit.UpdateView):
""" Update Course View."""
model = Course
form_class = CourseForm
template_name = 'publisher/course_form.html'
success_url = 'publisher:publisher_courses_edit'
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
class CreateCourseRunView(edit.CreateView):
""" Create Course Run View."""
model = CourseRun
form_class = CourseRunForm
template_name = 'publisher/course_run_form.html'
success_url = 'publisher:publisher_course_runs_edit'
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
class UpdateCourseRunView(edit.UpdateView):
""" Update Course Run View."""
model = CourseRun
form_class = CourseRunForm
template_name = 'publisher/course_run_form.html'
success_url = 'publisher:publisher_course_runs_edit'
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
class CreateSeatView(edit.CreateView):
""" Create Seat View."""
model = Seat
form_class = SeatForm
template_name = 'publisher/seat_form.html'
success_url = 'publisher:publisher_seats_edit'
def get_context_data(self, **kwargs):
context = super(CreateSeatView, self).get_context_data(**kwargs)
context['hidden_fields'] = SEATS_HIDDEN_FIELDS
return context
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
class UpdateSeatView(edit.UpdateView):
""" Update Seat View."""
model = Seat
form_class = SeatForm
template_name = 'publisher/seat_form.html'
success_url = 'publisher:publisher_seats_edit'
def get_context_data(self, **kwargs):
context = super(UpdateSeatView, self).get_context_data(**kwargs)
context['hidden_fields'] = SEATS_HIDDEN_FIELDS
return context
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse(self.success_url, kwargs={'pk': self.object.id})
...@@ -153,7 +153,6 @@ COMPRESS_CSS_FILTERS = [ ...@@ -153,7 +153,6 @@ COMPRESS_CSS_FILTERS = [
'compressor.filters.cssmin.CSSMinFilter', 'compressor.filters.cssmin.CSSMinFilter',
] ]
# TEMPLATE CONFIGURATION # TEMPLATE CONFIGURATION
# See: https://docs.djangoproject.com/en/1.8/ref/settings/#templates # See: https://docs.djangoproject.com/en/1.8/ref/settings/#templates
TEMPLATES = [ TEMPLATES = [
......
$(function () {
var show_verified_fields,
hide_verified_fields,
show_professional_fields,
hide_professional_fields,
show_credit_fields,
hide_credit_fields,
hide_all_fields,
change_fields;
show_verified_fields= function () {
$('.field-price').show();
$('.field-upgrade_deadline').show();
};
hide_verified_fields = function () {
$('.field-price').hide();
$('.field-upgrade_deadline').hide();
};
show_professional_fields = function () {
$('.field-price').show();
};
hide_professional_fields = function () {
$('.field-price').hide();
};
show_credit_fields = function () {
show_verified_fields();
$('.field-credit_provider').show();
$('.field-credit_hours').show();
};
hide_credit_fields = function () {
hide_verified_fields();
$('.field-credit_provider').hide();
$('.field-credit_hours').hide();
};
hide_all_fields = function () {
hide_verified_fields();
hide_professional_fields();
hide_credit_fields()
};
change_fields = function (select_tag) {
if (!select_tag) {
select_tag = '#id_type';
}
var selected_value = $(select_tag).find("option:selected").val();
if (selected_value === 'verified') {
hide_all_fields();
show_verified_fields();
}
else if (selected_value === 'professional' || selected_value === 'no-id-professional') {
hide_all_fields();
show_professional_fields();
}
else if (selected_value === 'credit') {
hide_all_fields();
show_credit_fields();
}
else {
hide_all_fields();
}
};
change_fields();
$('.field-type .input-select').change(function () {
change_fields(this);
});
});
function addDatePicker() {
_.each($('.add-pikaday'), function(el) {
if (el.getAttribute('datepicker-initialized') !== 'true') {
new Pikaday({
field: el,
format: 'YYYY-MM-DD hh:mm:ss',
defaultDate: $(el).val(),
setDefaultDate: true,
showTime: true,
use24hour: false,
autoClose: false
});
el.setAttribute('datepicker-initialized', 'true');
}
});
}
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
// ------------------------------ // ------------------------------
// #RESET // #RESET
// ------------------------------ // ------------------------------
$background-color: palette(grayscale, base) !default;
// ------------------------------ // ------------------------------
// #BASE // #BASE
// ------------------------------ // ------------------------------
...@@ -14,7 +14,7 @@ html, body { ...@@ -14,7 +14,7 @@ html, body {
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
background: palette(grayscale-cool, xx-light); background: $background-color;
} }
// ------------------------------ // ------------------------------
......
...@@ -17,3 +17,9 @@ ...@@ -17,3 +17,9 @@
// ------------------------------ // ------------------------------
@import "lib"; @import "lib";
@import '../bower_components/edx-pattern-library/pattern-library/sass/edx-pattern-library'; @import '../bower_components/edx-pattern-library/pattern-library/sass/edx-pattern-library';
// ------------------------------
// #EXTENSIONS
// ------------------------------
@import "base";
@import "publisher/course_form";
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
// ------------------------------ // ------------------------------
// #VARIABLES // #VARIABLES
// ------------------------------ // ------------------------------
$pattern-library-path: '../bower_components/edx-pattern-library' !default; $pattern-library-path: '../bower_components/edx-pattern-library/pattern-library' !default;
// ------------------------------
// // edX Course Discovery: Course form
.course-form {
margin: 20px;
}
.btn-add {
float: right;
margin-right: 30px;
}
...@@ -10,8 +10,24 @@ ...@@ -10,8 +10,24 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% endblock title %}</title> <title>{% block title %}{% endblock title %}</title>
<script type="text/javascript" language="javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="{% static 'bower_components/underscore/underscore.js' %}"></script>
<script src="{% static 'bower_components/moment/moment.js' %}"></script>
<script src="{% static 'bower_components/pikaday/pikaday.js' %}"></script>
<script src="{% static 'js/utils.js' %}"></script>
<script type="text/javascript">
$(document).ready(function () {
addDatePicker();
});
</script>
{% compress css %} {% compress css %}
<link rel="stylesheet" href="{% static 'sass/main-'|add:language_bidi|add:'.scss' %}" type="text/x-scss"> {% if language_bidi %}
<link rel="stylesheet" href="{% static 'sass/main-rtl.scss' %}" type="text/x-scss">
{% else %}
<link rel="stylesheet" href="{% static 'sass/main-ltr.scss' %}" type="text/x-scss">
{% endif %}
<link rel="stylesheet" href="{% static 'bower_components/pikaday/css/pikaday.css' %}" type="text/x-scss">
{% endcompress %} {% endcompress %}
</head> </head>
...@@ -19,5 +35,9 @@ ...@@ -19,5 +35,9 @@
{% block content %} {% block content %}
{% endblock content %} {% endblock content %}
{% block extra_js %}
{% endblock %}
</body> </body>
</html> </html>
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Course Form" %}
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="card course-form">
<h4 class="hd-4">{% trans "Course Form" %}</h4>
{% if object.id %}
<a href="{% url 'publisher:publisher_course_runs_new' %}" target="_blank" class="btn btn-neutral btn-add">
{% trans "Add Course Run" %}
</a>
{% endif %}
<form class="form" method="post" action=""> {% csrf_token %}
<fieldset class="form-group">
{% for field in form %}
{% include "publisher/form_field.html" %}
{% endfor %}
</fieldset>
<button class="btn-brand btn-base" type="submit">{% trans "Save" %}</button>
</form>
</div>
</div>
{% endblock content %}
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Course Run Form" %}
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="card course-form">
<h4 class="hd-4">{% trans "Course Run Form" %}</h4>
{% if object.id %}
<a href="{% url 'publisher:publisher_seats_new' %}" target="_blank" class="btn btn-neutral btn-add">
{% trans "Add Seat" %}
</a>
{% endif %}
<form class="form" method="post" action=""> {% csrf_token %}
<fieldset class="form-group">
{% for field in form %}
{% include "publisher/form_field.html" %}
{% endfor %}
</fieldset>
<button class="btn-brand btn-base" type="submit">{% trans "Save" %}</button>
</form>
</div>
</div>
{% endblock content %}
<div class="field field-{{ field.name }}" {% if field.name in hidden_fields %}hidden="hidden"{% endif %}>
<label class="field-label {% if field.required %}field-required{% endif %}" for="{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% for error in field.errors %}
<div class="field-message has-error">
<span class="field-message-content">
{{ error|escape }}
</span>
</div>
{% endfor %}
</div>
{% extends 'base.html' %}
{% load i18n %}
{% load staticfiles %}
{% block title %}
{% trans "Seat Form" %}
{% endblock title %}
{% block content %}
<div class="layout-full layout">
<div class="card course-form">
<h4 class="hd-4">{% trans "Seat Form" %}</h4>
<form class="form" method="post" action=""> {% csrf_token %}
<fieldset class="form-group">
{% for field in form %}
{% include "publisher/form_field.html" %}
{% endfor %}
</fieldset>
<button class="btn-brand btn-base" type="submit">{% trans "Save" %}</button>
</form>
</div>
</div>
{% endblock content %}
{% block extra_js %}
<script src="{% static 'js/seat-type-change.js' %}"></script>
{% endblock %}
...@@ -34,6 +34,7 @@ urlpatterns = auth_urlpatterns + [ ...@@ -34,6 +34,7 @@ urlpatterns = auth_urlpatterns + [
url(r'^auto_auth/$', core_views.AutoAuth.as_view(), name='auto_auth'), url(r'^auto_auth/$', core_views.AutoAuth.as_view(), name='auto_auth'),
url(r'^health/$', core_views.health, name='health'), url(r'^health/$', core_views.health, name='health'),
url('^$', QueryPreviewView.as_view()), url('^$', QueryPreviewView.as_view()),
url(r'^publisher/', include('course_discovery.apps.publisher.urls', namespace='publisher')),
] ]
if settings.DEBUG and os.environ.get('ENABLE_DJANGO_TOOLBAR', False): # pragma: no cover if settings.DEBUG and os.environ.get('ENABLE_DJANGO_TOOLBAR', False): # pragma: no cover
......
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