Skip to content

Commit

Permalink
feat: add db models for course reset feature (openedx#34282)
Browse files Browse the repository at this point in the history
* feat: add db models for course reset feature

* style: quality

* fix: read only fields when creating / updating model
  • Loading branch information
jansenk authored Feb 23, 2024
1 parent 78afee7 commit ab4f627
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
42 changes: 42 additions & 0 deletions lms/djangoapps/support/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
""" Django admins for support models """
from django.contrib import admin
from lms.djangoapps.support.models import CourseResetCourseOptIn, CourseResetAudit


class CourseResetCourseOptInAdmin(admin.ModelAdmin):
""" Django admin for CourseResetCourseOptIn model """
list_display = ['course_id', 'active']
fields = ['course_id', 'active', 'created', 'modified']

def get_readonly_fields(self, request, obj=None):
"""
Ensure that 'course_id' cannot be edited after creation.
"""
if obj:
return ['course_id', 'created', 'modified']
else:
return ['created', 'modified']


class CourseResetAuditAdmin(admin.ModelAdmin):
""" Django admin for CourseResetAudit model """

list_display = ['course', 'user', 'status', 'created', 'completed_at', 'reset_by']
fields = ['created', 'modified', 'status', 'completed_at', 'course', 'user', 'course_enrollment', 'reset_by']

def get_readonly_fields(self, request, obj=None):
"""
If we are editing an existing model, we should only be able to change the status, for potential debugging
"""
if obj:
return ['created', 'modified', 'completed_at', 'course', 'user', 'course_enrollment', 'reset_by']
else:
return ['created', 'modified', 'user']

@admin.display(description="user")
def user(self, obj):
return obj.course_enrollment.user


admin.site.register(CourseResetCourseOptIn, CourseResetCourseOptInAdmin)
admin.site.register(CourseResetAudit, CourseResetAuditAdmin)
49 changes: 49 additions & 0 deletions lms/djangoapps/support/migrations/0003_course_reset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 3.2.23 on 2024-02-22 14:48

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields
import opaque_keys.edx.django.models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('student', '0045_auto_20230808_0944'),
('support', '0002_alter_historicalusersocialauth_options'),
]

operations = [
migrations.CreateModel(
name='CourseResetCourseOptIn',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('course_id', opaque_keys.edx.django.models.CourseKeyField(max_length=255)),
('active', models.BooleanField()),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='CourseResetAudit',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('status', models.CharField(choices=[('in_progress', 'In Progress'), ('complete', 'Complete'), ('enqueued', 'Enqueued'), ('failed', 'Failed')], default='enqueued', max_length=12)),
('completed_at', models.DateTimeField(blank=True, default=None, null=True)),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='support.courseresetcourseoptin')),
('course_enrollment', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='student.courseenrollment')),
('reset_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]
50 changes: 50 additions & 0 deletions lms/djangoapps/support/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
"""
Models used to implement support related models in such as SSO History model
"""
from django.contrib.auth import get_user_model
from django.db.models import ForeignKey, DO_NOTHING, CASCADE, TextChoices
from django.db.models.fields import BooleanField, CharField, DateTimeField

from model_utils.models import TimeStampedModel
from opaque_keys.edx.django.models import CourseKeyField
from simple_history import register
from social_django.models import UserSocialAuth

from common.djangoapps.student.models import CourseEnrollment

User = get_user_model()

# Registers UserSocialAuth with simple-django-history.
register(UserSocialAuth, app=__package__)


class CourseResetCourseOptIn(TimeStampedModel):
"""
Model that represents a course which has opted in to the course reset feature.
"""
course_id = CourseKeyField(max_length=255)
active = BooleanField()

def __str__(self):
return f'{self.course_id} - {"ACTIVE" if self.active else "INACTIVE"}'


class CourseResetAudit(TimeStampedModel):
"""
Model which records the course reset action's status and metadata
"""
class CourseResetStatus(TextChoices):
IN_PROGRESS = "in_progress"
COMPLETE = "complete"
ENQUEUED = "enqueued"
FAILED = "failed"

course = ForeignKey(
CourseResetCourseOptIn,
on_delete=CASCADE
)
course_enrollment = ForeignKey(
CourseEnrollment,
on_delete=DO_NOTHING
)
reset_by = ForeignKey(
User,
on_delete=DO_NOTHING
)
status = CharField(
max_length=12,
choices=CourseResetStatus.choices,
default=CourseResetStatus.ENQUEUED,
)
completed_at = DateTimeField(default=None, null=True, blank=True)

0 comments on commit ab4f627

Please sign in to comment.