diff --git a/completion_aggregator/templates/chapter_completion_progress_bar.html b/completion_aggregator/templates/chapter_completion_progress_bar.html new file mode 100644 index 00000000..748c50ac --- /dev/null +++ b/completion_aggregator/templates/chapter_completion_progress_bar.html @@ -0,0 +1,13 @@ +{% load i18n %} +
+ + 0% +
+
+ {{completion_percentage}}% +
+
+ 100% +
diff --git a/completion_aggregator/templates/completion_progress_bar.html b/completion_aggregator/templates/completion_progress_bar.html new file mode 100644 index 00000000..300ec883 --- /dev/null +++ b/completion_aggregator/templates/completion_progress_bar.html @@ -0,0 +1,15 @@ +{% load i18n %} + +
+ + 0% +
+
+ {{completion_percentage}}% +
+
+ 100% +
+ diff --git a/completion_aggregator/urls.py b/completion_aggregator/urls.py index d36755cc..63a5923b 100644 --- a/completion_aggregator/urls.py +++ b/completion_aggregator/urls.py @@ -5,10 +5,11 @@ from __future__ import absolute_import, division, print_function, unicode_literals from django.conf.urls import include, url -from django.views.generic import TemplateView +from . import views urlpatterns = [ url(r'^v1/', include('completion_aggregator.api.v1.urls', namespace='completion_api_v1')), url(r'^v0/', include('completion_aggregator.api.v0.urls', namespace='completion_api_v0')), - url(r'^$', TemplateView.as_view(template_name="completion_aggregator/base.html")), + url(r'^progress_bar/(?P[\w.@+:-]+)/$', views.CompletionProgressBarView.as_view(), name="completion-progress-bar"), + url(r'^progress_bar/(?P[\w.@+:-]+)/(?P.+)/$', views.CompletionProgressBarView.as_view(), name="completion-progress-bar"), ] diff --git a/completion_aggregator/views.py b/completion_aggregator/views.py new file mode 100644 index 00000000..0f8b2afe --- /dev/null +++ b/completion_aggregator/views.py @@ -0,0 +1,71 @@ +""" +completion_aggregator App progress bar view +""" +from __future__ import absolute_import, unicode_literals + +from django.conf import settings +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.generic import TemplateView +from xblockutils.resources import ResourceLoader + +from .api.v1.views import CompletionDetailView + +loader = ResourceLoader(__name__) + + +class CompletionProgressBarView(LoginRequiredMixin, TemplateView): + """ + View to display the progress bar of a student in a course + """ + @xframe_options_exempt + def get(self, request, course_key, chapter_id=None): + """ + Fetch progress and render the template. + """ + completion_percentage = 0 + new_req = request.GET.copy() + new_req['username'] = request.user.username + if chapter_id is not None: + new_req['requested_fields'] = "chapter" + request.GET = new_req + completion_resp = CompletionDetailView.as_view()(request, course_key).data + if completion_resp: + results = completion_resp.get('results') + user_completion_percentage = self._get_user_completion(chapter_id, results) + + if user_completion_percentage: + completion_percentage = user_completion_percentage + + template = 'chapter_completion_progress_bar.html' if chapter_id is not None else 'completion_progress_bar.html' + return render(request, template, { + 'completion_percentage': completion_percentage, + }) + + def _get_user_completion(self, chapter_id, results): + """ + Return the user completion percentage, using the completion response. + In case the user completion cannot be returned as a result of missing user completion, we return None, + indicating its absence. + """ + if not results: + return None + + user_completion = next(filter(lambda r: r, results), None) + + # No completion returned, hence we cannot get the percentage either + # Indicate no user completion by returning None + if not user_completion: + return None + + if chapter_id: + chapters = user_completion['chapter'] + chapter = next(filter(lambda c: c['block_key'].split('@')[-1] == chapter_id, chapters), None) + + completion_kind = chapter if chapter_id else user_completion + + if not completion_kind: + return None + + return round(float(completion_kind['completion']['percent']) * 100)