Commit f3ad8342 by Waheed Ahmed

Added course list page.

ECOM-6085
ECOM-6086
ECOM-6448
parent 6c794b85
......@@ -174,6 +174,13 @@ class Course(TimeStampedModel, ChangedByMixin):
return None
@property
def partner_coordinator(self):
try:
return self.course_user_roles.get(role=PublisherUserRole.PartnerCoordinator).user
except CourseUserRole.DoesNotExist:
return None
class CourseRun(TimeStampedModel, ChangedByMixin):
""" Publisher CourseRun model. It contains fields related to the course run intake form."""
......
......@@ -143,6 +143,16 @@ class CourseTests(TestCase):
self.assertIn('abc', self.course.keywords_data)
self.assertIn('def', self.course.keywords_data)
def test_partner_coordinator(self):
""" Verify that the partner_coordinator property returns user if exist. """
self.assertIsNone(self.course.partner_coordinator)
factories.CourseUserRoleFactory(
course=self.course, user=self.user1, role=PublisherUserRole.PartnerCoordinator
)
self.assertEqual(self.user1, self.course.partner_coordinator)
class SeatTests(TestCase):
""" Tests for the publisher `Seat` model. """
......
......@@ -1372,3 +1372,48 @@ class UpdateCourseKeyViewTests(TestCase):
self.assertIn(expected_body, body)
page_url = 'https://{host}{path}'.format(host=Site.objects.get_current().domain.strip('/'), path=object_path)
self.assertIn(page_url, body)
class CourseListViewTests(TestCase):
""" Tests for `CourseListView` """
def setUp(self):
super(CourseListViewTests, self).setUp()
self.course = factories.CourseFactory()
self.user = UserFactory()
self.client.login(username=self.user.username, password=USER_PASSWORD)
self.courses_url = reverse('publisher:publisher_courses')
def test_courses_with_no_courses(self):
""" Verify that user cannot see any course on course list page. """
self.assert_course_list_page(course_count=0)
def test_courses_with_admin(self):
""" Verify that admin user can see all courses on course list page. """
self.user.groups.add(Group.objects.get(name=ADMIN_GROUP_NAME))
self.assert_course_list_page(course_count=1)
def test_courses_with_course_user_role(self):
""" Verify that internal user can see course on course list page. """
self.user.groups.add(Group.objects.get(name=INTERNAL_USER_GROUP_NAME))
factories.CourseUserRoleFactory(course=self.course, user=self.user)
self.assert_course_list_page(course_count=1)
def test_courses_with_permission(self):
""" Verify that user can see course with permission on course list page. """
assign_perm(Course.VIEW_PERMISSION, self.user, self.course)
self.assert_course_list_page(course_count=1)
def assert_course_list_page(self, course_count):
""" Dry method to assert course list page content. """
response = self.client.get(self.courses_url)
self.assertContains(response, '{} Courses'.format(course_count))
self.assertContains(response, 'Add Course')
if course_count > 0:
self.assertContains(response, self.course.title)
self.assertContains(response, 'Edit')
......@@ -8,6 +8,7 @@ from course_discovery.apps.publisher import views
urlpatterns = [
url(r'^$', views.Dashboard.as_view(), name='publisher_dashboard'),
url(r'^api/', include('course_discovery.apps.publisher.api.urls', namespace='api')),
url(r'^courses/$', views.CourseListView.as_view(), name='publisher_courses'),
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'),
......
......@@ -412,3 +412,19 @@ class ToggleEmailNotification(mixins.LoginRequiredMixin, View):
class UpdateCourseKeyView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, UpdateAPIView):
queryset = CourseRun.objects.all()
serializer_class = UpdateCourseKeySerializer
class CourseListView(mixins.LoginRequiredMixin, ListView):
""" Course List View."""
template_name = 'publisher/courses.html'
def get_queryset(self):
user = self.request.user
if is_publisher_admin(user):
courses = Course.objects.all()
elif is_internal_user(user):
courses = Course.objects.filter(course_user_roles__user=user).distinct()
else:
courses = get_objects_for_user(user, Course.VIEW_PERMISSION, Course)
return courses
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-14 15:06+0500\n"
"POT-Creation-Date: 2016-12-19 14:36+0500\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: apps/api/filters.py
#, python-brace-format
......@@ -413,7 +413,7 @@ msgstr ""
msgid "JSON string containing an elasticsearch function score config."
msgstr ""
#: apps/publisher/choices.py
#: apps/publisher/choices.py templates/publisher/courses.html
msgid "Partner Coordinator"
msgstr ""
......@@ -1223,7 +1223,7 @@ msgstr ""
msgid "Dashboard"
msgstr ""
#: templates/publisher/base.html
#: templates/publisher/base.html templates/publisher/courses.html
msgid "Courses"
msgstr ""
......@@ -1594,6 +1594,7 @@ msgid "No Seats Available."
msgstr ""
#: templates/publisher/course_run_detail/_studio.html
#: templates/publisher/courses.html
#: templates/publisher/dashboard/_in_progress.html
#: templates/publisher/dashboard/_preview_ready.html
#: templates/publisher/dashboard/_published.html
......@@ -1667,6 +1668,23 @@ msgstr ""
msgid "Looks like you haven't publish a course yet"
msgstr ""
#: templates/publisher/courses.html
msgid "Add Course"
msgstr ""
#: templates/publisher/courses.html
#: templates/publisher/dashboard/_in_progress.html
msgid "Institution"
msgstr ""
#: templates/publisher/courses.html
msgid "Runs"
msgstr ""
#: templates/publisher/courses.html
msgid "Edit"
msgstr ""
#: templates/publisher/dashboard.html
msgid "Course runs"
msgstr ""
......@@ -1692,10 +1710,6 @@ msgid "There are no in progress course runs."
msgstr ""
#: templates/publisher/dashboard/_in_progress.html
msgid "Institution"
msgstr ""
#: templates/publisher/dashboard/_in_progress.html
#: templates/publisher/dashboard/_published.html
msgid "Start"
msgstr ""
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-14 15:06+0500\n"
"POT-Creation-Date: 2016-12-19 14:36+0500\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: static/js/catalogs-change-form.js
msgid "Preview"
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-14 15:06+0500\n"
"POT-Creation-Date: 2016-12-19 14:36+0500\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: apps/api/filters.py
......@@ -519,7 +519,7 @@ msgstr ""
"JSÖN strïng çöntäïnïng än élästïçséärçh fünçtïön sçöré çönfïg. Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: apps/publisher/choices.py
#: apps/publisher/choices.py templates/publisher/courses.html
msgid "Partner Coordinator"
msgstr "Pärtnér Çöördïnätör Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
......@@ -1488,7 +1488,7 @@ msgstr ""
msgid "Dashboard"
msgstr "Däshßöärd Ⱡ'σяєм ιρѕυм ∂σł#"
#: templates/publisher/base.html
#: templates/publisher/base.html templates/publisher/courses.html
msgid "Courses"
msgstr "Çöürsés Ⱡ'σяєм ιρѕυм #"
......@@ -1868,6 +1868,7 @@ msgid "No Seats Available."
msgstr "Nö Séäts Àväïläßlé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
#: templates/publisher/course_run_detail/_studio.html
#: templates/publisher/courses.html
#: templates/publisher/dashboard/_in_progress.html
#: templates/publisher/dashboard/_preview_ready.html
#: templates/publisher/dashboard/_published.html
......@@ -1948,6 +1949,23 @@ msgstr ""
"Lööks lïké ýöü hävén't püßlïsh ä çöürsé ýét Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя #"
#: templates/publisher/courses.html
msgid "Add Course"
msgstr "Àdd Çöürsé Ⱡ'σяєм ιρѕυм ∂σłσ#"
#: templates/publisher/courses.html
#: templates/publisher/dashboard/_in_progress.html
msgid "Institution"
msgstr "Ìnstïtütïön Ⱡ'σяєм ιρѕυм ∂σłσя #"
#: templates/publisher/courses.html
msgid "Runs"
msgstr "Rüns Ⱡ'σяєм ι#"
#: templates/publisher/courses.html
msgid "Edit"
msgstr "Édït Ⱡ'σяєм ι#"
#: templates/publisher/dashboard.html
msgid "Course runs"
msgstr "Çöürsé rüns Ⱡ'σяєм ιρѕυм ∂σłσя #"
......@@ -1975,10 +1993,6 @@ msgstr ""
"¢σηѕє¢тєтυ#"
#: templates/publisher/dashboard/_in_progress.html
msgid "Institution"
msgstr "Ìnstïtütïön Ⱡ'σяєм ιρѕυм ∂σłσя #"
#: templates/publisher/dashboard/_in_progress.html
#: templates/publisher/dashboard/_published.html
msgid "Start"
msgstr "Stärt Ⱡ'σяєм ιρѕ#"
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-14 15:06+0500\n"
"POT-Creation-Date: 2016-12-19 14:36+0500\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/js/catalogs-change-form.js
......
......@@ -689,3 +689,28 @@ select {
}
}
}
.btn-course-edit {
@include padding(2px, 20px, 3px, 20px);
@include float(right);
font-weight: 400;
font-size: 14px;
border-radius: 5px;
}
.btn-course-add {
@include padding(4px, 20px, 4px, 20px);
@include margin-left(12px);
border-radius: 5px;
}
.course-count-heading {
display: inline-block;
font-weight: 700;
font-size: 24px;
}
.coursesTable {
@include padding(20px, 20px, 20px, 20px);
border: 2px solid #169bd5;
}
......@@ -29,8 +29,8 @@
</a>
</li>
<li class="item">
<a class="btn {% if request.path == new_course_url %}active{% endif %}"
href="/publisher/course/">
{% url 'publisher:publisher_courses' as courses_url %}
<a class="btn {% if request.path == courses_url %}active{% endif %}" href="{{ courses_url }}">
{% trans "Courses" %}
</a>
</li>
......
{% extends 'publisher/base.html' %}
{% load i18n %}
{% block title %}
{% trans "Courses" %}
{% endblock title %}
{% block page_content %}
<h2 class="hd-2 course-count-heading">{{ object_list.count }} Courses</h2>
<a href="{% url 'publisher:publisher_courses_new' %}" class="btn btn-brand btn-small btn-course-add">
{% trans "Add Course" %}
</a>
<div class="coursesTable">
<table id="dataTableCourse" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th role="button">
{% trans "Course Name" %}
</th>
<th role="button">
{% trans "Institution" %}
</th>
<th role="button">
{% trans "Partner Coordinator" %}
</th>
<th role="button">
{% trans "Runs" %}
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for course in object_list %}
<tr>
<td>
<a href="{% url 'publisher:publisher_courses_readonly' course.id %}">{{ course.title }}</a>
</td>
<td>
{% if course.organizations.first %}{{ course.organizations.first.name }}{% endif %}
</td>
<td>
{{ course.partner_coordinator.full_name }}
</td>
<td>
{{ course.publisher_course_runs.count }}
</td>
<td>
<a href="{% url 'publisher:publisher_courses_edit' course.id %}" class="btn btn-brand btn-small btn-course-edit">
{% trans "Edit" %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block extra_js %}
<script>
$(document).ready(function() {
$('#dataTableCourse').DataTable({
"autoWidth": false,
"oLanguage": { "sEmptyTable": gettext("Looks like you haven't created any course yet") }
});
});
</script>
{% 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