Merge pull request #8315 from edx/zub/story/credit-requirement-model-add-location-id-field
use 'name' field in 'CreditRequirement' model to save the locatio…
This commit is contained in:
@@ -6,7 +6,7 @@ from openedx.core.djangoapps.credit.exceptions import InvalidCreditCourse
|
||||
|
||||
|
||||
def set_credit_requirements(course_key, requirements):
|
||||
""" Add requirements to given course
|
||||
"""Add requirements to given course.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): The identifier for course
|
||||
@@ -16,24 +16,22 @@ def set_credit_requirements(course_key, requirements):
|
||||
>>> set_credit_requirements(
|
||||
"course-v1-edX-DemoX-1T2015",
|
||||
[
|
||||
{
|
||||
"namespace": "verification",
|
||||
"name": "verification",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "proctored_exam",
|
||||
"name": "final",
|
||||
"name": "i4x://edX/DemoX/proctoring-block/final_uuid",
|
||||
"display_name": "Final Exam",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {"min_grade": 0.8},
|
||||
},
|
||||
])
|
||||
@@ -65,7 +63,7 @@ def set_credit_requirements(course_key, requirements):
|
||||
|
||||
|
||||
def get_credit_requirements(course_key, namespace=None):
|
||||
""" Returns the requirements of a given course and namespace
|
||||
"""Get credit eligibility requirements of a given course and namespace.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): The identifier for course
|
||||
@@ -76,24 +74,22 @@ def get_credit_requirements(course_key, namespace=None):
|
||||
{
|
||||
requirements =
|
||||
[
|
||||
{
|
||||
"namespace": "verification",
|
||||
"name": "verification",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "proctored_exam",
|
||||
"name": "final",
|
||||
"name": "i4x://edX/DemoX/proctoring-block/final_uuid",
|
||||
"display_name": "Final Exam",
|
||||
"criteria": {},
|
||||
},
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {"min_grade": 0.8},
|
||||
},
|
||||
]
|
||||
@@ -108,6 +104,7 @@ def get_credit_requirements(course_key, namespace=None):
|
||||
{
|
||||
"namespace": requirement.namespace,
|
||||
"name": requirement.name,
|
||||
"display_name": requirement.display_name,
|
||||
"criteria": requirement.criteria
|
||||
}
|
||||
for requirement in requirements
|
||||
@@ -115,7 +112,8 @@ def get_credit_requirements(course_key, namespace=None):
|
||||
|
||||
|
||||
def _get_requirements_to_disable(old_requirements, new_requirements):
|
||||
""" Returns the ids of CreditRequirement to be disabled that are deleted from the courseware
|
||||
"""Get the ids of 'CreditRequirement' entries to be disabled that are
|
||||
deleted from the courseware.
|
||||
|
||||
Args:
|
||||
old_requirements(QuerySet): QuerySet of CreditRequirement
|
||||
@@ -128,6 +126,7 @@ def _get_requirements_to_disable(old_requirements, new_requirements):
|
||||
for old_req in old_requirements:
|
||||
found_flag = False
|
||||
for req in new_requirements:
|
||||
# check if an already added requirement is modified
|
||||
if req["namespace"] == old_req.namespace and req["name"] == old_req.name:
|
||||
found_flag = True
|
||||
break
|
||||
@@ -137,7 +136,7 @@ def _get_requirements_to_disable(old_requirements, new_requirements):
|
||||
|
||||
|
||||
def _validate_requirements(requirements):
|
||||
""" Validate the requirements
|
||||
"""Validate the requirements.
|
||||
|
||||
Args:
|
||||
requirements(list): List of requirements
|
||||
@@ -152,6 +151,8 @@ def _validate_requirements(requirements):
|
||||
invalid_params.append("namespace")
|
||||
if not requirement.get("name"):
|
||||
invalid_params.append("name")
|
||||
if not requirement.get("display_name"):
|
||||
invalid_params.append("display_name")
|
||||
if "criteria" not in requirement:
|
||||
invalid_params.append("criteria")
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
""" This module contains the exceptions raised in credit course requirements """
|
||||
"""
|
||||
This module contains the exceptions raised in credit course requirements.
|
||||
"""
|
||||
|
||||
|
||||
class InvalidCreditRequirements(Exception):
|
||||
""" The exception occurs when the requirement dictionary has invalid format. """
|
||||
"""
|
||||
The exception occurs when the requirement dictionary has invalid format.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidCreditCourse(Exception):
|
||||
""" The exception occurs when the the course is not marked as a Credit Course. """
|
||||
"""
|
||||
The exception occurs when the the course is not marked as a Credit Course.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'CreditRequirement.display_name'
|
||||
db.add_column('credit_creditrequirement', 'display_name',
|
||||
self.gf('django.db.models.fields.CharField')(default='', max_length=255),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'CreditRequirement.display_name'
|
||||
db.delete_column('credit_creditrequirement', 'display_name')
|
||||
|
||||
|
||||
models = {
|
||||
'credit.creditcourse': {
|
||||
'Meta': {'object_name': 'CreditCourse'},
|
||||
'course_key': ('xmodule_django.models.CourseKeyField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'credit.crediteligibility': {
|
||||
'Meta': {'unique_together': "(('username', 'course'),)", 'object_name': 'CreditEligibility'},
|
||||
'course': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'eligibilities'", 'to': "orm['credit.CreditCourse']"}),
|
||||
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'provider': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'eligibilities'", 'to': "orm['credit.CreditProvider']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'credit.creditprovider': {
|
||||
'Meta': {'object_name': 'CreditProvider'},
|
||||
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'provider_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'credit.creditrequirement': {
|
||||
'Meta': {'unique_together': "(('namespace', 'name', 'course'),)", 'object_name': 'CreditRequirement'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'course': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'credit_requirements'", 'to': "orm['credit.CreditCourse']"}),
|
||||
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'criteria': ('jsonfield.fields.JSONField', [], {}),
|
||||
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'namespace': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'credit.creditrequirementstatus': {
|
||||
'Meta': {'object_name': 'CreditRequirementStatus'},
|
||||
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
|
||||
'reason': ('jsonfield.fields.JSONField', [], {'default': '{}'}),
|
||||
'requirement': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'statuses'", 'to': "orm['credit.CreditRequirement']"}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['credit']
|
||||
@@ -19,14 +19,16 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreditCourse(models.Model):
|
||||
"""Model for tracking a credit course."""
|
||||
"""
|
||||
Model for tracking a credit course.
|
||||
"""
|
||||
|
||||
course_key = CourseKeyField(max_length=255, db_index=True, unique=True)
|
||||
enabled = models.BooleanField(default=False)
|
||||
|
||||
@classmethod
|
||||
def is_credit_course(cls, course_key):
|
||||
""" Check that given course is credit or not
|
||||
"""Check that given course is credit or not.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): The course identifier
|
||||
@@ -38,7 +40,7 @@ class CreditCourse(models.Model):
|
||||
|
||||
@classmethod
|
||||
def get_credit_course(cls, course_key):
|
||||
""" Get the credit course if exists for the given course_key
|
||||
"""Get the credit course if exists for the given 'course_key'.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): The course identifier
|
||||
@@ -65,28 +67,36 @@ class CreditProvider(TimeStampedModel):
|
||||
class CreditRequirement(TimeStampedModel):
|
||||
"""This model represents a credit requirement.
|
||||
|
||||
Each requirement is uniquely identified by a `namespace` and a `name`. CreditRequirements
|
||||
also include a `criteria` dictionary, the format of which varies by the type of requirement.
|
||||
The criteria dictionary provides additional information clients may need to determine
|
||||
whether a user has satisfied the requirement.
|
||||
Each requirement is uniquely identified by its 'namespace' and
|
||||
'name' fields.
|
||||
The 'name' field stores the unique name or location (in case of XBlock)
|
||||
for a requirement, which serves as the unique identifier for that
|
||||
requirement.
|
||||
The 'display_name' field stores the display name of the requirement.
|
||||
The 'criteria' field dictionary provides additional information, clients
|
||||
may need to determine whether a user has satisfied the requirement.
|
||||
"""
|
||||
|
||||
course = models.ForeignKey(CreditCourse, related_name="credit_requirements")
|
||||
namespace = models.CharField(max_length=255)
|
||||
name = models.CharField(max_length=255)
|
||||
display_name = models.CharField(max_length=255)
|
||||
criteria = JSONField()
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
class Meta(object):
|
||||
"""Model metadata"""
|
||||
"""
|
||||
Model metadata.
|
||||
"""
|
||||
unique_together = ('namespace', 'name', 'course')
|
||||
|
||||
@classmethod
|
||||
def add_or_update_course_requirement(cls, credit_course, requirement):
|
||||
""" Add requirement to a given course
|
||||
"""Add requirement to a given course.
|
||||
|
||||
Args:
|
||||
credit_course(CreditCourse): The identifier for credit course course
|
||||
requirement(dict): requirement dict to be added
|
||||
credit_course(CreditCourse): The identifier for credit course
|
||||
requirement(dict): Requirement dict to be added
|
||||
|
||||
Returns:
|
||||
(CreditRequirement, created) tuple
|
||||
@@ -96,6 +106,7 @@ class CreditRequirement(TimeStampedModel):
|
||||
course=credit_course,
|
||||
namespace=requirement["namespace"],
|
||||
name=requirement["name"],
|
||||
display_name=requirement["display_name"],
|
||||
defaults={"criteria": requirement["criteria"], "active": True}
|
||||
)
|
||||
if not created:
|
||||
@@ -107,11 +118,11 @@ class CreditRequirement(TimeStampedModel):
|
||||
|
||||
@classmethod
|
||||
def get_course_requirements(cls, course_key, namespace=None):
|
||||
""" Get credit requirements of a given course
|
||||
"""Get credit requirements of a given course.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): The identifier for a course
|
||||
namespace(str): namespace of credit course requirements
|
||||
namespace(str): Namespace of credit course requirements
|
||||
|
||||
Returns:
|
||||
QuerySet of CreditRequirement model
|
||||
@@ -123,7 +134,7 @@ class CreditRequirement(TimeStampedModel):
|
||||
|
||||
@classmethod
|
||||
def disable_credit_requirements(cls, requirement_ids):
|
||||
""" Mark the given requirements inactive
|
||||
"""Mark the given requirements inactive.
|
||||
|
||||
Args:
|
||||
requirement_ids(list): List of ids
|
||||
@@ -176,5 +187,7 @@ class CreditEligibility(TimeStampedModel):
|
||||
provider = models.ForeignKey(CreditProvider, related_name="eligibilities")
|
||||
|
||||
class Meta(object):
|
||||
"""Model metadata"""
|
||||
"""
|
||||
Model metadata.
|
||||
"""
|
||||
unique_together = ('username', 'course')
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
"""This file contains receivers of course publication signals."""
|
||||
"""
|
||||
This file contains receivers of course publication signals.
|
||||
"""
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
@@ -7,11 +9,12 @@ from xmodule.modulestore.django import SignalHandler
|
||||
|
||||
@receiver(SignalHandler.course_published)
|
||||
def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Receives signal and kicks off celery task to update the course requirements.
|
||||
"""Receive 'course_published' signal and kick off a celery task to update
|
||||
the credit course requirements.
|
||||
"""
|
||||
|
||||
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
|
||||
# Import here, because signal is registered at startup, but items in tasks
|
||||
# are not yet able to be loaded
|
||||
from .tasks import update_course_requirements
|
||||
|
||||
update_course_requirements.delay(unicode(course_key))
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
""" This file contains celery tasks for credit course views """
|
||||
"""
|
||||
This file contains celery tasks for credit course views.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
@@ -55,20 +57,20 @@ def _get_course_credit_requirements(course):
|
||||
List of minimum_grade_credit and ICRV requirements
|
||||
|
||||
"""
|
||||
icrv_requirements = _get_credit_course_requirement_xblocks(course)
|
||||
credit_xblock_requirements = _get_credit_course_requirement_xblocks(course)
|
||||
min_grade_requirement = _get_min_grade_requirement(course)
|
||||
credit_requirements = icrv_requirements + min_grade_requirement
|
||||
credit_requirements = credit_xblock_requirements + min_grade_requirement
|
||||
return credit_requirements
|
||||
|
||||
|
||||
def _get_min_grade_requirement(course):
|
||||
"""Returns the list of minimum_grade_credit requirements for the given course.
|
||||
"""Get list of 'minimum_grade_credit' requirement for the given course.
|
||||
|
||||
Args:
|
||||
course(Course): The course object
|
||||
|
||||
Raises:
|
||||
AttributeError if the course has not minimum_grade_credit attribute
|
||||
AttributeError if the course has not 'minimum_grade_credit' attribute
|
||||
|
||||
Returns:
|
||||
The list of minimum_grade_credit requirements
|
||||
@@ -80,6 +82,7 @@ def _get_min_grade_requirement(course):
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": getattr(course, "minimum_grade_credit")
|
||||
}
|
||||
@@ -91,7 +94,7 @@ def _get_min_grade_requirement(course):
|
||||
|
||||
|
||||
def _get_credit_course_requirement_xblocks(course): # pylint: disable=invalid-name
|
||||
"""Generates a course structure dictionary for the specified course.
|
||||
"""Generate a course structure dictionary for the specified course.
|
||||
|
||||
Args:
|
||||
course(Course): The course object
|
||||
@@ -109,23 +112,25 @@ def _get_credit_course_requirement_xblocks(course): # pylint: disable=invalid-n
|
||||
block = {
|
||||
"namespace": curr_block.get_credit_requirement_namespace(),
|
||||
"name": curr_block.get_credit_requirement_name(),
|
||||
"display_name": curr_block.get_credit_requirement_display_name(),
|
||||
"criteria": ""
|
||||
}
|
||||
requirements_blocks.append(block)
|
||||
|
||||
# Add this blocks children to the stack so that we can traverse them as well.
|
||||
# Add the children of current block to the stack so that we can
|
||||
# traverse them as well.
|
||||
blocks_stack.extend(children)
|
||||
return requirements_blocks
|
||||
|
||||
|
||||
def _is_credit_requirement(xblock):
|
||||
"""Check if the given xblock is a credit requirement.
|
||||
"""Check if the given XBlock is a credit requirement.
|
||||
|
||||
Args:
|
||||
xblock(XBlock): The given xblock object
|
||||
xblock(XBlock): The given XBlock object
|
||||
|
||||
Returns:
|
||||
True if xblock is a credit requirement else False
|
||||
True if XBlock is a credit requirement else False
|
||||
|
||||
"""
|
||||
is_credit_requirement = False
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
""" Tests for credit course api """
|
||||
"""
|
||||
Tests for credit course api.
|
||||
"""
|
||||
|
||||
import ddt
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.credit.api import (
|
||||
get_credit_requirements, set_credit_requirements, _get_requirements_to_disable
|
||||
)
|
||||
@@ -12,7 +16,9 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
@ddt.ddt
|
||||
class ApiTestCases(ModuleStoreTestCase):
|
||||
""" Tests for credit course api """
|
||||
"""
|
||||
Tests for credit course api.
|
||||
"""
|
||||
|
||||
def setUp(self, **kwargs):
|
||||
super(ApiTestCases, self).setUp()
|
||||
@@ -39,6 +45,7 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade"
|
||||
}
|
||||
]
|
||||
)
|
||||
@@ -48,25 +55,34 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
set_credit_requirements(self.course_key, requirements)
|
||||
|
||||
def test_set_credit_requirements_invalid_course(self):
|
||||
"""Test that 'InvalidCreditCourse' exception is raise if we try to
|
||||
set credit requirements for a non credit course.
|
||||
"""
|
||||
requirements = [
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {}
|
||||
}
|
||||
]
|
||||
with self.assertRaises(InvalidCreditCourse):
|
||||
set_credit_requirements(self.course_key, requirements)
|
||||
|
||||
self.add_credit_course(enabled=False)
|
||||
with self.assertRaises(InvalidCreditCourse):
|
||||
set_credit_requirements(self.course_key, requirements)
|
||||
|
||||
def test_set_get_credit_requirements(self):
|
||||
"""Test that if same requirement is added multiple times
|
||||
then it is added only one time and update for next all iterations.
|
||||
"""
|
||||
self.add_credit_course()
|
||||
requirements = [
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
@@ -74,27 +90,26 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
"min_grade": 0.9
|
||||
}
|
||||
}
|
||||
]
|
||||
set_credit_requirements(self.course_key, requirements)
|
||||
self.assertEqual(len(get_credit_requirements(self.course_key)), 1)
|
||||
|
||||
# now verify that the saved requirement has values of last requirement
|
||||
# from all same requirements
|
||||
self.assertEqual(get_credit_requirements(self.course_key)[0], requirements[1])
|
||||
|
||||
def test_disable_credit_requirements(self):
|
||||
self.add_credit_course()
|
||||
requirements = [
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
@@ -106,12 +121,14 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
requirements = [
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {}
|
||||
}
|
||||
]
|
||||
set_credit_requirements(self.course_key, requirements)
|
||||
self.assertEqual(len(get_credit_requirements(self.course_key)), 1)
|
||||
|
||||
grade_req = CreditRequirement.objects.filter(namespace="grade", name="grade")
|
||||
self.assertEqual(len(grade_req), 1)
|
||||
self.assertEqual(grade_req[0].active, False)
|
||||
@@ -122,13 +139,7 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
@@ -142,7 +153,8 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
requirements = [
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {}
|
||||
}
|
||||
]
|
||||
@@ -154,13 +166,15 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
{
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"namespace": "reverification",
|
||||
"name": "midterm",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {}
|
||||
}
|
||||
]
|
||||
@@ -168,8 +182,9 @@ class ApiTestCases(ModuleStoreTestCase):
|
||||
self.assertEqual(len(requirements_to_disabled), 0)
|
||||
|
||||
def add_credit_course(self, enabled=True):
|
||||
""" Mark the course as a credit """
|
||||
|
||||
"""
|
||||
Mark the course as a credit.
|
||||
"""
|
||||
credit_course = CreditCourse(course_key=self.course_key, enabled=enabled)
|
||||
credit_course.save()
|
||||
return credit_course
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
""" Tests for credit course models """
|
||||
"""
|
||||
Tests for credit course models.
|
||||
"""
|
||||
|
||||
import ddt
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.credit.models import CreditCourse, CreditRequirement
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ModelTestCases(ModuleStoreTestCase):
|
||||
""" Tests for credit course models """
|
||||
"""
|
||||
Tests for credit course models.
|
||||
"""
|
||||
|
||||
def setUp(self, **kwargs):
|
||||
super(ModelTestCases, self).setUp()
|
||||
@@ -28,6 +33,7 @@ class ModelTestCases(ModuleStoreTestCase):
|
||||
requirement = {
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
@@ -43,6 +49,7 @@ class ModelTestCases(ModuleStoreTestCase):
|
||||
requirement = {
|
||||
"namespace": "grade",
|
||||
"name": "grade",
|
||||
"display_name": "Grade",
|
||||
"criteria": {
|
||||
"min_grade": 0.8
|
||||
}
|
||||
@@ -52,9 +59,10 @@ class ModelTestCases(ModuleStoreTestCase):
|
||||
self.assertEqual(created, True)
|
||||
|
||||
requirement = {
|
||||
"namespace": "icrv",
|
||||
"name": "midterm",
|
||||
"criteria": ""
|
||||
"namespace": "reverification",
|
||||
"name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
|
||||
"display_name": "Assessment 1",
|
||||
"criteria": {}
|
||||
}
|
||||
credit_req, created = CreditRequirement.add_or_update_course_requirement(credit_course, requirement)
|
||||
self.assertEqual(credit_course, credit_req.course)
|
||||
@@ -62,6 +70,7 @@ class ModelTestCases(ModuleStoreTestCase):
|
||||
|
||||
requirements = CreditRequirement.get_course_requirements(self.course_key)
|
||||
self.assertEqual(len(requirements), 2)
|
||||
|
||||
requirements = CreditRequirement.get_course_requirements(self.course_key, namespace="grade")
|
||||
self.assertEqual(len(requirements), 1)
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
""" Tests for credit course tasks """
|
||||
"""
|
||||
Tests for credit course tasks.
|
||||
"""
|
||||
|
||||
import mock
|
||||
from datetime import datetime
|
||||
@@ -13,16 +15,17 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
|
||||
|
||||
class TestTaskExecution(ModuleStoreTestCase):
|
||||
"""
|
||||
Set of tests to ensure that the task code will do the right thing when
|
||||
executed directly. The test course gets created without the listeners
|
||||
being present, which allows us to ensure that when the listener is
|
||||
executed, it is done as expected.
|
||||
"""Set of tests to ensure that the task code will do the right thing when
|
||||
executed directly.
|
||||
|
||||
The test course gets created without the listeners being present, which
|
||||
allows us to ensure that when the listener is executed, it is done as
|
||||
expected.
|
||||
"""
|
||||
|
||||
def mocked_set_credit_requirements(course_key, requirements): # pylint: disable=no-self-argument, unused-argument
|
||||
"""
|
||||
Used as a side effect when mocking `verify_student.ssencrypt.has_valid_signature`.
|
||||
"""Used as a side effect when mocking method credit api method
|
||||
'set_credit_requirements'.
|
||||
"""
|
||||
raise InvalidCreditRequirements
|
||||
|
||||
@@ -46,8 +49,7 @@ class TestTaskExecution(ModuleStoreTestCase):
|
||||
|
||||
def test_task_adding_requirements_invalid_course(self):
|
||||
"""
|
||||
Make sure that the receiver correctly fires off the task when
|
||||
invoked by signal
|
||||
Test that credit requirements cannot be added for non credit course.
|
||||
"""
|
||||
requirements = get_credit_requirements(self.course.id)
|
||||
self.assertEqual(len(requirements), 0)
|
||||
@@ -57,9 +59,10 @@ class TestTaskExecution(ModuleStoreTestCase):
|
||||
self.assertEqual(len(requirements), 0)
|
||||
|
||||
def test_task_adding_requirements(self):
|
||||
"""
|
||||
"""Test that credit requirements are added properly for credit course.
|
||||
|
||||
Make sure that the receiver correctly fires off the task when
|
||||
invoked by signal
|
||||
invoked by signal.
|
||||
"""
|
||||
self.add_credit_course(self.course.id)
|
||||
requirements = get_credit_requirements(self.course.id)
|
||||
@@ -70,9 +73,8 @@ class TestTaskExecution(ModuleStoreTestCase):
|
||||
self.assertEqual(len(requirements), 1)
|
||||
|
||||
def test_task_adding_icrv_requirements(self):
|
||||
"""
|
||||
Make sure that the receiver correctly fires off the task when
|
||||
invoked by signal
|
||||
"""Make sure that the receiver correctly fires off the task when
|
||||
invoked by signal.
|
||||
"""
|
||||
self.add_credit_course(self.course.id)
|
||||
self.add_icrv_xblock()
|
||||
@@ -90,7 +92,9 @@ class TestTaskExecution(ModuleStoreTestCase):
|
||||
)
|
||||
)
|
||||
def test_retry(self):
|
||||
"""
|
||||
"""Test that adding credit requirements is retried when
|
||||
'InvalidCreditRequirements' exception is raised.
|
||||
|
||||
Make sure that the receiver correctly fires off the task when
|
||||
invoked by signal
|
||||
"""
|
||||
@@ -103,10 +107,10 @@ class TestTaskExecution(ModuleStoreTestCase):
|
||||
self.assertEqual(len(requirements), 0)
|
||||
|
||||
def add_credit_course(self, course_key):
|
||||
""" Add the course as a credit
|
||||
"""Add the course as a credit.
|
||||
|
||||
Args:
|
||||
course_key(CourseKey): identifier for the course
|
||||
course_key(CourseKey): Identifier for the course
|
||||
|
||||
Returns:
|
||||
CreditCourse object added
|
||||
|
||||
@@ -50,7 +50,7 @@ git+https://github.com/hmarr/django-debug-toolbar-mongo.git@b0686a76f1ce3532088c
|
||||
git+https://github.com/edx/edx-lint.git@ed8c8d2a0267d4d42f43642d193e25f8bd575d9b#egg=edx_lint==0.2.3
|
||||
-e git+https://github.com/edx/xblock-utils.git@db22bc40fd2a75458a3c66d057f88aff5a7383e6#egg=xblock-utils
|
||||
-e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive
|
||||
-e git+https://github.com/edx/edx-reverification-block.git@03da85753d5f563a22c1282c0e89fcb2e828b8c1#egg=edx-reverification-block
|
||||
-e git+https://github.com/edx/edx-reverification-block.git@6e2834c5f7e998ad9b81170e7ceb4d8a64900eb0#egg=edx-reverification-block
|
||||
git+https://github.com/edx/ecommerce-api-client.git@1.0.0#egg=ecommerce-api-client==1.0.0
|
||||
|
||||
# Third Party XBlocks
|
||||
|
||||
Reference in New Issue
Block a user