Commit 17a0444a by Chris Dodge

tie into the xblock publish API point for progress and grading events

parent 4a9cc1e3
......@@ -211,7 +211,7 @@ def _has_access_course_desc(user, action, course):
'enroll': can_enroll,
'see_exists': see_exists,
'staff': lambda: _has_staff_access_to_descriptor(user, course, course.id),
'instructor': lambda: _has_instructor_access_to_descriptor(user, course, course.id),
'instructor': lambda: _has_instructor_access_to_descriptor(user, course, course.id)
}
return _dispatch(checkers, action, user, course)
......@@ -258,7 +258,6 @@ def _has_access_descriptor(user, action, descriptor, course_key=None):
if descriptor.visible_to_staff_only and not _has_staff_access_to_descriptor(user, descriptor, course_key):
return False
# If start dates are off, can always load
if settings.FEATURES['DISABLE_START_DATES'] and not is_masquerading_as_student(user):
debug("Allow: DISABLE_START_DATES")
return True
......@@ -285,7 +284,7 @@ def _has_access_descriptor(user, action, descriptor, course_key=None):
checkers = {
'load': can_load,
'staff': lambda: _has_staff_access_to_descriptor(user, descriptor, course_key),
'instructor': lambda: _has_instructor_access_to_descriptor(user, descriptor, course_key)
'instructor': lambda: _has_instructor_access_to_descriptor(user, descriptor, course_key),
}
return _dispatch(checkers, action, user, descriptor)
......
......@@ -7,6 +7,9 @@ import mimetypes
import static_replace
import xblock.reference.plugins
from datetime import datetime
from django.utils.timezone import UTC
from collections import OrderedDict
from functools import partial
from requests.auth import HTTPBasicAuth
......@@ -348,6 +351,16 @@ def get_module_system_for_user(user, field_data_cache,
)
def handle_grade_event(block, event_type, event):
# check permissions, unfortunately this has to be done on the course descriptor
# since problems don't have 'end' dates
if not settings.FEATURES.get("ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE", True):
# if a course has ended, don't register grading events
course = modulestore().get_course(course_id, depth=0)
now = datetime.now(UTC())
if course.end is not None and now > course.end:
return
user_id = event.get('user_id', user.id)
# Construct the key for the module
......@@ -388,6 +401,14 @@ def get_module_system_for_user(user, field_data_cache,
"""
tie into the CourseCompletions datamodels that are exposed in the api_manager djangoapp
"""
if not settings.FEATURES.get("ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE", True):
# if a course has ended, don't register progress events
course = modulestore().get_course(course_id, depth=0)
now = datetime.now(UTC())
if course.end is not None and now > course.end:
return
user_id = event.get('user_id', user.id)
if not user_id:
return
......
......@@ -3,9 +3,13 @@
Run these tests @ Devstack:
paver test_system -s lms --test_id=lms/djangoapps/gradebook/tests.py
"""
from mock import MagicMock
from mock import MagicMock, patch
import uuid
from datetime import datetime
from django.utils.timezone import UTC
from django.conf import settings
from django.test import TestCase
from django.test.utils import override_settings
......@@ -13,7 +17,8 @@ from capa.tests.response_xml_factory import StringResponseXMLFactory
from courseware import module_render
from courseware.model_data import FieldDataCache
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
from student.tests.factories import UserFactory
from student.tests.factories import UserFactory, AdminFactory
from courseware.tests.factories import StaffFactory
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from gradebook.models import StudentGradebook, StudentGradebookHistory
......@@ -44,7 +49,11 @@ class GradebookTests(TestCase):
self.user = UserFactory()
self.score = 0.75
self.course = CourseFactory.create()
def _create_course(self, start=None, end=None):
self.course = CourseFactory.create(
start=start,
end=end
)
self.course.always_recalculate_grades = True
test_data = '<html>{}</html>'.format(str(uuid.uuid4()))
chapter1 = ItemFactory.create(
......@@ -116,6 +125,7 @@ class GradebookTests(TestCase):
)
def test_receiver_on_score_changed(self):
self._create_course()
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
......@@ -141,3 +151,101 @@ class GradebookTests(TestCase):
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 5)
@patch.dict(settings.FEATURES, {'ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE': False})
def test_open_course(self):
self._create_course(start=datetime(2010,1,1, tzinfo=UTC()), end=datetime(3000, 1, 1, tzinfo=UTC()))
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
module = self.get_module_for_user(self.user, self.course, self.problem2)
grade_dict = {'value': 0.95, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
gradebook = StudentGradebook.objects.all()
self.assertEqual(len(gradebook), 1)
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 2)
@patch.dict(settings.FEATURES, {'ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE': False})
def test_not_yet_started_course(self):
self._create_course(start=datetime(3000,1,1, tzinfo=UTC()), end=datetime(3000, 1, 1, tzinfo=UTC()))
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
module = self.get_module_for_user(self.user, self.course, self.problem2)
grade_dict = {'value': 0.95, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
gradebook = StudentGradebook.objects.all()
self.assertEqual(len(gradebook), 1)
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 2)
@patch.dict(settings.FEATURES, {'ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE': False})
def test_closed_course_student(self):
self._create_course(start=datetime(2010,1,1, tzinfo=UTC()), end=datetime(2011, 1, 1, tzinfo=UTC()))
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
module = self.get_module_for_user(self.user, self.course, self.problem2)
grade_dict = {'value': 0.95, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
gradebook = StudentGradebook.objects.all()
self.assertEqual(len(gradebook), 0)
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 0)
@patch.dict(settings.FEATURES, {'ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE': False})
def test_closed_course_admin(self):
"""
Users marked as Admin should be able to submit grade events to a closed course
"""
self.user = AdminFactory()
self._create_course(start=datetime(2010,1,1, tzinfo=UTC()), end=datetime(2011, 1, 1, tzinfo=UTC()))
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
module = self.get_module_for_user(self.user, self.course, self.problem2)
grade_dict = {'value': 0.95, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
gradebook = StudentGradebook.objects.all()
self.assertEqual(len(gradebook), 0)
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 0)
@patch.dict(settings.FEATURES, {'ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE': False})
def test_closed_course_staff(self):
"""
Users marked as course staff should be able to submit grade events to a closed course
"""
self._create_course(start=datetime(2010,1,1, tzinfo=UTC()), end=datetime(2011, 1, 1, tzinfo=UTC()))
self.user = StaffFactory(course_key=self.course.id)
module = self.get_module_for_user(self.user, self.course, self.problem)
grade_dict = {'value': 0.75, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
module = self.get_module_for_user(self.user, self.course, self.problem2)
grade_dict = {'value': 0.95, 'max_value': 1, 'user_id': self.user.id}
module.system.publish(module, 'grade', grade_dict)
gradebook = StudentGradebook.objects.all()
self.assertEqual(len(gradebook), 0)
history = StudentGradebookHistory.objects.all()
self.assertEqual(len(history), 0)
......@@ -2,13 +2,19 @@
Django database models supporting the progress app
"""
from datetime import datetime
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Sum, Q
from django.utils.timezone import UTC
from model_utils.models import TimeStampedModel
from xmodule_django.models import CourseKeyField
from xmodule.modulestore.django import modulestore
from opaque_keys.edx.keys import CourseKey
class StudentProgress(TimeStampedModel):
......
......@@ -57,6 +57,7 @@ FEATURES['EMBARGO'] = True
# Toggles API on for testing
FEATURES['API'] = True
FEATURES['ALLOW_STUDENT_STATE_UPDATES_ON_CLOSED_COURSE'] = False
# Need wiki for courseware views to work. TODO (vshnayder): shouldn't need it.
WIKI_ENABLED = True
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment