Skip to content

Commit

Permalink
Only prompt for login for enrollable runs (#5051)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysyngsun committed Sep 21, 2021
1 parent 9a78149 commit b56aeec
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 38 deletions.
10 changes: 10 additions & 0 deletions courses/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,13 @@ class CourseRunFactory(DjangoModelFactory):

class Meta:
model = CourseRun

class Params:
future_run = factory.Trait(
enrollment_start = factory.Faker(
'date_time_between',
start_date="+1d",
end_date="+30d",
tzinfo=pytz.utc
)
)
44 changes: 22 additions & 22 deletions courses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils.functional import cached_property

from grades.constants import FinalGradeStatus
from micromasters.models import TimestampedModel
Expand All @@ -29,24 +30,10 @@ class Topic(models.Model):
def __str__(self):
return self.name


class ProgramQuerySet(models.QuerySet):
"""
Custom QuerySet for Programs
"""
def prefetch_course_runs(self):
"""Returns a new query that prefetches the course runs"""
return self.prefetch_related(
models.Prefetch("course_set__courserun_set", to_attr="course_runs")
)


class Program(TimestampedModel):
"""
A degree someone can pursue, e.g. "Supply Chain Management"
"""
objects = ProgramQuerySet.as_manager()

title = models.CharField(max_length=255)
live = models.BooleanField(default=False)
description = models.TextField(blank=True, null=True)
Expand All @@ -67,22 +54,22 @@ def has_frozen_grades_for_all_courses(self):
"""
return all([course.has_frozen_runs() for course in self.course_set.all()])

@property
def course_runs(self):
@cached_property
def enrollable_course_runs(self):
""" Return the set of course runs """
return CourseRun.objects.filter(course__program=self)
return CourseRun.objects.filter(course__program=self).enrollable()

@property
def courseware_backends(self):
@cached_property
def enrollable_courseware_backends(self):
""" Return the set of courseware backends """
return list({run.courseware_backend for run in self.course_runs})
return list({run.courseware_backend for run in self.enrollable_course_runs})

@property
@cached_property
def has_mitxonline_courses(self):
"""
Return true if as least one course has at least one run that is on mitxonline
"""
return BACKEND_MITX_ONLINE in self.courseware_backends
return BACKEND_MITX_ONLINE in self.enrollable_courseware_backends


class Course(models.Model):
Expand Down Expand Up @@ -202,12 +189,25 @@ def first_unexpired_run(self):
)



class CourseRunQuerySet(models.QuerySet):
"""
Custom QuerySet for CourseRuns
"""
def enrollable(self):
"""Returns a new query that returns currently enrollable runs"""
now = now_in_utc()
return self.filter(enrollment_start__lte=now, enrollment_end__gt=now)


class CourseRun(models.Model):
"""
An individual run of a course within a Program, e.g. "Supply Chain 101
- Summer 2017". This is different than the logical notion of a course, but
rather a specific instance of that course being taught.
"""
objects = CourseRunQuerySet.as_manager()

title = models.CharField(max_length=255)
edx_course_key = models.CharField(max_length=255, blank=True, null=True, unique=True)
enrollment_start = models.DateTimeField(blank=True, null=True, db_index=True)
Expand Down
15 changes: 15 additions & 0 deletions courses/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ def test_complete(self, first_has_frozen, second_has_frozen, result):

assert course_1.program.has_frozen_grades_for_all_courses() is result

def test_enrollable_course_runs(self):
""" Test that enrollable_course_runs only returns currently enrollable runs """
program = ProgramFactory.create()
enrollable_run = CourseRunFactory.create(course__program=program) # enrollable
CourseRunFactory.create(course__program=program, future_run=True) # not enrollable

assert list(program.enrollable_course_runs) == [enrollable_run]


def from_weeks(weeks, now=None):
"""Helper function to get a date adjusted by a number of weeks"""
Expand Down Expand Up @@ -563,3 +571,10 @@ def test_has_future_exam(self):
date_last_eligible=(now_in_utc() - timedelta(days=1)).date(),
)
assert course_run.has_future_exam is False

def test_enrollable(self):
""" Test CourseRun.objects.enrollable() """
enrollable_run = CourseRunFactory.create() # enrollable
CourseRunFactory.create(future_run=True) # not enrollable

assert list(CourseRun.objects.enrollable()) == [enrollable_run]
2 changes: 1 addition & 1 deletion courses/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Meta:
'enrolled',
'total_courses',
'topics',
'courseware_backends',
'enrollable_courseware_backends',
)


Expand Down
8 changes: 4 additions & 4 deletions courses/serializers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_program_no_programpage(self):
'enrolled': False,
'total_courses': 1,
'topics': [{'name': topic.name} for topic in self.program.topics.iterator()],
"courseware_backends": ["edxorg"],
"enrollable_courseware_backends": ["edxorg"],
}

def test_program_with_programpage(self):
Expand All @@ -118,7 +118,7 @@ def test_program_with_programpage(self):
'enrolled': False,
'total_courses': 1,
'topics': [{'name': topic.name} for topic in self.program.topics.iterator()],
"courseware_backends": ["edxorg"],
"enrollable_courseware_backends": ["edxorg"],
}
assert len(programpage.url) > 0

Expand All @@ -135,7 +135,7 @@ def test_program_enrolled(self):
'enrolled': True,
'total_courses': 1,
'topics': [{'name': topic.name} for topic in self.program.topics.iterator()],
"courseware_backends": ["edxorg"],
"enrollable_courseware_backends": ["edxorg"],
}

def test_program_courses(self):
Expand All @@ -151,7 +151,7 @@ def test_program_courses(self):
'enrolled': False,
'total_courses': 6,
'topics': [{'name': topic.name} for topic in self.program.topics.iterator()],
"courseware_backends": ["edxorg"],
"enrollable_courseware_backends": ["edxorg"],
}


Expand Down
2 changes: 1 addition & 1 deletion courses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ProgramViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = (
IsAuthenticated,
)
queryset = Program.objects.filter(live=True).prefetch_course_runs()
queryset = Program.objects.filter(live=True)
serializer_class = ProgramSerializer


Expand Down
12 changes: 6 additions & 6 deletions static/js/components/CouponNotificationDialog_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ const COURSE: Course = {
}

const PROGRAM: AvailableProgram = {
id: 1,
title: "Awesomesauce",
enrolled: true,
programpage_url: null,
total_courses: 0,
courseware_backends: ["edxorg"]
id: 1,
title: "Awesomesauce",
enrolled: true,
programpage_url: null,
total_courses: 0,
enrollable_courseware_backends: ["edxorg"]
}

describe("CouponNotificationDialog", () => {
Expand Down
2 changes: 1 addition & 1 deletion static/js/components/SocialAuthDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const SocialAuthDialog = (props: Props) => {
const [open, setOpen] = useState(false)
const missingBackend = R.head(
R.difference(
R.propOr([], "courseware_backends", currentProgramEnrollment),
R.propOr([], "enrollable_courseware_backends", currentProgramEnrollment),
R.propOr([], "social_auth_providers", SETTINGS.user)
)
)
Expand Down
4 changes: 2 additions & 2 deletions static/js/factories/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const makeAvailableProgram = (
programpage_url: `/page/${programId}`,
title: `AvailableProgram for ${programId}`,
total_courses: 1,
courseware_backends: backends
enrollable_courseware_backends: backends
}
}

Expand All @@ -79,7 +79,7 @@ export const makeAvailablePrograms = (
programpage_url: `/page/${program.id}`,
title: `AvailableProgram for ${program.id}`,
total_courses: 1,
courseware_backends: ["edxorg"]
enrollable_courseware_backends: ["edxorg"]
}))
}

Expand Down
2 changes: 1 addition & 1 deletion static/js/flow/enrollmentTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type AvailableProgram = {
programpage_url: ?string,
enrolled: boolean,
total_courses: ?number,
courseware_backends: Array<string>,
enrollable_courseware_backends: Array<string>,
}

export type AvailablePrograms = Array<AvailableProgram>
Expand Down

0 comments on commit b56aeec

Please sign in to comment.