Skip to content
This repository has been archived by the owner on Apr 21, 2022. It is now read-only.

Commit

Permalink
Analytics2.0 - duplicated meta information (#136)
Browse files Browse the repository at this point in the history
Rewrite Analytics fragment view as a regular function-based view
  • Loading branch information
noisysky authored and OlhaShyliaieva committed Jun 13, 2019
1 parent d0d5680 commit 9592a42
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 131 deletions.
2 changes: 1 addition & 1 deletion rg_instructor_analytics/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class InstructorAnalyticsDashboardTab(CourseTab):
title = ugettext_noop("Instructor analytics")
body_class = "instructor-analytics-tab"
is_dynamic = True
fragment_view_name = 'rg_instructor_analytics.views.InstructorAnalyticsFragmentView'
fragment_view_name = 'rg_instructor_analytics.views.instructor_analytics_dashboard'
view_name = 'instructor_analytics_dashboard'

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,22 @@
<%static:css group='style-course'/>
<!-- Plotly.js -->
## TODO: pin vendor libs!
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="//cdn.plot.ly/plotly-latest.min.js"></script>

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="${static.url('rg_instructor_analytics/css/instructor_analytics.css')}">

<!-- froala. -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.0/codemirror.min.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.7.3/css/froala_editor.pkgd.min.css" rel="stylesheet" type="text/css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.7.3/css/froala_style.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.0/codemirror.min.css">
<link href="//cdnjs.cloudflare.com/ajax/libs/froala-editor/2.7.3/css/froala_editor.pkgd.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/froala-editor/2.7.3/css/froala_style.min.css" rel="stylesheet" type="text/css" />
</%block>

<%include file="/courseware/course_navigation.html" args="active_page='instructor_analytics'" />


<div class="container">
<div class="instructor-dashboard-wrapper-2">

<main id="main" aria-label="Content" tabindex="-1">
<section class="instructor-dashboard-content-2" id="instructor-analytics-dashboard-content">
<ul class="instructor-nav">
Expand Down Expand Up @@ -135,3 +134,17 @@
</main>
</div>
</div>

<%block name="js_extra">
<script src="${static.url('rg_instructor_analytics/js/utils.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/tab-holder.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/enrollment-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/activity-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/problem-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/funnel-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/gradebook-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/clusters-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/suggestions-tab.js')}"></script>
<script src="${static.url('rg_instructor_analytics/js/base.js')}"></script>
</%block>
4 changes: 2 additions & 2 deletions rg_instructor_analytics/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
ProblemDetailView, ProblemHomeWorkStatisticView, ProblemQuestionView, ProblemsStatisticView, ProblemStudentDataView
)
from rg_instructor_analytics.views.suggestion import SuggestionView
from rg_instructor_analytics.views.tab_fragment import InstructorAnalyticsFragmentView
from rg_instructor_analytics.views.tab_fragment import instructor_analytics_dashboard

urlpatterns = [
# Enrollment stats tab:
Expand Down Expand Up @@ -67,5 +67,5 @@
# Suggestions tab:
url(r'^api/suggestion/$', SuggestionView.as_view(), name='suggestion'),

url(r'^', InstructorAnalyticsFragmentView.as_view(), name='instructor_analytics_dashboard'),
url(r'^$', instructor_analytics_dashboard, name='instructor_analytics_dashboard'),
]
208 changes: 87 additions & 121 deletions rg_instructor_analytics/views/tab_fragment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,146 +5,112 @@
import sys
from time import mktime

from django.http import Http404, HttpResponseBadRequest
from django.http import Http404
from django.shortcuts import render_to_response
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from opaque_keys import InvalidKeyError
from django.views.decorators.cache import cache_control
from django.views.decorators.csrf import ensure_csrf_cookie
from instructor.views.api import require_level
from opaque_keys.edx.keys import CourseKey
from rg_instructor_analytics_log_collector.models import EnrollmentByDay
from web_fragments.fragment import Fragment
from util.views import ensure_valid_course_key

from courseware.courses import get_course_by_id
from edxmako.shortcuts import render_to_string
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from rg_instructor_analytics.utils import resource_string
from rg_instructor_analytics.utils.decorators import instructor_access_required
from student.models import CourseAccessRole

try:
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
except ImportError:
# edx-ficus
from web_fragments.views import FragmentView as EdxFragmentView

# NOTE(flying-pi) reload(sys) is used for restore method `setdefaultencoding`,
# which set flag PYTHONIOENCODING to utf8.
reload(sys)
sys.setdefaultencoding('utf8')


class InstructorAnalyticsFragmentView(EdxFragmentView):
def get_enroll_info(course):
"""
Fragment for render tab.
Return enroll_start for given course.
"""
enrollment_by_day = EnrollmentByDay.objects.filter(course=course.id).order_by('day').first()
enroll_start = enrollment_by_day and enrollment_by_day.day

@method_decorator(instructor_access_required)
def dispatch(self, *args, **kwargs):
"""
See: https://docs.djangoproject.com/en/1.8/topics/class-based-views/intro/#id2.
"""
return super(InstructorAnalyticsFragmentView, self).dispatch(*args, **kwargs)

def render_to_fragment(self, request, *args, **kwargs):
"""
Render tab fragment.
"""
try:
course_key = CourseKey.from_string(kwargs.get('course_id'))
course = get_course_by_id(course_key)
except InvalidKeyError:
return HttpResponseBadRequest(_("Invalid course ID."))

available_courses = [
{
'course_id': str(user_course.id),
'course_name': str(user_course.display_name),
'is_current': course == user_course,
}
for user_course in self.get_available_courses(request.user)
]

enroll_info = {
str(course_item.id): self.get_enroll_info(course_item)
for course_item in self.get_available_courses(request.user)
}
return {
'enroll_start': mktime(enroll_start.timetuple()) if enroll_start else 'null',
}

course_dates_info = {
str(course_item.id): self.get_course_dates_info(course_item)
for course_item in self.get_available_courses(request.user)
}

context = {
'course': course,
'enroll_info': json.dumps(enroll_info),
'available_courses': available_courses,
'course_dates_info': json.dumps(course_dates_info),
}
def get_available_courses(user):
"""
Return courses, available for the given user.
"""
result = []
# For staff user we need return all available courses on platform.
if user.is_staff:
available_courses = CourseOverview.objects.all()
for course in available_courses:
try:
result.append(get_course_by_id(course.id, depth=0))
except Http404:
continue
# Return courses, where user has permission as instructor of staff
else:
available_courses = CourseAccessRole.objects.filter(user=user, role__in=['instructor', 'staff'])
exist_courses_id = []
for record in available_courses:
try:
course = get_course_by_id(record.course_id, depth=0)
course_id = str(course.id)
if course_id not in exist_courses_id:
result.append(course)
exist_courses_id.append(course_id)
except Http404:
continue
return result


def get_course_dates_info(course):
"""
Return course_start and course_is_started for given course.
"""
return {
'course_start': mktime(course.start.timetuple()) if course.start else 'null',
'course_is_started': False if course.start and course.start > timezone.now() else True
}

html = render_to_string('rg_instructor_analytics/instructor_analytics_fragment.html', context)
fragment = Fragment(html)
fragment.add_css(resource_string("css/instructor_analytics.css"))

fragment.add_javascript(resource_string("js/utils.js"))
fragment.add_javascript(resource_string("js/tab.js"))
fragment.add_javascript(resource_string("js/tab-holder.js"))
fragment.add_javascript(resource_string("js/enrollment-tab.js"))
fragment.add_javascript(resource_string("js/activity-tab.js"))
fragment.add_javascript(resource_string("js/problem-tab.js"))
fragment.add_javascript(resource_string("js/funnel-tab.js"))
fragment.add_javascript(resource_string("js/gradebook-tab.js"))
fragment.add_javascript(resource_string("js/clusters-tab.js"))
fragment.add_javascript(resource_string("js/suggestions-tab.js"))
fragment.add_javascript(resource_string("js/base.js"))

return fragment

@staticmethod
def get_enroll_info(course):
"""
Return enroll_start and enroll_end for given course.
"""
enrollment_by_day = EnrollmentByDay.objects.filter(course=course.id).order_by('day').first()
enroll_start = enrollment_by_day and enrollment_by_day.day
return {
'enroll_start': mktime(enroll_start.timetuple()) if enroll_start else 'null',
}

@staticmethod
def get_available_courses(user):
"""
Return courses, available for the given user.
"""
result = []
# For staff user we need return all available courses on platform.
if user.is_staff:
available_courses = CourseOverview.objects.all()
for course in available_courses:
try:
result.append(get_course_by_id(course.id, depth=0))
except Http404:
continue
# Return courses, where user has permission as instructor of staff
else:
available_courses = CourseAccessRole.objects.filter(user=user, role__in=['instructor', 'staff'])
exist_courses_id = []
for record in available_courses:
try:
course = get_course_by_id(record.course_id, depth=0)
course_id = str(course.id)
if course_id not in exist_courses_id:
result.append(course)
exist_courses_id.append(course_id)
except Http404:
continue
return result

@staticmethod
def get_course_dates_info(course):
"""
Return course_start and course_is_started for given course.
"""
return {
'course_start': mktime(course.start.timetuple()) if course.start else 'null',
'course_is_started': False if course.start and course.start > timezone.now() else True
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@ensure_valid_course_key
@require_level('staff')
def instructor_analytics_dashboard(request, course_id):
"""
Display the instructor dashboard for a course.
"""
course_key = CourseKey.from_string(course_id)
course = get_course_by_id(course_key, depth=0)

enroll_info = {
str(course_item.id): get_enroll_info(course_item)
for course_item in get_available_courses(request.user)
}

available_courses = [
{
'course_id': str(user_course.id),
'course_name': str(user_course.display_name),
'is_current': course == user_course,
}
for user_course in get_available_courses(request.user)
]

course_dates_info = {
str(course_item.id): get_course_dates_info(course_item)
for course_item in get_available_courses(request.user)
}

context = {
'course': course,
'enroll_info': json.dumps(enroll_info),
'available_courses': available_courses,
'course_dates_info': json.dumps(course_dates_info),
}

return render_to_response('rg_instructor_analytics/instructor_analytics_fragment.html', context)

0 comments on commit 9592a42

Please sign in to comment.