open_ended_notifications.py 8.38 KB
Newer Older
1
from django.conf import settings
2
from xmodule.open_ended_grading_classes import peer_grading_service
3
from .staff_grading_service import StaffGradingService
4
from xmodule.open_ended_grading_classes.controller_query_service import ControllerQueryService
5 6 7
import json
from student.models import unique_id_for_user
from courseware.models import StudentModule
8 9
import logging
from courseware.access import has_access
10
from util.cache import cache
11
import datetime
12 13
from xmodule.x_module import ModuleSystem
from mitxmako.shortcuts import render_to_string
14
import datetime
15

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

18 19 20
NOTIFICATION_CACHE_TIME = 300
KEY_PREFIX = "open_ended_"

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

Calen Pennington committed
28

29
def staff_grading_notifications(course, user):
30
    staff_gs = StaffGradingService(settings.OPEN_ENDED_GRADING_INTERFACE)
Calen Pennington committed
31 32
    pending_grading = False
    img_path = ""
33
    course_id = course.id
34 35 36 37 38 39 40
    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

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

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

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

    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict
62

Calen Pennington committed
63

64
def peer_grading_notifications(course, user):
65 66 67 68 69 70 71 72
    system = ModuleSystem(
        ajax_url=None,
        track_function=None,
        get_module = None,
        render_template=render_to_string,
        replace_urls=None,
        xblock_model_data= {}
    )
73
    peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
Calen Pennington committed
74 75
    pending_grading = False
    img_path = ""
76
    course_id = course.id
77 78 79 80 81 82
    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
83

84
    try:
Calen Pennington committed
85
        notifications = json.loads(peer_gs.get_notifications(course_id, student_id))
86 87
        if notifications['success']:
            if notifications['student_needs_to_peer_grade']:
Calen Pennington committed
88
                pending_grading = True
89 90
    except:
        #Non catastrophic error, so no real action
91
        notifications = {}
92
        #This is a dev_facing_error
Vik Paruchuri committed
93 94 95
        log.info(
            "Problem with getting notifications from peer grading service for course {0} user {1}.".format(course_id,
                                                                                                           student_id))
96 97

    if pending_grading:
98
        img_path = "/static/images/grading_notification.png"
99

Calen Pennington committed
100
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
101 102 103 104

    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict
105

Calen Pennington committed
106

107
def combined_notifications(course, user):
Vik Paruchuri committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    """
    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 = ""
    notifications={}
    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

    #Define a mock modulesystem
127 128 129 130 131 132 133 134
    system = ModuleSystem(
        ajax_url=None,
        track_function=None,
        get_module = None,
        render_template=render_to_string,
        replace_urls=None,
        xblock_model_data= {}
    )
Vik Paruchuri committed
135
    #Initialize controller query service using our mock system
136
    controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
137
    student_id = unique_id_for_user(user)
138 139
    user_is_staff = has_access(user, course, 'staff')
    course_id = course.id
140 141
    notification_type = "combined"

Vik Paruchuri committed
142
    #See if we have a stored value in the cache
143 144 145
    success, notification_dict = get_value_from_cache(student_id, course_id, notification_type)
    if success:
        return notification_dict
146

Vik Paruchuri committed
147 148 149 150
    #Get the time of the last login of the user
    last_login = user.last_login

    #Find the modules they have seen since they logged in
Vik Paruchuri committed
151
    last_module_seen = StudentModule.objects.filter(student=user, course_id=course_id,
152
                                                    modified__gt=last_login).values('modified').order_by(
Vik Paruchuri committed
153
        '-modified')
Vik Paruchuri committed
154 155
    last_module_seen_count = last_module_seen.count()

Calen Pennington committed
156
    if last_module_seen_count > 0:
Vik Paruchuri committed
157
        #The last time they viewed an updated notification (last module seen minus how long notifications are cached)
158
        last_time_viewed = last_module_seen[0]['modified'] - datetime.timedelta(seconds=(NOTIFICATION_CACHE_TIME + 60))
Vik Paruchuri committed
159
    else:
Vik Paruchuri committed
160 161
        #If they have not seen any modules since they logged in, then don't refresh
        return {'pending_grading': False, 'img_path': img_path, 'response': notifications}
162 163

    try:
Vik Paruchuri committed
164
        #Get the notifications from the grading controller
Vik Paruchuri committed
165 166
        controller_response = controller_qs.check_combined_notifications(course.id, student_id, user_is_staff,
                                                                         last_time_viewed)
167
        notifications = json.loads(controller_response)
168 169
        if notifications['success']:
            if notifications['overall_need_to_check']:
Calen Pennington committed
170
                pending_grading = True
171 172
    except:
        #Non catastrophic error, so no real action
173
        #This is a dev_facing_error
Vik Paruchuri committed
174 175 176
        log.exception(
            "Problem with getting notifications from controller query service for course {0} user {1}.".format(
                course_id, student_id))
177 178

    if pending_grading:
179
        img_path = "/static/images/grading_notification.png"
180

Calen Pennington committed
181
    notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
182

Vik Paruchuri committed
183
    #Store the notifications in the cache
184 185 186 187
    set_value_in_cache(student_id, course_id, notification_type, notification_dict)

    return notification_dict

Calen Pennington committed
188

189 190 191 192 193
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
194

195 196 197 198
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
199

200
def create_key_name(student_id, course_id, notification_type):
Vik Paruchuri committed
201 202
    key_name = "{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id,
                                                          student=student_id)
203 204
    return key_name

Calen Pennington committed
205

206 207 208 209
def _get_value_from_cache(key_name):
    value = cache.get(key_name)
    success = False
    if value is None:
Calen Pennington committed
210
        return success, value
211 212 213 214 215
    try:
        value = json.loads(value)
        success = True
    except:
        pass
Calen Pennington committed
216 217
    return success, value

218 219

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