Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
58fea44f
Commit
58fea44f
authored
Jun 16, 2016
by
Bill DeRusha
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
HACK Course Modes - Add course mode configs for capability based mode definition
parent
75945b8c
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
216 additions
and
12 deletions
+216
-12
common/djangoapps/course_modes/admin.py
+13
-3
common/djangoapps/course_modes/migrations/0008_auto_20160617_1422.py
+46
-0
common/djangoapps/course_modes/models.py
+98
-6
common/djangoapps/student/migrations/0007_auto_20160617_1422.py
+48
-0
common/djangoapps/student/models.py
+8
-2
lms/djangoapps/commerce/api/v1/models.py
+3
-1
No files found.
common/djangoapps/course_modes/admin.py
View file @
58fea44f
...
...
@@ -14,7 +14,7 @@ from opaque_keys import InvalidKeyError
from
util.date_utils
import
get_time_display
from
xmodule.modulestore.django
import
modulestore
from
course_modes.models
import
CourseMode
,
CourseModeExpirationConfig
from
course_modes.models
import
CourseMode
,
CourseMode
Config
,
CourseMode
ExpirationConfig
# Technically, we shouldn't be doing this, since verify_student is defined
# in LMS, and course_modes is defined in common.
...
...
@@ -185,7 +185,8 @@ class CourseModeAdmin(admin.ModelAdmin):
'_expiration_datetime'
,
'verification_deadline'
,
'sku'
,
'bulk_sku'
'bulk_sku'
,
'course_mode_config'
,
)
search_fields
=
(
'course_id'
,)
...
...
@@ -197,7 +198,8 @@ class CourseModeAdmin(admin.ModelAdmin):
'min_price'
,
'expiration_datetime_custom'
,
'sku'
,
'bulk_sku'
'bulk_sku'
,
'course_mode_config'
,
)
def
expiration_datetime_custom
(
self
,
obj
):
...
...
@@ -216,5 +218,13 @@ class CourseModeExpirationConfigAdmin(admin.ModelAdmin):
class
Meta
(
object
):
model
=
CourseModeExpirationConfig
class
CourseModeConfigAdmin
(
admin
.
ModelAdmin
):
"""Admin interface for the course mode auto expiration configuration. """
class
Meta
(
object
):
model
=
CourseModeConfig
admin
.
site
.
register
(
CourseMode
,
CourseModeAdmin
)
admin
.
site
.
register
(
CourseModeExpirationConfig
,
CourseModeExpirationConfigAdmin
)
admin
.
site
.
register
(
CourseModeConfig
,
CourseModeConfigAdmin
)
common/djangoapps/course_modes/migrations/0008_auto_20160617_1422.py
0 → 100644
View file @
58fea44f
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.utils.timezone
import
model_utils.fields
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_modes'
,
'0007_coursemode_bulk_sku'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'CourseModeConfig'
,
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
)),
(
'name'
,
models
.
CharField
(
max_length
=
100
)),
(
'display_name'
,
models
.
CharField
(
max_length
=
255
)),
(
'certificate'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Certificate'
)),
(
'id_verification'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'ID Verification'
)),
(
'credit_eligible'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Credit Eligible'
)),
(
'cohort'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Cohort'
)),
(
'upsell_course_mode'
,
models
.
ForeignKey
(
default
=
None
,
blank
=
True
,
to
=
'course_modes.CourseModeConfig'
,
null
=
True
,
verbose_name
=
'Upsell Course Mode Config'
)),
],
),
migrations
.
AddField
(
model_name
=
'coursemode'
,
name
=
'created'
,
field
=
model_utils
.
fields
.
AutoCreatedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'created'
,
editable
=
False
),
),
migrations
.
AddField
(
model_name
=
'coursemode'
,
name
=
'modified'
,
field
=
model_utils
.
fields
.
AutoLastModifiedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'modified'
,
editable
=
False
),
),
migrations
.
AddField
(
model_name
=
'coursemode'
,
name
=
'course_mode_config'
,
field
=
models
.
ForeignKey
(
default
=
None
,
blank
=
True
,
to
=
'course_modes.CourseModeConfig'
,
null
=
True
,
verbose_name
=
'Course Mode Config'
),
),
]
common/djangoapps/course_modes/models.py
View file @
58fea44f
...
...
@@ -10,6 +10,7 @@ from django.core.exceptions import ValidationError
from
django.db
import
models
from
django.db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
model_utils.models
import
TimeStampedModel
from
xmodule_django.models
import
CourseKeyField
Mode
=
namedtuple
(
'Mode'
,
...
...
@@ -26,7 +27,7 @@ Mode = namedtuple('Mode',
])
class
CourseMode
(
models
.
Model
):
class
CourseMode
(
TimeStamped
Model
):
"""
We would like to offer a course in a variety of modes.
...
...
@@ -109,12 +110,20 @@ class CourseMode(models.Model):
)
)
course_mode_config
=
models
.
ForeignKey
(
'CourseModeConfig'
,
null
=
True
,
blank
=
True
,
default
=
None
,
verbose_name
=
_
(
"Course Mode Config"
)
)
HONOR
=
'honor'
PROFESSIONAL
=
'professional'
VERIFIED
=
"verified"
AUDIT
=
"audit"
NO_ID_PROFESSIONAL_MODE
=
"no-id-professional"
CREDIT_MODE
=
"credit"
VERIFIED
=
'verified'
AUDIT
=
'audit'
NO_ID_PROFESSIONAL_MODE
=
'no-id-professional'
CREDIT_MODE
=
'credit'
DEFAULT_MODE
=
Mode
(
AUDIT
,
_
(
'Audit'
),
0
,
''
,
'usd'
,
None
,
None
,
None
,
None
)
DEFAULT_MODE_SLUG
=
AUDIT
...
...
@@ -125,6 +134,8 @@ class CourseMode(models.Model):
# Modes that allow a student to pursue a non-verified certificate
NON_VERIFIED_MODES
=
[
HONOR
,
AUDIT
,
NO_ID_PROFESSIONAL_MODE
]
CERTIFICATE_GRANTING_MODES
=
[
VERIFIED
,
PROFESSIONAL
,
NO_ID_PROFESSIONAL_MODE
]
# Modes that allow a student to earn credit with a university partner
CREDIT_MODES
=
[
CREDIT_MODE
]
...
...
@@ -167,7 +178,11 @@ class CourseMode(models.Model):
NOTE (CCB): This is a silly hack needed because all of the class methods use tuples
with a property named slug instead of mode_slug.
"""
return
self
.
mode_slug
course_mode_config
=
self
.
course_mode_config
if
course_mode_config
:
return
course_mode_config
.
name
else
:
return
self
.
mode_slug
@property
def
expiration_datetime
(
self
):
...
...
@@ -182,6 +197,50 @@ class CourseMode(models.Model):
self
.
expiration_datetime_is_explicit
=
True
self
.
_expiration_datetime
=
new_datetime
@property
def
has_id_verification
(
self
):
"""
Returns whether or not the course_mode allows id verification.
"""
course_mode_config
=
self
.
course_mode_config
if
course_mode_config
:
return
course_mode_config
.
id_verification
else
:
return
self
.
mode_slug
in
self
.
VERIFIED_MODES
@property
def
has_certificate
(
self
):
"""
Returns whether or not the course_mode grants a certificate.
"""
course_mode_config
=
self
.
course_mode_config
if
course_mode_config
:
return
course_mode_config
.
certificate
else
:
return
self
.
mode_slug
in
self
.
CERTIFICATE_GRANTING_MODES
@property
def
has_cohorting
(
self
):
"""
Returns whether or not the course_mode allows cohorting by mode.
"""
course_mode_config
=
self
.
course_mode_config
if
course_mode_config
:
return
course_mode_config
.
cohort
else
:
return
self
.
mode_slug
==
self
.
VERIFIED
@property
def
is_credit_eligible
(
self
):
"""
Returns whether or not the course_mode is credit eligible.
"""
course_mode_config
=
self
.
course_mode_config
if
course_mode_config
:
return
course_mode_config
.
credit_eligible
else
:
return
self
.
mode_slug
in
self
.
CREDIT_MODES
@classmethod
def
all_modes_for_courses
(
cls
,
course_id_list
):
"""Find all modes for a list of course IDs, including expired modes.
...
...
@@ -700,3 +759,36 @@ class CourseModeExpirationConfig(ConfigurationModel):
def
__unicode__
(
self
):
""" Returns the unicode date of the verification window. """
return
unicode
(
self
.
verification_window
)
class
CourseModeConfig
(
TimeStampedModel
):
"""
Configure course mode type capabilites.
"""
class
Meta
(
object
):
app_label
=
"course_modes"
name
=
models
.
CharField
(
max_length
=
100
)
display_name
=
models
.
CharField
(
max_length
=
255
)
certificate
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
"Certificate"
))
id_verification
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
"ID Verification"
))
upsell_course_mode
=
models
.
ForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
default
=
None
,
# Translators: this label indicates the course_mode config which this course_mode config can progress to:
verbose_name
=
_
(
"Upsell Course Mode Config"
),
)
credit_eligible
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
"Credit Eligible"
))
cohort
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
"Cohort"
))
def
__unicode__
(
self
):
""" Returns the unicode date of the verification window. """
return
unicode
(
self
.
name
)
common/djangoapps/student/migrations/0007_auto_20160617_1422.py
0 → 100644
View file @
58fea44f
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
django.utils.timezone
import
model_utils.fields
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_modes'
,
'0008_auto_20160617_1422'
),
(
'student'
,
'0006_logoutviewconfiguration'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'courseenrollment'
,
name
=
'course_mode'
,
field
=
models
.
ForeignKey
(
verbose_name
=
'Course Mode'
,
blank
=
True
,
to
=
'course_modes.CourseMode'
,
null
=
True
),
),
migrations
.
AddField
(
model_name
=
'courseenrollment'
,
name
=
'modified'
,
field
=
model_utils
.
fields
.
AutoLastModifiedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'modified'
,
editable
=
False
),
),
migrations
.
AddField
(
model_name
=
'historicalcourseenrollment'
,
name
=
'course_mode'
,
field
=
models
.
ForeignKey
(
related_name
=
'+'
,
on_delete
=
django
.
db
.
models
.
deletion
.
DO_NOTHING
,
db_constraint
=
False
,
blank
=
True
,
to
=
'course_modes.CourseMode'
,
null
=
True
),
),
migrations
.
AddField
(
model_name
=
'historicalcourseenrollment'
,
name
=
'modified'
,
field
=
model_utils
.
fields
.
AutoLastModifiedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'modified'
,
editable
=
False
),
),
migrations
.
AlterField
(
model_name
=
'courseenrollment'
,
name
=
'created'
,
field
=
model_utils
.
fields
.
AutoCreatedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'created'
,
editable
=
False
),
),
migrations
.
AlterField
(
model_name
=
'historicalcourseenrollment'
,
name
=
'created'
,
field
=
model_utils
.
fields
.
AutoCreatedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'created'
,
editable
=
False
),
),
]
common/djangoapps/student/models.py
View file @
58fea44f
...
...
@@ -951,7 +951,7 @@ class CourseEnrollmentManager(models.Manager):
)
class
CourseEnrollment
(
models
.
Model
):
class
CourseEnrollment
(
TimeStamped
Model
):
"""
Represents a Student's Enrollment record for a single Course. You should
generally not manipulate CourseEnrollment objects directly, but use the
...
...
@@ -967,7 +967,6 @@ class CourseEnrollment(models.Model):
user
=
models
.
ForeignKey
(
User
)
course_id
=
CourseKeyField
(
max_length
=
255
,
db_index
=
True
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
# If is_active is False, then the student is not considered to be enrolled
# in the course (is_enrolled() will return False)
...
...
@@ -977,6 +976,13 @@ class CourseEnrollment(models.Model):
# list of possible values.
mode
=
models
.
CharField
(
default
=
CourseMode
.
DEFAULT_MODE_SLUG
,
max_length
=
100
)
course_mode
=
models
.
ForeignKey
(
CourseMode
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
"Course Mode"
)
)
objects
=
CourseEnrollmentManager
()
# Maintain a history of requirement status updates for auditing purposes
...
...
lms/djangoapps/commerce/api/v1/models.py
View file @
58fea44f
...
...
@@ -6,7 +6,7 @@ from django.db import transaction
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
from
openedx.core.djangoapps.content.course_overviews.models
import
CourseOverview
from
course_modes.models
import
CourseMode
from
course_modes.models
import
CourseMode
,
CourseModeConfig
from
lms.djangoapps.verify_student.models
import
VerificationDeadline
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -80,7 +80,9 @@ class Course(object):
for
posted_mode
in
attrs
.
get
(
'modes'
,
[]):
merged_mode
=
existing_modes
.
get
(
posted_mode
.
mode_slug
,
CourseMode
())
course_mode_config
=
CourseModeConfig
.
objects
.
filter
(
name
=
posted_mode
.
mode_slug
)
.
first
()
merged_mode
.
course_mode_config
=
course_mode_config
merged_mode
.
course_id
=
self
.
id
merged_mode
.
mode_slug
=
posted_mode
.
mode_slug
merged_mode
.
mode_display_name
=
posted_mode
.
mode_slug
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment