From 348f2bc4f727b27abd9878334e886527479d260c Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Apr 2020 16:54:35 +0530 Subject: Merge monitor, grade user and regrade intosingle dashboard --- online_test/__init__.py | 6 + online_test/celery.py | 19 ++ online_test/settings.py | 12 + yaksh/middleware/get_notifications.py | 21 ++ yaksh/tasks.py | 83 ++++++ yaksh/templates/manage.html | 30 ++- yaksh/templates/yaksh/grade_user.html | 109 +++++++- yaksh/templates/yaksh/monitor.html | 366 +++++++++++--------------- yaksh/templates/yaksh/regrade.html | 175 ------------ yaksh/templates/yaksh/user_data.html | 5 - yaksh/templates/yaksh/view_notifications.html | 60 +++++ yaksh/urls.py | 26 +- yaksh/views.py | 119 +++++---- 13 files changed, 562 insertions(+), 469 deletions(-) create mode 100644 online_test/celery.py create mode 100644 yaksh/middleware/get_notifications.py create mode 100644 yaksh/tasks.py delete mode 100644 yaksh/templates/yaksh/regrade.html create mode 100644 yaksh/templates/yaksh/view_notifications.html diff --git a/online_test/__init__.py b/online_test/__init__.py index ef91994..07d5e33 100644 --- a/online_test/__init__.py +++ b/online_test/__init__.py @@ -1 +1,7 @@ +from __future__ import absolute_import, unicode_literals + +from .celery import app as celery_app + +__all__ = ('celery_app',) + __version__ = '0.14.0' diff --git a/online_test/celery.py b/online_test/celery.py new file mode 100644 index 0000000..582f8a1 --- /dev/null +++ b/online_test/celery.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import, unicode_literals + +import os +from django.conf import settings +from celery import Celery + +# set the default Django settings module for the 'celery' program. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_test.settings') + +app = Celery('online_test') + +# Using a string here means the worker doesn't have to serialize +# the configuration object to child processes. +# - namespace='CELERY' means all celery-related configuration keys +# should have a `CELERY_` prefix. +app.config_from_object('django.conf:settings', namespace='CELERY') + +# Load task modules from all registered Django app configs. +app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) diff --git a/online_test/settings.py b/online_test/settings.py index 7b9a231..aa373c4 100644 --- a/online_test/settings.py +++ b/online_test/settings.py @@ -45,6 +45,8 @@ INSTALLED_APPS = ( 'taggit', 'social_django', 'grades', + 'django_celery_beat', + 'notifications_plugin', ) MIDDLEWARE = ( @@ -53,6 +55,7 @@ MIDDLEWARE = ( 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'yaksh.middleware.one_session_per_user.OneSessionPerUserMiddleware', + 'yaksh.middleware.get_notifications.NotificationMiddleware', 'yaksh.middleware.user_time_zone.TimezoneMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', @@ -164,6 +167,7 @@ TEMPLATES = [ 'social_django.context_processors.backends', 'social_django.context_processors.login_redirect', 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.request', ], 'debug': True, # make this False in production } @@ -208,3 +212,11 @@ AUTH_PASSWORD_VALIDATORS = [ ] TAGGIT_CASE_INSENSITIVE = True + +# Celery parameters +CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' +CELERY_ACCEPT_CONTENT = ['json'] +CELERY_TIMEZONE = 'Asia/Kolkata' +CELERY_BROKER_URL = 'redis://localhost' diff --git a/yaksh/middleware/get_notifications.py b/yaksh/middleware/get_notifications.py new file mode 100644 index 0000000..d211ad3 --- /dev/null +++ b/yaksh/middleware/get_notifications.py @@ -0,0 +1,21 @@ +from notifications_plugin.models import Notification + +class NotificationMiddleware(object): + """ Middleware to get user's notifications """ + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + # Code to be executed for each request before + # the view (and later middleware) are called. + user = request.user + if user.is_authenticated: + notifications = Notification.objects.get_unread_receiver_notifications( + user.id + ).count() + request.custom_notifications = notifications + response = self.get_response(request) + + # Code to be executed for each request/response after + # the view is called. + return response diff --git a/yaksh/tasks.py b/yaksh/tasks.py new file mode 100644 index 0000000..c68faa9 --- /dev/null +++ b/yaksh/tasks.py @@ -0,0 +1,83 @@ +# Python Imports +from __future__ import absolute_import, unicode_literals +from textwrap import dedent + +# Django and celery imports +from celery import shared_task +from celery.utils.log import get_task_logger +from django.urls import reverse +from django.shortcuts import get_object_or_404 + +# Local imports +from .models import Course, QuestionPaper, Quiz, AnswerPaper, CourseStatus +from notifications_plugin.models import NotificationMessage, Notification + + +@shared_task +def regrade_papers(data): + question_id = data.get("question_id") + questionpaper_id = data.get("questionpaper_id") + answerpaper_id = data.get("answerpaper_id") + course_id = data.get("course_id") + user_id = data.get("user_id") + quiz_id = data.get("quiz_id") + quiz_name = data.get("quiz_name") + course_name = data.get("course_name") + + logger = get_task_logger(__name__) + + try: + if answerpaper_id is not None and question_id is None: + # Regrade specific user for all questions + answerpaper = AnswerPaper.objects.get(id=answerpaper_id) + for question in answerpaper.questions.all(): + answerpaper.regrade(question.id) + course_status = CourseStatus.objects.filter( + user=answerpaper.user, course=answerpaper.course) + if course_status.exists(): + course_status.first().set_grade() + url = reverse("yaksh:grade_user", + args=[quiz_id, answerpaper.user_id, course_id]) + + elif answerpaper_id is not None and question_id is not None: + # Regrade specific user for a specific question + answerpaper = AnswerPaper.objects.get(pk=answerpaper_id) + answerpaper.regrade(question_id) + course_status = CourseStatus.objects.filter(user=answerpaper.user, + course=answerpaper.course) + if course_status.exists(): + course_status.first().set_grade() + url = reverse("yaksh:grade_user", + args=[quiz_id, answerpaper.user_id, course_id]) + + elif questionpaper_id is not None and question_id is not None: + # Regrade all users for a specific question + answerpapers = AnswerPaper.objects.filter( + questions=question_id, + question_paper_id=questionpaper_id, course_id=course_id) + for answerpaper in answerpapers: + answerpaper.regrade(question_id) + course_status = CourseStatus.objects.filter( + user=answerpaper.user, course=answerpaper.course) + if course_status.exists(): + course_status.first().set_grade() + url = reverse("yaksh:grade_user", args=[quiz_id, course_id]) + + message = dedent(""" + Quiz re-evaluation is complete Click here to view + """.format(url) + ) + nm = NotificationMessage.objects.add_single_message( + user_id, "{0} re-evaluation status".format(quiz_name), + message, "success" + ) + except Exception as e: + nm = NotificationMessage.objects.add_single_message( + user_id, "{0} re-evaluation status".format(quiz_name), + "Unable to regrade {0}. Try again later".format(quiz_name), + "warning" + ) + logger.error(e) + notification = Notification.objects.add_single_notification( + user_id, nm.id + ) diff --git a/yaksh/templates/manage.html b/yaksh/templates/manage.html index 8e74494..1b3527d 100644 --- a/yaksh/templates/manage.html +++ b/yaksh/templates/manage.html @@ -12,13 +12,33 @@