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
a830073b
Commit
a830073b
authored
Sep 21, 2017
by
Eric Fischer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add waffle flag for NewAssetsPage
parent
cc150813
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
294 additions
and
1 deletions
+294
-1
cms/djangoapps/contentstore/admin.py
+21
-1
cms/djangoapps/contentstore/config/__init__.py
+0
-0
cms/djangoapps/contentstore/config/forms.py
+37
-0
cms/djangoapps/contentstore/config/models.py
+77
-0
cms/djangoapps/contentstore/config/tests/__init__.py
+0
-0
cms/djangoapps/contentstore/config/tests/test_models.py
+92
-0
cms/djangoapps/contentstore/config/tests/utils.py
+27
-0
cms/djangoapps/contentstore/migrations/0002_add_assets_page_flag.py
+38
-0
cms/djangoapps/contentstore/views/assets.py
+2
-0
No files found.
cms/djangoapps/contentstore/admin.py
View file @
a830073b
...
...
@@ -2,10 +2,30 @@
Admin site bindings for contentstore
"""
from
config_models.admin
import
ConfigurationModelAdmin
from
config_models.admin
import
ConfigurationModelAdmin
,
KeyedConfigurationModelAdmin
from
django.contrib
import
admin
from
contentstore.config.forms
import
CourseNewAssetsPageAdminForm
from
contentstore.config.models
import
NewAssetsPageFlag
,
CourseNewAssetsPageFlag
from
contentstore.models
import
PushNotificationConfig
,
VideoUploadConfig
class
CourseNewAssetsPageAdmin
(
KeyedConfigurationModelAdmin
):
"""
Admin for enabling new asset page on a course-by-course basis.
Allows searching by course id.
"""
form
=
CourseNewAssetsPageAdminForm
search_fields
=
[
'course_id'
]
fieldsets
=
(
(
None
,
{
'fields'
:
(
'course_id'
,
'enabled'
),
'description'
:
'Enter a valid course id. If it is invalid, an error message will display.'
}),
)
admin
.
site
.
register
(
NewAssetsPageFlag
,
ConfigurationModelAdmin
)
admin
.
site
.
register
(
CourseNewAssetsPageFlag
,
CourseNewAssetsPageAdmin
)
admin
.
site
.
register
(
VideoUploadConfig
,
ConfigurationModelAdmin
)
admin
.
site
.
register
(
PushNotificationConfig
,
ConfigurationModelAdmin
)
cms/djangoapps/contentstore/config/__init__.py
0 → 100644
View file @
a830073b
cms/djangoapps/contentstore/config/forms.py
0 → 100644
View file @
a830073b
"""
Defines a form for providing validation.
"""
import
logging
from
django
import
forms
from
contentstore.config.models
import
CourseNewAssetsPageFlag
from
opaque_keys
import
InvalidKeyError
from
xmodule.modulestore.django
import
modulestore
from
opaque_keys.edx.locator
import
CourseLocator
log
=
logging
.
getLogger
(
__name__
)
class
CourseNewAssetsPageAdminForm
(
forms
.
ModelForm
):
"""Input form for new asset page enablment, allowing us to verify user input."""
class
Meta
(
object
):
model
=
CourseNewAssetsPageFlag
fields
=
'__all__'
def
clean_course_id
(
self
):
"""Validate the course id"""
cleaned_id
=
self
.
cleaned_data
[
"course_id"
]
try
:
course_key
=
CourseLocator
.
from_string
(
cleaned_id
)
except
InvalidKeyError
:
msg
=
u'Course id invalid. Entered course id was: "{0}."'
.
format
(
cleaned_id
)
raise
forms
.
ValidationError
(
msg
)
if
not
modulestore
()
.
has_course
(
course_key
):
msg
=
u'Course not found. Entered course id was: "{0}". '
.
format
(
course_key
.
to_deprecated_string
())
raise
forms
.
ValidationError
(
msg
)
return
course_key
cms/djangoapps/contentstore/config/models.py
0 → 100644
View file @
a830073b
"""
Models for configuration of the feature flags
controlling the new assets page.
"""
from
config_models.models
import
ConfigurationModel
from
django.db.models
import
BooleanField
from
openedx.core.djangoapps.xmodule_django.models
import
CourseKeyField
class
NewAssetsPageFlag
(
ConfigurationModel
):
"""
Enables the in-development new assets page from studio-frontend.
Defaults to False platform-wide, but can be overriden via a course-specific
flag. The idea is that we can use this to do a gradual rollout, and remove
the flag entirely once generally released to everyone.
"""
# this field overrides course-specific settings to enable the feature for all courses
enabled_for_all_courses
=
BooleanField
(
default
=
False
)
@classmethod
def
feature_enabled
(
cls
,
course_id
=
None
):
"""
Looks at the currently active configuration model to determine whether
the new assets page feature is available.
There are 2 booleans to be concerned with - enabled_for_all_courses,
and the implicit is_enabled(). They interact in the following ways:
- is_enabled: False, enabled_for_all_courses: True or False
- no one can use the feature.
- is_enabled: True, enabled_for_all_courses: False
- check for a CourseNewAssetsPageFlag, use that value (default False)
- if no course_id provided, return False
- is_enabled: True, enabled_for_all_courses: True
- everyone can use the feature
"""
if
not
NewAssetsPageFlag
.
is_enabled
():
return
False
elif
not
NewAssetsPageFlag
.
current
()
.
enabled_for_all_courses
:
if
course_id
:
effective
=
CourseNewAssetsPageFlag
.
objects
.
filter
(
course_id
=
course_id
)
.
order_by
(
'-change_date'
)
.
first
()
return
effective
.
enabled
if
effective
is
not
None
else
False
else
:
return
False
else
:
return
True
class
Meta
(
object
):
app_label
=
"contentstore"
def
__unicode__
(
self
):
current_model
=
NewAssetsPageFlag
.
current
()
return
u"NewAssetsPageFlag: enabled {}"
.
format
(
current_model
.
is_enabled
()
)
class
CourseNewAssetsPageFlag
(
ConfigurationModel
):
"""
Enables new assets page for a specific
course. Only has an effect if the general
flag above is set to True.
"""
KEY_FIELDS
=
(
'course_id'
,)
class
Meta
(
object
):
app_label
=
"contentstore"
# The course that these features are attached to.
course_id
=
CourseKeyField
(
max_length
=
255
,
db_index
=
True
)
def
__unicode__
(
self
):
not_en
=
"Not "
if
self
.
enabled
:
not_en
=
""
# pylint: disable=no-member
return
u"Course '{}': Persistent Grades {}Enabled"
.
format
(
self
.
course_id
.
to_deprecated_string
(),
not_en
)
cms/djangoapps/contentstore/config/tests/__init__.py
0 → 100644
View file @
a830073b
cms/djangoapps/contentstore/config/tests/test_models.py
0 → 100644
View file @
a830073b
"""
Tests for the models that control the
persistent grading feature.
"""
import
itertools
import
ddt
from
django.conf
import
settings
from
django.test
import
TestCase
from
mock
import
patch
from
opaque_keys.edx.locator
import
CourseLocator
from
contentstore.config.models
import
NewAssetsPageFlag
from
contentstore.config.tests.utils
import
new_assets_page_feature_flags
@ddt.ddt
class
NewAssetsPageFlagTests
(
TestCase
):
"""
Tests the behavior of the feature flags for the new assets page.
These are set via Django admin settings.
"""
def
setUp
(
self
):
super
(
NewAssetsPageFlagTests
,
self
)
.
setUp
()
self
.
course_id_1
=
CourseLocator
(
org
=
"edx"
,
course
=
"course"
,
run
=
"run"
)
self
.
course_id_2
=
CourseLocator
(
org
=
"edx"
,
course
=
"course2"
,
run
=
"run"
)
@ddt.data
(
*
itertools
.
product
(
(
True
,
False
),
(
True
,
False
),
(
True
,
False
),
))
@ddt.unpack
def
test_new_assets_page_feature_flags
(
self
,
global_flag
,
enabled_for_all_courses
,
enabled_for_course_1
):
with
new_assets_page_feature_flags
(
global_flag
=
global_flag
,
enabled_for_all_courses
=
enabled_for_all_courses
,
course_id
=
self
.
course_id_1
,
enabled_for_course
=
enabled_for_course_1
):
self
.
assertEqual
(
NewAssetsPageFlag
.
feature_enabled
(),
global_flag
and
enabled_for_all_courses
)
self
.
assertEqual
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
),
global_flag
and
(
enabled_for_all_courses
or
enabled_for_course_1
)
)
self
.
assertEqual
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_2
),
global_flag
and
enabled_for_all_courses
)
def
test_enable_disable_course_flag
(
self
):
"""
Ensures that the flag, once enabled for a course, can also be disabled.
"""
with
new_assets_page_feature_flags
(
global_flag
=
True
,
enabled_for_all_courses
=
False
,
course_id
=
self
.
course_id_1
,
enabled_for_course
=
True
):
self
.
assertTrue
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
))
with
new_assets_page_feature_flags
(
global_flag
=
True
,
enabled_for_all_courses
=
False
,
course_id
=
self
.
course_id_1
,
enabled_for_course
=
False
):
self
.
assertFalse
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
))
def
test_enable_disable_globally
(
self
):
"""
Ensures that the flag, once enabled globally, can also be disabled.
"""
with
new_assets_page_feature_flags
(
global_flag
=
True
,
enabled_for_all_courses
=
True
,
):
self
.
assertTrue
(
NewAssetsPageFlag
.
feature_enabled
())
self
.
assertTrue
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
))
with
new_assets_page_feature_flags
(
global_flag
=
True
,
enabled_for_all_courses
=
False
,
course_id
=
self
.
course_id_1
,
enabled_for_course
=
True
):
self
.
assertFalse
(
NewAssetsPageFlag
.
feature_enabled
())
self
.
assertTrue
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
))
with
new_assets_page_feature_flags
(
global_flag
=
False
,
):
self
.
assertFalse
(
NewAssetsPageFlag
.
feature_enabled
())
self
.
assertFalse
(
NewAssetsPageFlag
.
feature_enabled
(
self
.
course_id_1
))
cms/djangoapps/contentstore/config/tests/utils.py
0 → 100644
View file @
a830073b
"""
Provides helper functions for tests that want
to configure flags related to persistent grading.
"""
from
contextlib
import
contextmanager
from
contentstore.config.models
import
NewAssetsPageFlag
,
CourseNewAssetsPageFlag
from
request_cache.middleware
import
RequestCache
@contextmanager
def
new_assets_page_feature_flags
(
global_flag
,
enabled_for_all_courses
=
False
,
course_id
=
None
,
enabled_for_course
=
False
):
"""
Most test cases will use a single call to this manager,
as they need to set the global setting and the course-specific
setting for a single course.
"""
RequestCache
.
clear_request_cache
()
NewAssetsPageFlag
.
objects
.
create
(
enabled
=
global_flag
,
enabled_for_all_courses
=
enabled_for_all_courses
)
if
course_id
:
CourseNewAssetsPageFlag
.
objects
.
create
(
course_id
=
course_id
,
enabled
=
enabled_for_course
)
yield
cms/djangoapps/contentstore/migrations/0002_add_assets_page_flag.py
0 → 100644
View file @
a830073b
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
from
django.conf
import
settings
import
django.db.models.deletion
import
openedx.core.djangoapps.xmodule_django.models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
(
'contentstore'
,
'0001_initial'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'CourseNewAssetsPageFlag'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'change_date'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
'Change date'
)),
(
'enabled'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Enabled'
)),
(
'course_id'
,
openedx
.
core
.
djangoapps
.
xmodule_django
.
models
.
CourseKeyField
(
max_length
=
255
,
db_index
=
True
)),
(
'changed_by'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
PROTECT
,
editable
=
False
,
to
=
settings
.
AUTH_USER_MODEL
,
null
=
True
,
verbose_name
=
'Changed by'
)),
],
),
migrations
.
CreateModel
(
name
=
'NewAssetsPageFlag'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'change_date'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
'Change date'
)),
(
'enabled'
,
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Enabled'
)),
(
'enabled_for_all_courses'
,
models
.
BooleanField
(
default
=
False
)),
(
'changed_by'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
PROTECT
,
editable
=
False
,
to
=
settings
.
AUTH_USER_MODEL
,
null
=
True
,
verbose_name
=
'Changed by'
)),
],
),
]
cms/djangoapps/contentstore/views/assets.py
View file @
a830073b
...
...
@@ -18,6 +18,7 @@ from xmodule.exceptions import NotFoundError
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
contentstore.config.models
import
NewAssetsPageFlag
from
contentstore.utils
import
reverse_course_url
from
contentstore.views.exception
import
AssetNotFoundException
,
AssetSizeTooLargeException
from
edxmako.shortcuts
import
render_to_response
...
...
@@ -95,6 +96,7 @@ def _asset_index(course_key):
course_module
=
modulestore
()
.
get_course
(
course_key
)
return
render_to_response
(
'asset_index.html'
,
{
'waffle_flag_enabled'
:
NewAssetsPageFlag
.
feature_enabled
(
course_key
),
'context_course'
:
course_module
,
'max_file_size_in_mbs'
:
settings
.
MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB
,
'chunk_size_in_mbs'
:
settings
.
UPLOAD_CHUNK_SIZE_IN_MB
,
...
...
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