Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
course-discovery
Commits
543d8db4
Commit
543d8db4
authored
Jul 25, 2016
by
Bill DeRusha
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add course listing page
parent
0f66ff0d
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
164 additions
and
10 deletions
+164
-10
course_discovery/apps/publisher/migrations/0003_auto_20160801_1757.py
+30
-0
course_discovery/apps/publisher/models.py
+3
-3
course_discovery/apps/publisher/tests/test_wrapper.py
+51
-0
course_discovery/apps/publisher/urls.py
+1
-0
course_discovery/apps/publisher/views.py
+20
-7
course_discovery/apps/publisher/wrappers.py
+26
-0
course_discovery/templates/publisher/course_runs_list.html
+33
-0
No files found.
course_discovery/apps/publisher/migrations/0003_auto_20160801_1757.py
0 → 100644
View file @
543d8db4
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
sortedm2m.fields
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'publisher'
,
'0002_auto_20160729_1027'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'course'
,
name
=
'organizations'
,
field
=
models
.
ManyToManyField
(
blank
=
True
,
related_name
=
'publisher_courses'
,
to
=
'course_metadata.Organization'
,
verbose_name
=
'Partner Name'
),
),
migrations
.
AlterField
(
model_name
=
'courserun'
,
name
=
'course'
,
field
=
models
.
ForeignKey
(
related_name
=
'publisher_course_runs'
,
to
=
'publisher.Course'
),
),
migrations
.
AlterField
(
model_name
=
'courserun'
,
name
=
'staff'
,
field
=
sortedm2m
.
fields
.
SortedManyToManyField
(
blank
=
True
,
related_name
=
'publisher_course_runs_staffed'
,
help_text
=
None
,
to
=
'course_metadata.Person'
),
),
]
course_discovery/apps/publisher/models.py
View file @
543d8db4
...
@@ -28,7 +28,7 @@ class Course(TimeStampedModel, ChangedByMixin):
...
@@ -28,7 +28,7 @@ class Course(TimeStampedModel, ChangedByMixin):
)
)
full_description
=
models
.
TextField
(
default
=
None
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'About this course'
))
full_description
=
models
.
TextField
(
default
=
None
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'About this course'
))
organizations
=
models
.
ManyToManyField
(
organizations
=
models
.
ManyToManyField
(
Organization
,
null
=
True
,
blank
=
True
,
related_name
=
'publisher_courses'
,
verbose_name
=
_
(
'Partner Name'
)
Organization
,
blank
=
True
,
related_name
=
'publisher_courses'
,
verbose_name
=
_
(
'Partner Name'
)
)
)
level_type
=
models
.
ForeignKey
(
level_type
=
models
.
ForeignKey
(
LevelType
,
default
=
None
,
null
=
True
,
blank
=
True
,
related_name
=
'publisher_courses'
,
verbose_name
=
_
(
'Course level'
)
LevelType
,
default
=
None
,
null
=
True
,
blank
=
True
,
related_name
=
'publisher_courses'
,
verbose_name
=
_
(
'Course level'
)
...
@@ -70,7 +70,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
...
@@ -70,7 +70,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
(
PRIORITY_LEVEL_5
,
_
(
'Level 5'
)),
(
PRIORITY_LEVEL_5
,
_
(
'Level 5'
)),
)
)
course
=
models
.
ForeignKey
(
Course
)
course
=
models
.
ForeignKey
(
Course
,
related_name
=
'publisher_course_runs'
)
lms_course_id
=
models
.
CharField
(
max_length
=
255
,
unique
=
True
,
null
=
True
,
blank
=
True
)
lms_course_id
=
models
.
CharField
(
max_length
=
255
,
unique
=
True
,
null
=
True
,
blank
=
True
)
start
=
models
.
DateTimeField
(
null
=
True
,
blank
=
True
)
start
=
models
.
DateTimeField
(
null
=
True
,
blank
=
True
)
...
@@ -81,7 +81,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
...
@@ -81,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
,
null
=
True
,
blank
=
True
,
related_name
=
'publisher_course_runs_staffed'
)
staff
=
SortedManyToManyField
(
Person
,
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.'
))
...
...
course_discovery/apps/publisher/tests/test_wrapper.py
0 → 100644
View file @
543d8db4
# pylint: disable=no-member
from
django.test
import
TestCase
from
unittest
import
mock
from
course_discovery.apps.course_metadata.tests.factories
import
CourseRunFactory
,
OrganizationFactory
from
course_discovery.apps.course_metadata.models
import
CourseOrganization
from
course_discovery.apps.publisher.wrappers
import
CourseRunWrapper
class
CourseRunWrapperTests
(
TestCase
):
""" Tests for the publisher `BaseWrapper` model. """
def
setUp
(
self
):
super
(
CourseRunWrapperTests
,
self
)
.
setUp
()
self
.
course_run
=
CourseRunFactory
()
course
=
self
.
course_run
.
course
organization_1
=
OrganizationFactory
()
organization_2
=
OrganizationFactory
()
CourseOrganization
.
objects
.
create
(
course
=
course
,
organization
=
organization_1
,
relation_type
=
CourseOrganization
.
OWNER
)
CourseOrganization
.
objects
.
create
(
course
=
course
,
organization
=
organization_2
,
relation_type
=
CourseOrganization
.
OWNER
)
course
.
save
()
self
.
wrapped_course_run
=
CourseRunWrapper
(
self
.
course_run
)
def
test_title
(
self
):
""" Verify that the wrapper can override course_run title. """
self
.
assertEqual
(
self
.
wrapped_course_run
.
title
,
self
.
course_run
.
course
.
title
)
def
test_partner
(
self
):
""" Verify that the wrapper can return partner values. """
partner
=
"/"
.
join
([
org
.
key
for
org
in
self
.
course_run
.
course
.
organizations
.
all
()])
self
.
assertEqual
(
self
.
wrapped_course_run
.
partner
,
partner
)
def
test_model_attr
(
self
):
""" Verify that the wrapper passes through object values not defined on wrapper. """
self
.
assertEqual
(
self
.
wrapped_course_run
.
key
,
self
.
course_run
.
key
)
def
test_callable
(
self
):
mock_callable
=
mock
.
Mock
(
return_value
=
'callable_value'
)
mock_obj
=
mock
.
MagicMock
(
callable_attr
=
mock_callable
)
wrapper
=
CourseRunWrapper
(
mock_obj
)
self
.
assertEqual
(
wrapper
.
callable_attr
(),
'callable_value'
)
course_discovery/apps/publisher/urls.py
View file @
543d8db4
...
@@ -8,6 +8,7 @@ from course_discovery.apps.publisher import views
...
@@ -8,6 +8,7 @@ from course_discovery.apps.publisher import views
urlpatterns
=
[
urlpatterns
=
[
url
(
r'^courses/new$'
,
views
.
CreateCourseView
.
as_view
(),
name
=
'publisher_courses_new'
),
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'^courses/(?P<pk>\d+)/edit/$'
,
views
.
UpdateCourseView
.
as_view
(),
name
=
'publisher_courses_edit'
),
url
(
r'^course_runs/$'
,
views
.
CourseRunListView
.
as_view
(),
name
=
'publisher_course_runs'
),
url
(
r'^course_runs/new$'
,
views
.
CreateCourseRunView
.
as_view
(),
name
=
'publisher_course_runs_new'
),
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<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/new$'
,
views
.
CreateSeatView
.
as_view
(),
name
=
'publisher_seats_new'
),
...
...
course_discovery/apps/publisher/views.py
View file @
543d8db4
...
@@ -3,15 +3,28 @@ Course publisher views.
...
@@ -3,15 +3,28 @@ Course publisher views.
"""
"""
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.http
import
HttpResponseRedirect
from
django.http
import
HttpResponseRedirect
from
django.views.generic
import
edit
from
django.views.generic.edit
import
CreateView
,
UpdateView
from
django.views.generic.list
import
ListView
from
course_discovery.apps.publisher.forms
import
CourseForm
,
CourseRunForm
,
SeatForm
from
course_discovery.apps.publisher.forms
import
CourseForm
,
CourseRunForm
,
SeatForm
from
course_discovery.apps.publisher.models
import
Course
,
CourseRun
,
Seat
from
course_discovery.apps.publisher.models
import
Course
,
CourseRun
,
Seat
from
course_discovery.apps.publisher.wrappers
import
CourseRunWrapper
class
CourseRunListView
(
ListView
):
""" Create Course View."""
template_name
=
'publisher/course_runs_list.html'
def
get_queryset
(
self
):
return
[
CourseRunWrapper
(
course_run
)
for
course_run
in
CourseRun
.
objects
.
select_related
(
'course'
)
.
all
()
]
SEATS_HIDDEN_FIELDS
=
[
'price'
,
'currency'
,
'upgrade_deadline'
,
'credit_provider'
,
'credit_hours'
]
SEATS_HIDDEN_FIELDS
=
[
'price'
,
'currency'
,
'upgrade_deadline'
,
'credit_provider'
,
'credit_hours'
]
# pylint: disable=attribute-defined-outside-init
# pylint: disable=attribute-defined-outside-init
class
CreateCourseView
(
edit
.
CreateView
):
class
CreateCourseView
(
CreateView
):
""" Create Course View."""
""" Create Course View."""
model
=
Course
model
=
Course
form_class
=
CourseForm
form_class
=
CourseForm
...
@@ -26,7 +39,7 @@ class CreateCourseView(edit.CreateView):
...
@@ -26,7 +39,7 @@ class CreateCourseView(edit.CreateView):
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
class
UpdateCourseView
(
edit
.
UpdateView
):
class
UpdateCourseView
(
UpdateView
):
""" Update Course View."""
""" Update Course View."""
model
=
Course
model
=
Course
form_class
=
CourseForm
form_class
=
CourseForm
...
@@ -41,7 +54,7 @@ class UpdateCourseView(edit.UpdateView):
...
@@ -41,7 +54,7 @@ class UpdateCourseView(edit.UpdateView):
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
class
CreateCourseRunView
(
edit
.
CreateView
):
class
CreateCourseRunView
(
CreateView
):
""" Create Course Run View."""
""" Create Course Run View."""
model
=
CourseRun
model
=
CourseRun
form_class
=
CourseRunForm
form_class
=
CourseRunForm
...
@@ -56,7 +69,7 @@ class CreateCourseRunView(edit.CreateView):
...
@@ -56,7 +69,7 @@ class CreateCourseRunView(edit.CreateView):
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
class
UpdateCourseRunView
(
edit
.
UpdateView
):
class
UpdateCourseRunView
(
UpdateView
):
""" Update Course Run View."""
""" Update Course Run View."""
model
=
CourseRun
model
=
CourseRun
form_class
=
CourseRunForm
form_class
=
CourseRunForm
...
@@ -71,7 +84,7 @@ class UpdateCourseRunView(edit.UpdateView):
...
@@ -71,7 +84,7 @@ class UpdateCourseRunView(edit.UpdateView):
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
class
CreateSeatView
(
edit
.
CreateView
):
class
CreateSeatView
(
CreateView
):
""" Create Seat View."""
""" Create Seat View."""
model
=
Seat
model
=
Seat
form_class
=
SeatForm
form_class
=
SeatForm
...
@@ -91,7 +104,7 @@ class CreateSeatView(edit.CreateView):
...
@@ -91,7 +104,7 @@ class CreateSeatView(edit.CreateView):
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
return
reverse
(
self
.
success_url
,
kwargs
=
{
'pk'
:
self
.
object
.
id
})
class
UpdateSeatView
(
edit
.
UpdateView
):
class
UpdateSeatView
(
UpdateView
):
""" Update Seat View."""
""" Update Seat View."""
model
=
Seat
model
=
Seat
form_class
=
SeatForm
form_class
=
SeatForm
...
...
course_discovery/apps/publisher/wrappers.py
0 → 100644
View file @
543d8db4
"""Publisher Wrapper Classes"""
class
BaseWrapper
(
object
):
def
__init__
(
self
,
wrapped_obj
):
self
.
wrapped_obj
=
wrapped_obj
def
__getattr__
(
self
,
attr
):
orig_attr
=
self
.
wrapped_obj
.
__getattribute__
(
attr
)
if
callable
(
orig_attr
):
def
hooked
(
*
args
,
**
kwargs
):
return
orig_attr
(
*
args
,
**
kwargs
)
return
hooked
else
:
return
orig_attr
class
CourseRunWrapper
(
BaseWrapper
):
"""Decorator for the ``CourseRun`` model."""
@property
def
title
(
self
):
return
self
.
wrapped_obj
.
course
.
title
@property
def
partner
(
self
):
return
'/'
.
join
([
org
.
key
for
org
in
self
.
wrapped_obj
.
course
.
organizations
.
all
()])
course_discovery/templates/publisher/course_runs_list.html
0 → 100644
View file @
543d8db4
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Course Run List" %}
{% endblock title %}
{% block content %}
<div
class=
"layout-full layout"
>
<div
class=
"card"
>
<h4
class=
"hd-4"
>
{% trans "Course Run List" %}
</h4>
<table
class=
"table"
>
<tr>
<th>
{% trans "Course Title" %}
</th>
<th>
{% trans "Partner" %}
</th>
<th>
{% trans "Target Content?" %}
</th>
<th>
{% trans "Priority" %}
</th>
<th>
{% trans "Last Updated" %}
</th>
</tr>
{% for course_run in object_list %}
<tr>
<td>
{{ course_run.title }}
</td>
<td>
{{ course_run.partner }}
</td>
<td>
{{ course_run.target_content }}
</td>
<td>
{{ course_run.priority }}
</td>
<td>
{{ course_run.modified }}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment