diff --git a/openedx/core/djangoapps/credit/migrations/0003_add_creditrequirementstatus_reason.py b/openedx/core/djangoapps/credit/migrations/0003_add_creditrequirementstatus_reason.py new file mode 100644 index 0000000000..b2f5416f4a --- /dev/null +++ b/openedx/core/djangoapps/credit/migrations/0003_add_creditrequirementstatus_reason.py @@ -0,0 +1,69 @@ +# -*- 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 'CreditRequirementStatus.reason' + db.add_column('credit_creditrequirementstatus', 'reason', + self.gf('jsonfield.fields.JSONField')(default={}), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'CreditRequirementStatus.reason' + db.delete_column('credit_creditrequirementstatus', 'reason') + + + 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', [], {}), + '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'] \ No newline at end of file diff --git a/openedx/core/djangoapps/credit/models.py b/openedx/core/djangoapps/credit/models.py index d3b7403603..c4640144ba 100644 --- a/openedx/core/djangoapps/credit/models.py +++ b/openedx/core/djangoapps/credit/models.py @@ -135,16 +135,36 @@ class CreditRequirement(TimeStampedModel): class CreditRequirementStatus(TimeStampedModel): - """This model represents the status of each requirement.""" + """This model represents the status of each requirement. + + For a particular credit requirement, a user can either: + 1) Have satisfied the requirement (example: approved in-course reverification) + 2) Have failed the requirement (example: denied in-course reverification) + 3) Neither satisfied nor failed (example: the user hasn't yet attempted in-course reverification). + + Cases (1) and (2) are represented by having a CreditRequirementStatus with + the status set to "satisfied" or "failed", respectively. + + In case (3), no CreditRequirementStatus record will exist for the requirement and user. + + """ REQUIREMENT_STATUS_CHOICES = ( ("satisfied", "satisfied"), + ("failed", "failed"), ) username = models.CharField(max_length=255, db_index=True) requirement = models.ForeignKey(CreditRequirement, related_name="statuses") status = models.CharField(choices=REQUIREMENT_STATUS_CHOICES, max_length=32) + # Include additional information about why the user satisfied or failed + # the requirement. This is specific to the type of requirement. + # For example, the minimum grade requirement might record the user's + # final grade when the user completes the course. This allows us to display + # the grade to users later and to send the information to credit providers. + reason = JSONField(default={}) + class CreditEligibility(TimeStampedModel): """A record of a user's eligibility for credit from a specific credit