Commit 93c3ff2a by Albert (AJ) St. Aubin Committed by GitHub

Merge pull request #16273 from edx/aj/LEARNER-1733

Implement Entitlement Model for Course Centric Architecture
parents aa980554 a9011fde
from django.contrib import admin
from .models import CourseEntitlement
@admin.register(CourseEntitlement)
class EntitlementAdmin(admin.ModelAdmin):
list_display = ('user',
'uuid',
'course_uuid',
'created',
'modified',
'expired_at',
'mode',
'enrollment_course_run',
'order_number')
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
from django.conf import settings
import model_utils.fields
import uuid
class Migration(migrations.Migration):
dependencies = [
('student', '0013_delete_historical_enrollment_records'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='CourseEntitlement',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False)),
('course_uuid', models.UUIDField()),
('expired_at', models.DateTimeField(null=True)),
('mode', models.CharField(default=b'audit', max_length=100)),
('order_number', models.CharField(max_length=128, null=True)),
('enrollment_course_run', models.ForeignKey(to='student.CourseEnrollment', null=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]
import uuid as uuid_tools
from django.db import models
from model_utils.models import TimeStampedModel
from django.contrib.auth.models import User
from course_modes.models import CourseMode
class CourseEntitlement(TimeStampedModel):
"""
Represents a Student's Entitlement to a Course Run for a given Course.
"""
user = models.ForeignKey(User)
uuid = models.UUIDField(default=uuid_tools.uuid4, editable=False)
course_uuid = models.UUIDField()
# The date that an the entitlement expired
# if NULL the entitlement has not expired
expired_at = models.DateTimeField(null=True)
# The mode of the Course that will be applied
mode = models.CharField(default=CourseMode.DEFAULT_MODE_SLUG, max_length=100)
# The ID of the course enrollment for this Entitlement
# if NULL the entitlement is not in use
enrollment_course_run = models.ForeignKey('student.CourseEnrollment', null=True)
order_number = models.CharField(max_length=128, null=True)
@classmethod
def entitlements_for_user(cls, user):
"""
Retrieve all the Entitlements for a User
Arguments:
user: A Django User object identifying the current user
Returns:
All of the Entitlements for the User
"""
return cls.objects.filter(user=user)
@classmethod
def get_user_course_entitlement(cls, user, course_uuid):
"""
Retrieve The entitlement for the given parent course id if it exists for the User
Arguments:
user: A Django User object identifying the current user
course_uuid(string): The parent course uuid
Returns:
The single entitlement for the requested parent course id
"""
return cls.objects.filter(user=user, course_uuid=course_uuid).first()
@classmethod
def update_or_create_new_entitlement(cls, user, course_uuid, entitlement_data):
"""
Updates or creates a new Course Entitlement
Arguments:
user: A Django User object identifying the current user
course_uuid(string): The parent course uuid
entitlement_data(dict): The dictionary containing all the data for the entitlement
e.g. entitlement_data = {
'user': user,
'course_uuid': course_uuid
'enroll_end_date': '2017-09-14 11:47:58.000000',
'mode': 'verified',
}
Returns:
stored_entitlement: The new or updated CourseEntitlement object
is_created (bool): Boolean representing whether or not the Entitlement was created or updated
"""
stored_entitlement, is_created = cls.objects.update_or_create(
user=user,
course_uuid=course_uuid,
defaults=entitlement_data
)
return stored_entitlement, is_created
@classmethod
def update_entitlement_enrollment(cls, user, course_uuid, course_run_enrollment):
"""
Sets the enrollment course for a given entitlement
Arguments:
user: A Django User object identifying the current user
course_uuid(string): The parent course uuid
course_run_enrollment (CourseEnrollment): The CourseEnrollment object to store, None to clear the Enrollment
"""
return cls.objects.filter(
user=user,
course_uuid=course_uuid
).update(enrollment_course_run_id=course_run_enrollment)
"""
Test the Data Aggregation Layer for Course Entitlements.
"""
import unittest
import uuid
import ddt
from django.conf import settings
from entitlements.models import CourseEntitlement
from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from student.tests.factories import CourseEnrollmentFactory
@ddt.ddt
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class EntitlementDataTest(ModuleStoreTestCase):
"""
Test course entitlement data aggregation.
"""
USERNAME = "Bob"
EMAIL = "bob@example.com"
PASSWORD = "edx"
def setUp(self):
"""Create a course and user, then log in. """
super(EntitlementDataTest, self).setUp()
self.course = CourseFactory.create()
self.course_uuid = uuid.uuid4()
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
self.client.login(username=self.USERNAME, password=self.PASSWORD)
def _add_entitlement_for_user(self, course, user, parent_uuid):
entitlement_data = {
'user': user,
'course_uuid': parent_uuid,
'mode': 'verified',
}
stored_entitlement, is_created = CourseEntitlement.update_or_create_new_entitlement(
user,
parent_uuid,
entitlement_data
)
return stored_entitlement, is_created
def test_get_entitlement_info(self):
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
self.assertTrue(is_created)
# Get the Entitlement and verify the data
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
self.assertEqual(entitlement.course_uuid, self.course_uuid)
self.assertEqual(entitlement.mode, 'verified')
self.assertIsNone(entitlement.enrollment_course_run)
def test_get_course_entitlements(self):
course2 = CourseFactory.create()
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
self.assertTrue(is_created)
course2_uuid = uuid.uuid4()
stored_entitlement2, is_created2 = self._add_entitlement_for_user(course2, self.user, course2_uuid)
self.assertTrue(is_created2)
# Get the Entitlement and verify the data
entitlement_list = CourseEntitlement.entitlements_for_user(self.user)
self.assertEqual(2, len(entitlement_list))
self.assertEqual(self.course_uuid, entitlement_list[0].course_uuid)
self.assertEqual(course2_uuid, entitlement_list[1].course_uuid)
def test_set_enrollment(self):
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
self.assertTrue(is_created)
# Entitlement set not enroll the user in the Course run
enrollment = CourseEnrollmentFactory(
user=self.user,
course_id=self.course.id,
mode="verified",
)
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, enrollment)
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
self.assertIsNotNone(entitlement.enrollment_course_run)
def test_remove_enrollment(self):
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
self.assertTrue(is_created)
# Entitlement set not enroll the user in the Course run
enrollment = CourseEnrollmentFactory(
user=self.user,
course_id=self.course.id,
mode="verified",
)
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, enrollment)
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
self.assertIsNotNone(entitlement.enrollment_course_run)
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, None)
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
self.assertIsNone(entitlement.enrollment_course_run)
......@@ -2128,6 +2128,9 @@ INSTALLED_APPS = [
# Enrollment API
'enrollment',
# Entitlement API
'entitlements',
# Bulk Enrollment API
'bulk_enroll',
......
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