open_ended_notifications.py 7.18 KB
Newer Older
Calen Pennington committed
1 2 3 4
import datetime
import json
import logging

5
from django.conf import settings
Calen Pennington committed
6

7
from xmodule.open_ended_grading_classes import peer_grading_service
8
from xmodule.open_ended_grading_classes.controller_query_service import ControllerQueryService
Calen Pennington committed
9

10
from courseware.access import has_access
David Baumgold committed
11
from edxmako.shortcuts import render_to_string
Calen Pennington committed
12 13 14 15
from student.models import unique_id_for_user
from util.cache import cache

from .staff_grading_service import StaffGradingService
16

Calen Pennington committed
17
log = logging.getLogger(__name__)
18

19 20 21
NOTIFICATION_CACHE_TIME = 300
KEY_PREFIX = "open_ended_"

22
NOTIFICATION_TYPES = (
23 24 25 26
    ('student_needs_to_peer_grade', 'peer_grading', 'Peer Grading'),
    ('staff_needs_to_grade', 'staff_grading', 'Staff Grading'),
    ('new_student_grading_to_view', 'open_ended_problems', 'Problems you have submitted'),
    ('flagged_submissions_exist', 'open_ended_flagged_problems', 'Flagged Submissions')
Vik Paruchuri committed
27
)
28

Calen Pennington committed
29

30
def staff_grading_notifications(course, user):
31
    staff_gs = StaffGradingService(settings.OPEN_ENDED_GRADING_INTERFACE)
Calen Pennington committed
32 33
    pending_grading = False
    img_path = ""
34
    course_id = course.id
35 36 37 38 39 40 41
    student_id = unique_id_for_user(user)
    notification_type = "staff"

    success, notification_dict = get_value_from_cache(student_id, course_id, notification_type)
    if success:
        return notification_dict

42
    try:
43
        notifications = json.loads(staff_gs.get_notifications(course_id))
44 45
        if notifications['success']:
            if notifications['staff_needs_to_grade']:
Calen Pennington committed
46
                pending_grading = True
47 48
    except:
        #Non catastrophic error, so no real action
49
        notifications = {}
50
        #This is a dev_facing_error
Vik Paruchuri committed
51 52 53
        log.info(
            "Problem with getting notifications from staff grading service for course {0} user {1}.".format(course_id,
                                                                                                            student_id))
54 55

    if pending_grading:
56
        img_path = "/static/images/grading_notification.png"
57

Calen Pennington committed
58
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
59 60 61 62

    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict
63

Calen Pennington committed
64

65
def peer_grading_notifications(course, user):
66
    peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, render_to_string)
Calen Pennington committed
67 68
    pending_grading = False
    img_path = ""
69
    course_id = course.id
70 71 72 73 74 75
    student_id = unique_id_for_user(user)
    notification_type = "peer"

    success, notification_dict = get_value_from_cache(student_id, course_id, notification_type)
    if success:
        return notification_dict
76

77
    try:
Calen Pennington committed
78
        notifications = json.loads(peer_gs.get_notifications(course_id, student_id))
79 80
        if notifications['success']:
            if notifications['student_needs_to_peer_grade']:
Calen Pennington committed
81
                pending_grading = True
82 83
    except:
        #Non catastrophic error, so no real action
84
        notifications = {}
85
        #This is a dev_facing_error
Vik Paruchuri committed
86 87 88
        log.info(
            "Problem with getting notifications from peer grading service for course {0} user {1}.".format(course_id,
                                                                                                           student_id))
89
    if pending_grading:
90
        img_path = "/static/images/grading_notification.png"
91

Calen Pennington committed
92
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
93 94 95 96

    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict
97

Calen Pennington committed
98

99
def combined_notifications(course, user):
Vik Paruchuri committed
100 101 102 103 104 105 106 107 108 109 110
    """
    Show notifications to a given user for a given course.  Get notifications from the cache if possible,
    or from the grading controller server if not.
    @param course: The course object for which we are getting notifications
    @param user: The user object for which we are getting notifications
    @return: A dictionary with boolean pending_grading (true if there is pending grading), img_path (for notification
    image), and response (actual response from grading controller server).
    """
    #Set up return values so that we can return them for error cases
    pending_grading = False
    img_path = ""
111
    notifications = {}
Vik Paruchuri committed
112 113 114 115 116 117 118
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}

    #We don't want to show anonymous users anything.
    if not user.is_authenticated():
        return notification_dict

    #Initialize controller query service using our mock system
119
    controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, render_to_string)
120
    student_id = unique_id_for_user(user)
121
    user_is_staff = has_access(user, 'staff', course)
122
    course_id = course.id
123 124
    notification_type = "combined"

Vik Paruchuri committed
125
    #See if we have a stored value in the cache
126 127 128
    success, notification_dict = get_value_from_cache(student_id, course_id, notification_type)
    if success:
        return notification_dict
129

Vik Paruchuri committed
130 131
    #Get the time of the last login of the user
    last_login = user.last_login
Vik Paruchuri committed
132
    last_time_viewed = last_login - datetime.timedelta(seconds=(NOTIFICATION_CACHE_TIME + 60))
133 134

    try:
Vik Paruchuri committed
135
        #Get the notifications from the grading controller
136 137 138 139 140 141
        notifications = controller_qs.check_combined_notifications(
            course.id,
            student_id,
            user_is_staff,
            last_time_viewed,
        )
142 143
        if notifications.get('success'):
            if (notifications.get('staff_needs_to_grade') or
stv committed
144
                    notifications.get('student_needs_to_peer_grade')):
Calen Pennington committed
145
                pending_grading = True
146 147
    except:
        #Non catastrophic error, so no real action
148
        #This is a dev_facing_error
Vik Paruchuri committed
149
        log.exception(
150
            u"Problem with getting notifications from controller query service for course {0} user {1}.".format(
Vik Paruchuri committed
151
                course_id, student_id))
152 153

    if pending_grading:
154
        img_path = "/static/images/grading_notification.png"
155

Calen Pennington committed
156
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
157

Vik Paruchuri committed
158
    #Store the notifications in the cache
159 160 161 162
    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict

Calen Pennington committed
163

164 165 166 167 168
def get_value_from_cache(student_id, course_id, notification_type):
    key_name = create_key_name(student_id, course_id, notification_type)
    success, value = _get_value_from_cache(key_name)
    return success, value

Calen Pennington committed
169

170 171 172 173
def set_value_in_cache(student_id, course_id, notification_type, value):
    key_name = create_key_name(student_id, course_id, notification_type)
    _set_value_in_cache(key_name, value)

Calen Pennington committed
174

175
def create_key_name(student_id, course_id, notification_type):
176 177 178 179 180 181
    key_name = u"{prefix}{type}_{course}_{student}".format(
        prefix=KEY_PREFIX,
        type=notification_type,
        course=course_id,
        student=student_id,
    )
182 183
    return key_name

Calen Pennington committed
184

185 186 187 188
def _get_value_from_cache(key_name):
    value = cache.get(key_name)
    success = False
    if value is None:
Calen Pennington committed
189
        return success, value
190 191 192 193 194
    try:
        value = json.loads(value)
        success = True
    except:
        pass
Calen Pennington committed
195 196
    return success, value

197 198

def _set_value_in_cache(key_name, value):
Calen Pennington committed
199
    cache.set(key_name, json.dumps(value), NOTIFICATION_CACHE_TIME)