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
a8084628
Commit
a8084628
authored
May 23, 2013
by
chrisndodge
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1956 from edx/feature/cdodge/autoprovision-forums-master
Feature/cdodge/autoprovision forums master
parents
257dae63
e6a1a9fa
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
303 additions
and
147 deletions
+303
-147
cms/djangoapps/contentstore/tests/test_contentstore.py
+28
-18
cms/djangoapps/contentstore/views/course.py
+12
-9
cms/envs/common.py
+3
-0
cms/envs/dev.py
+1
-2
common/djangoapps/django_comment_common/__init__.py
+0
-0
common/djangoapps/django_comment_common/migrations/0001_initial.py
+92
-0
common/djangoapps/django_comment_common/migrations/__init__.py
+0
-0
common/djangoapps/django_comment_common/models.py
+74
-0
common/djangoapps/django_comment_common/utils.py
+56
-0
common/lib/xmodule/xmodule/modulestore/__init__.py
+9
-15
common/lib/xmodule/xmodule/modulestore/draft.py
+1
-0
common/lib/xmodule/xmodule/modulestore/tests/factories.py
+0
-1
lms/djangoapps/django_comment_client/base/views.py
+1
-1
lms/djangoapps/django_comment_client/management/commands/assign_role.py
+1
-1
lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py
+1
-1
lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py
+1
-1
lms/djangoapps/django_comment_client/management/commands/seed_permissions_roles.py
+2
-24
lms/djangoapps/django_comment_client/management/commands/show_permissions.py
+1
-0
lms/djangoapps/django_comment_client/models.py
+1
-64
lms/djangoapps/django_comment_client/permissions.py
+1
-1
lms/djangoapps/django_comment_client/tests.py
+1
-1
lms/djangoapps/django_comment_client/tests/factories.py
+1
-1
lms/djangoapps/django_comment_client/tests/test_models.py
+1
-1
lms/djangoapps/django_comment_client/tests/test_utils.py
+1
-1
lms/djangoapps/django_comment_client/utils.py
+1
-1
lms/djangoapps/instructor/tests/test_forum_admin.py
+1
-1
lms/djangoapps/instructor/views.py
+1
-1
lms/envs/common.py
+1
-2
rakefiles/tests.rake
+10
-0
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
a8084628
...
...
@@ -34,6 +34,8 @@ from xmodule.course_module import CourseDescriptor
from
xmodule.seq_module
import
SequenceDescriptor
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
django_comment_common.utils
import
are_permissions_roles_seeded
TEST_DATA_MODULESTORE
=
copy
.
deepcopy
(
settings
.
MODULESTORE
)
TEST_DATA_MODULESTORE
[
'default'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
TEST_DATA_MODULESTORE
[
'direct'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
...
...
@@ -45,7 +47,7 @@ class MongoCollectionFindWrapper(object):
self
.
counter
=
0
def
find
(
self
,
query
,
*
args
,
**
kwargs
):
self
.
counter
=
self
.
counter
+
1
self
.
counter
=
self
.
counter
+
1
return
self
.
original
(
query
,
*
args
,
**
kwargs
)
...
...
@@ -352,7 +354,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
clone_items
=
module_store
.
get_items
(
Location
([
'i4x'
,
'MITx'
,
'999'
,
'vertical'
,
None
]))
self
.
assertGreater
(
len
(
clone_items
),
0
)
for
descriptor
in
items
:
new_loc
=
descriptor
.
location
.
_
replace
(
org
=
'MITx'
,
course
=
'999'
)
new_loc
=
descriptor
.
location
.
replace
(
org
=
'MITx'
,
course
=
'999'
)
print
"Checking {0} should now also be at {1}"
.
format
(
descriptor
.
location
.
url
(),
new_loc
.
url
())
resp
=
self
.
client
.
get
(
reverse
(
'edit_unit'
,
kwargs
=
{
'location'
:
new_loc
.
url
()}))
self
.
assertEqual
(
resp
.
status_code
,
200
)
...
...
@@ -375,15 +377,15 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
self
.
assertEqual
(
len
(
items
),
0
)
def
verify_content_existence
(
self
,
modulestore
,
root_dir
,
location
,
dirname
,
category_name
,
filename_suffix
=
''
):
f
s
=
OSFS
(
root_dir
/
'test_export'
)
self
.
assertTrue
(
f
s
.
exists
(
dirname
))
f
ilesystem
=
OSFS
(
root_dir
/
'test_export'
)
self
.
assertTrue
(
f
ilesystem
.
exists
(
dirname
))
query_loc
=
Location
(
'i4x'
,
location
.
org
,
location
.
course
,
category_name
,
None
)
items
=
modulestore
.
get_items
(
query_loc
)
for
item
in
items
:
f
s
=
OSFS
(
root_dir
/
(
'test_export/'
+
dirname
))
self
.
assertTrue
(
f
s
.
exists
(
item
.
location
.
name
+
filename_suffix
))
f
ilesystem
=
OSFS
(
root_dir
/
(
'test_export/'
+
dirname
))
self
.
assertTrue
(
f
ilesystem
.
exists
(
item
.
location
.
name
+
filename_suffix
))
def
test_export_course
(
self
):
module_store
=
modulestore
(
'direct'
)
...
...
@@ -415,7 +417,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# add private to list of children
sequential
=
module_store
.
get_item
(
Location
([
'i4x'
,
'edX'
,
'full'
,
'sequential'
,
'Administrivia_and_Circuit_Elements'
,
None
]))
private_location_no_draft
=
private_vertical
.
location
.
_
replace
(
revision
=
None
)
private_location_no_draft
=
private_vertical
.
location
.
replace
(
revision
=
None
)
module_store
.
update_children
(
sequential
.
location
,
sequential
.
children
+
[
private_location_no_draft
.
url
()])
...
...
@@ -440,20 +442,20 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
self
.
verify_content_existence
(
module_store
,
root_dir
,
location
,
'custom_tags'
,
'custom_tag_template'
)
# check for graiding_policy.json
f
s
=
OSFS
(
root_dir
/
'test_export/policies/6.002_Spring_2012'
)
self
.
assertTrue
(
f
s
.
exists
(
'grading_policy.json'
))
f
ilesystem
=
OSFS
(
root_dir
/
'test_export/policies/6.002_Spring_2012'
)
self
.
assertTrue
(
f
ilesystem
.
exists
(
'grading_policy.json'
))
course
=
module_store
.
get_item
(
location
)
# compare what's on disk compared to what we have in our course
with
f
s
.
open
(
'grading_policy.json'
,
'r'
)
as
grading_policy
:
with
f
ilesystem
.
open
(
'grading_policy.json'
,
'r'
)
as
grading_policy
:
on_disk
=
loads
(
grading_policy
.
read
())
self
.
assertEqual
(
on_disk
,
course
.
grading_policy
)
#check for policy.json
self
.
assertTrue
(
f
s
.
exists
(
'policy.json'
))
self
.
assertTrue
(
f
ilesystem
.
exists
(
'policy.json'
))
# compare what's on disk to what we have in the course module
with
f
s
.
open
(
'policy.json'
,
'r'
)
as
course_policy
:
with
f
ilesystem
.
open
(
'policy.json'
,
'r'
)
as
course_policy
:
on_disk
=
loads
(
course_policy
.
read
())
self
.
assertIn
(
'course/6.002_Spring_2012'
,
on_disk
)
self
.
assertEqual
(
on_disk
[
'course/6.002_Spring_2012'
],
own_metadata
(
course
))
...
...
@@ -608,6 +610,14 @@ class ContentStoreTest(ModuleStoreTestCase):
data
=
parse_json
(
resp
)
self
.
assertEqual
(
data
[
'id'
],
'i4x://MITx/999/course/Robot_Super_Course'
)
def
test_create_course_check_forum_seeding
(
self
):
"""Test new course creation and verify forum seeding """
resp
=
self
.
client
.
post
(
reverse
(
'create_new_course'
),
self
.
course_data
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
data
=
parse_json
(
resp
)
self
.
assertEqual
(
data
[
'id'
],
'i4x://MITx/999/course/Robot_Super_Course'
)
self
.
assertTrue
(
are_permissions_roles_seeded
(
'MITx/999/Robot_Super_Course'
))
def
test_create_course_duplicate_course
(
self
):
"""Test new course creation - error path"""
resp
=
self
.
client
.
post
(
reverse
(
'create_new_course'
),
self
.
course_data
)
...
...
@@ -801,37 +811,37 @@ class ContentStoreTest(ModuleStoreTestCase):
self
.
assertEqual
(
200
,
resp
.
status_code
)
# go look at a subsection page
subsection_location
=
loc
.
_
replace
(
category
=
'sequential'
,
name
=
'test_sequence'
)
subsection_location
=
loc
.
replace
(
category
=
'sequential'
,
name
=
'test_sequence'
)
resp
=
self
.
client
.
get
(
reverse
(
'edit_subsection'
,
kwargs
=
{
'location'
:
subsection_location
.
url
()}))
self
.
assertEqual
(
200
,
resp
.
status_code
)
# go look at the Edit page
unit_location
=
loc
.
_
replace
(
category
=
'vertical'
,
name
=
'test_vertical'
)
unit_location
=
loc
.
replace
(
category
=
'vertical'
,
name
=
'test_vertical'
)
resp
=
self
.
client
.
get
(
reverse
(
'edit_unit'
,
kwargs
=
{
'location'
:
unit_location
.
url
()}))
self
.
assertEqual
(
200
,
resp
.
status_code
)
# delete a component
del_loc
=
loc
.
_
replace
(
category
=
'html'
,
name
=
'test_html'
)
del_loc
=
loc
.
replace
(
category
=
'html'
,
name
=
'test_html'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
200
,
resp
.
status_code
)
# delete a unit
del_loc
=
loc
.
_
replace
(
category
=
'vertical'
,
name
=
'test_vertical'
)
del_loc
=
loc
.
replace
(
category
=
'vertical'
,
name
=
'test_vertical'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
200
,
resp
.
status_code
)
# delete a unit
del_loc
=
loc
.
_
replace
(
category
=
'sequential'
,
name
=
'test_sequence'
)
del_loc
=
loc
.
replace
(
category
=
'sequential'
,
name
=
'test_sequence'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
200
,
resp
.
status_code
)
# delete a chapter
del_loc
=
loc
.
_
replace
(
category
=
'chapter'
,
name
=
'chapter_2'
)
del_loc
=
loc
.
replace
(
category
=
'chapter'
,
name
=
'chapter_2'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
200
,
resp
.
status_code
)
...
...
cms/djangoapps/contentstore/views/course.py
View file @
a8084628
...
...
@@ -13,17 +13,13 @@ from django.core.urlresolvers import reverse
from
mitxmako.shortcuts
import
render_to_response
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
\
import
ItemNotFoundError
,
InvalidLocationError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
InvalidLocationError
from
xmodule.modulestore
import
Location
from
contentstore.course_info_model
\
import
get_course_updates
,
update_course_updates
,
delete_course_update
from
contentstore.utils
\
import
get_lms_link_for_item
,
add_extra_panel_tab
,
\
remove_extra_panel_tab
from
models.settings.course_details
\
import
CourseDetails
,
CourseSettingsEncoder
from
contentstore.course_info_model
import
get_course_updates
,
update_course_updates
,
delete_course_update
from
contentstore.utils
import
get_lms_link_for_item
,
add_extra_panel_tab
,
remove_extra_panel_tab
from
models.settings.course_details
import
CourseDetails
,
CourseSettingsEncoder
from
models.settings.course_grading
import
CourseGradingModel
from
models.settings.course_metadata
import
CourseMetadata
from
auth.authz
import
create_all_course_groups
...
...
@@ -35,6 +31,10 @@ from .tabs import initialize_course_tabs
from
.component
import
OPEN_ENDED_COMPONENT_TYPES
,
\
NOTE_COMPONENT_TYPES
,
ADVANCED_COMPONENT_POLICY_KEY
from
django_comment_common.utils
import
seed_permissions_roles
# TODO: should explicitly enumerate exports with __all__
__all__
=
[
'course_index'
,
'create_new_course'
,
'course_info'
,
'course_info_updates'
,
'get_course_settings'
,
'course_config_graders_page'
,
...
...
@@ -136,6 +136,9 @@ def create_new_course(request):
create_all_course_groups
(
request
.
user
,
new_course
.
location
)
# seed the forums
seed_permissions_roles
(
new_course
.
location
.
course_id
)
return
HttpResponse
(
json
.
dumps
({
'id'
:
new_course
.
location
.
url
()}))
...
...
cms/envs/common.py
View file @
a8084628
...
...
@@ -322,6 +322,9 @@ INSTALLED_APPS = (
'pipeline'
,
'staticfiles'
,
'static_replace'
,
# comment common
'django_comment_common'
,
)
################# EDX MARKETING SITE ##################################
...
...
cms/envs/dev.py
View file @
a8084628
...
...
@@ -127,8 +127,7 @@ CELERY_ALWAYS_EAGER = True
################################ DEBUG TOOLBAR #################################
INSTALLED_APPS
+=
(
'debug_toolbar'
,
'debug_toolbar_mongo'
)
MIDDLEWARE_CLASSES
+=
(
'django_comment_client.utils.QueryCountDebugMiddleware'
,
'debug_toolbar.middleware.DebugToolbarMiddleware'
,)
MIDDLEWARE_CLASSES
+=
(
'debug_toolbar.middleware.DebugToolbarMiddleware'
,)
INTERNAL_IPS
=
(
'127.0.0.1'
,)
DEBUG_TOOLBAR_PANELS
=
(
...
...
common/djangoapps/django_comment_common/__init__.py
0 → 100644
View file @
a8084628
common/djangoapps/django_comment_common/migrations/0001_initial.py
0 → 100644
View file @
a8084628
# -*- coding: utf-8 -*-
from
south.v2
import
SchemaMigration
class
Migration
(
SchemaMigration
):
#
# cdodge: This is basically an empty migration since everything has - up to now - managed in the django_comment_client app
# But going forward we should be using this migration
#
def
forwards
(
self
,
orm
):
pass
def
backwards
(
self
,
orm
):
pass
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'about'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'avatar_type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'n'"
,
'max_length'
:
'1'
}),
'bronze'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'consecutive_days_visit_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'country'
:
(
'django_countries.fields.CountryField'
,
[],
{
'max_length'
:
'2'
,
'blank'
:
'True'
}),
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'date_of_birth'
:
(
'django.db.models.fields.DateField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'display_tag_filter_strategy'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'email_isvalid'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'email_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'null'
:
'True'
}),
'email_tag_filter_strategy'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'1'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'gold'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'gravatar'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ignored_tags'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'interesting_tags'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'last_seen'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'location'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'new_response_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'questions_per_page'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'10'
}),
'real_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'reputation'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'default'
:
'1'
}),
'seen_response_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'show_country'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'silver'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'w'"
,
'max_length'
:
'2'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
}),
'website'
:
(
'django.db.models.fields.URLField'
,
[],
{
'max_length'
:
'200'
,
'blank'
:
'True'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
'django_comment_common.permission'
:
{
'Meta'
:
{
'object_name'
:
'Permission'
},
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'primary_key'
:
'True'
}),
'roles'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"'permissions'"
,
'symmetrical'
:
'False'
,
'to'
:
"orm['django_comment_common.Role']"
})
},
'django_comment_common.role'
:
{
'Meta'
:
{
'object_name'
:
'Role'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
}),
'users'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"'roles'"
,
'symmetrical'
:
'False'
,
'to'
:
"orm['auth.User']"
})
}
}
complete_apps
=
[
'django_comment_common'
]
common/djangoapps/django_comment_common/migrations/__init__.py
0 → 100644
View file @
a8084628
common/djangoapps/django_comment_common/models.py
0 → 100644
View file @
a8084628
import
logging
from
django.db
import
models
from
django.contrib.auth.models
import
User
from
django.dispatch
import
receiver
from
django.db.models.signals
import
post_save
from
student.models
import
CourseEnrollment
from
xmodule.modulestore.django
import
modulestore
from
xmodule.course_module
import
CourseDescriptor
FORUM_ROLE_ADMINISTRATOR
=
'Administrator'
FORUM_ROLE_MODERATOR
=
'Moderator'
FORUM_ROLE_COMMUNITY_TA
=
'Community TA'
FORUM_ROLE_STUDENT
=
'Student'
@receiver
(
post_save
,
sender
=
CourseEnrollment
)
def
assign_default_role
(
sender
,
instance
,
**
kwargs
):
if
instance
.
user
.
is_staff
:
role
=
Role
.
objects
.
get_or_create
(
course_id
=
instance
.
course_id
,
name
=
"Moderator"
)[
0
]
else
:
role
=
Role
.
objects
.
get_or_create
(
course_id
=
instance
.
course_id
,
name
=
"Student"
)[
0
]
logging
.
info
(
"assign_default_role: adding
%
s as
%
s"
%
(
instance
.
user
,
role
))
instance
.
user
.
roles
.
add
(
role
)
class
Role
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
30
,
null
=
False
,
blank
=
False
)
users
=
models
.
ManyToManyField
(
User
,
related_name
=
"roles"
)
course_id
=
models
.
CharField
(
max_length
=
255
,
blank
=
True
,
db_index
=
True
)
class
Meta
:
# use existing table that was originally created from django_comment_client app
db_table
=
'django_comment_client_role'
def
__unicode__
(
self
):
return
self
.
name
+
" for "
+
(
self
.
course_id
if
self
.
course_id
else
"all courses"
)
def
inherit_permissions
(
self
,
role
):
# TODO the name of this method is a little bit confusing,
# since it's one-off and doesn't handle inheritance later
if
role
.
course_id
and
role
.
course_id
!=
self
.
course_id
:
logging
.
warning
(
"
%
s cannot inherit permissions from
%
s due to course_id inconsistency"
,
\
self
,
role
)
for
per
in
role
.
permissions
.
all
():
self
.
add_permission
(
per
)
def
add_permission
(
self
,
permission
):
self
.
permissions
.
add
(
Permission
.
objects
.
get_or_create
(
name
=
permission
)[
0
])
def
has_permission
(
self
,
permission
):
course_loc
=
CourseDescriptor
.
id_to_location
(
self
.
course_id
)
course
=
modulestore
()
.
get_instance
(
self
.
course_id
,
course_loc
)
if
self
.
name
==
FORUM_ROLE_STUDENT
and
\
(
permission
.
startswith
(
'edit'
)
or
permission
.
startswith
(
'update'
)
or
permission
.
startswith
(
'create'
))
and
\
(
not
course
.
forum_posts_allowed
):
return
False
return
self
.
permissions
.
filter
(
name
=
permission
)
.
exists
()
class
Permission
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
30
,
null
=
False
,
blank
=
False
,
primary_key
=
True
)
roles
=
models
.
ManyToManyField
(
Role
,
related_name
=
"permissions"
)
class
Meta
:
# use existing table that was originally created from django_comment_client app
db_table
=
'django_comment_client_permission'
def
__unicode__
(
self
):
return
self
.
name
common/djangoapps/django_comment_common/utils.py
0 → 100644
View file @
a8084628
from
django_comment_common.models
import
Role
_STUDENT_ROLE_PERMISSIONS
=
[
"vote"
,
"update_thread"
,
"follow_thread"
,
"unfollow_thread"
,
"update_comment"
,
"create_sub_comment"
,
"unvote"
,
"create_thread"
,
"follow_commentable"
,
"unfollow_commentable"
,
"create_comment"
,
]
_MODERATOR_ROLE_PERMISSIONS
=
[
"edit_content"
,
"delete_thread"
,
"openclose_thread"
,
"endorse_comment"
,
"delete_comment"
,
"see_all_cohorts"
]
_ADMINISTRATOR_ROLE_PERMISSIONS
=
[
"manage_moderator"
]
def
seed_permissions_roles
(
course_id
):
administrator_role
=
Role
.
objects
.
get_or_create
(
name
=
"Administrator"
,
course_id
=
course_id
)[
0
]
moderator_role
=
Role
.
objects
.
get_or_create
(
name
=
"Moderator"
,
course_id
=
course_id
)[
0
]
community_ta_role
=
Role
.
objects
.
get_or_create
(
name
=
"Community TA"
,
course_id
=
course_id
)[
0
]
student_role
=
Role
.
objects
.
get_or_create
(
name
=
"Student"
,
course_id
=
course_id
)[
0
]
for
per
in
_STUDENT_ROLE_PERMISSIONS
:
student_role
.
add_permission
(
per
)
for
per
in
_MODERATOR_ROLE_PERMISSIONS
:
moderator_role
.
add_permission
(
per
)
for
per
in
_ADMINISTRATOR_ROLE_PERMISSIONS
:
administrator_role
.
add_permission
(
per
)
moderator_role
.
inherit_permissions
(
student_role
)
# For now, Community TA == Moderator, except for the styling.
community_ta_role
.
inherit_permissions
(
moderator_role
)
administrator_role
.
inherit_permissions
(
moderator_role
)
def
are_permissions_roles_seeded
(
course_id
):
try
:
administrator_role
=
Role
.
objects
.
get
(
name
=
"Administrator"
,
course_id
=
course_id
)
moderator_role
=
Role
.
objects
.
get
(
name
=
"Moderator"
,
course_id
=
course_id
)
student_role
=
Role
.
objects
.
get
(
name
=
"Student"
,
course_id
=
course_id
)
except
:
return
False
for
per
in
_STUDENT_ROLE_PERMISSIONS
:
if
not
student_role
.
has_permission
(
per
):
return
False
for
per
in
_MODERATOR_ROLE_PERMISSIONS
+
_STUDENT_ROLE_PERMISSIONS
:
if
not
moderator_role
.
has_permission
(
per
):
return
False
for
per
in
_ADMINISTRATOR_ROLE_PERMISSIONS
+
_MODERATOR_ROLE_PERMISSIONS
+
_STUDENT_ROLE_PERMISSIONS
:
if
not
administrator_role
.
has_permission
(
per
):
return
False
return
True
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
a8084628
...
...
@@ -9,7 +9,7 @@ import re
from
collections
import
namedtuple
from
.exceptions
import
InvalidLocationError
,
InsufficientSpecificationError
from
xmodule.errortracker
import
ErrorLog
,
make_error_tracker
from
xmodule.errortracker
import
make_error_tracker
from
bson.son
import
SON
log
=
logging
.
getLogger
(
'mitx.'
+
'modulestore'
)
...
...
@@ -64,7 +64,6 @@ class Location(_LocationBase):
"""
return
re
.
sub
(
'_+'
,
'_'
,
invalid
.
sub
(
'_'
,
value
))
@staticmethod
def
clean
(
value
):
"""
...
...
@@ -72,7 +71,6 @@ class Location(_LocationBase):
"""
return
Location
.
_clean
(
value
,
INVALID_CHARS
)
@staticmethod
def
clean_keeping_underscores
(
value
):
"""
...
...
@@ -82,7 +80,6 @@ class Location(_LocationBase):
"""
return
INVALID_CHARS
.
sub
(
'_'
,
value
)
@staticmethod
def
clean_for_url_name
(
value
):
"""
...
...
@@ -154,9 +151,7 @@ class Location(_LocationBase):
to mean wildcard selection.
"""
if
(
org
is
None
and
course
is
None
and
category
is
None
and
name
is
None
and
revision
is
None
):
if
(
org
is
None
and
course
is
None
and
category
is
None
and
name
is
None
and
revision
is
None
):
location
=
loc_or_tag
else
:
location
=
(
loc_or_tag
,
org
,
course
,
category
,
name
,
revision
)
...
...
@@ -258,6 +253,12 @@ class Location(_LocationBase):
at the location URL hierachy"""
return
"/"
.
join
([
self
.
org
,
self
.
course
,
self
.
name
])
def
replace
(
self
,
**
kwargs
):
'''
Expose a public method for replacing location elements
'''
return
self
.
_replace
(
**
kwargs
)
class
ModuleStore
(
object
):
"""
...
...
@@ -382,12 +383,6 @@ class ModuleStore(object):
'''
raise
NotImplementedError
def
get_course
(
self
,
course_id
):
'''
Look for a specific course id. Returns the course descriptor, or None if not found.
'''
raise
NotImplementedError
def
get_parent_locations
(
self
,
location
,
course_id
):
'''Find all locations that are the parents of this location in this
course. Needed for path_to_location().
...
...
@@ -406,8 +401,7 @@ class ModuleStore(object):
courses
=
[
course
for
course
in
self
.
get_courses
()
if
course
.
location
.
org
==
location
.
org
and
course
.
location
.
course
==
location
.
course
if
course
.
location
.
org
==
location
.
org
and
course
.
location
.
course
==
location
.
course
]
return
courses
...
...
common/lib/xmodule/xmodule/modulestore/draft.py
View file @
a8084628
...
...
@@ -13,6 +13,7 @@ def as_draft(location):
"""
return
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
def
as_published
(
location
):
"""
Returns the Location that is the published version for `location`
...
...
common/lib/xmodule/xmodule/modulestore/tests/factories.py
View file @
a8084628
...
...
@@ -3,7 +3,6 @@ from time import gmtime
from
uuid
import
uuid4
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.django
import
modulestore
from
xmodule.timeparse
import
stringify_time
from
xmodule.modulestore.inheritance
import
own_metadata
...
...
lms/djangoapps/django_comment_client/base/views.py
View file @
a8084628
...
...
@@ -26,7 +26,7 @@ from course_groups.cohorts import get_cohort_id, is_commentable_cohorted
from
django_comment_client.utils
import
JsonResponse
,
JsonError
,
extract
,
get_courseware_context
from
django_comment_client.permissions
import
check_permissions_by_view
,
cached_has_permission
from
django_comment_c
lient
.models
import
Role
from
django_comment_c
ommon
.models
import
Role
from
courseware.access
import
has_access
log
=
logging
.
getLogger
(
__name__
)
...
...
lms/djangoapps/django_comment_client/management/commands/assign_role.py
View file @
a8084628
from
optparse
import
make_option
from
django.core.management.base
import
BaseCommand
,
CommandError
from
django_comment_c
lient
.models
import
Role
from
django_comment_c
ommon
.models
import
Role
from
django.contrib.auth.models
import
User
...
...
lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py
View file @
a8084628
...
...
@@ -7,7 +7,7 @@ Enrollments.
from
django.core.management.base
import
BaseCommand
,
CommandError
from
student.models
import
CourseEnrollment
from
django_comment_c
lient
.models
import
assign_default_role
from
django_comment_c
ommon
.models
import
assign_default_role
class
Command
(
BaseCommand
):
...
...
lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py
View file @
a8084628
...
...
@@ -7,7 +7,7 @@ Enrollments.
from
django.core.management.base
import
BaseCommand
,
CommandError
from
student.models
import
CourseEnrollment
from
django_comment_c
lient
.models
import
assign_default_role
from
django_comment_c
ommon
.models
import
assign_default_role
class
Command
(
BaseCommand
):
...
...
lms/djangoapps/django_comment_client/management/commands/seed_permissions_roles.py
View file @
a8084628
from
django.core.management.base
import
BaseCommand
,
CommandError
from
django_comment_c
lient.models
import
Role
from
django_comment_c
ommon.utils
import
seed_permissions_roles
class
Command
(
BaseCommand
):
...
...
@@ -13,26 +13,4 @@ class Command(BaseCommand):
raise
CommandError
(
"Too many arguments"
)
course_id
=
args
[
0
]
administrator_role
=
Role
.
objects
.
get_or_create
(
name
=
"Administrator"
,
course_id
=
course_id
)[
0
]
moderator_role
=
Role
.
objects
.
get_or_create
(
name
=
"Moderator"
,
course_id
=
course_id
)[
0
]
community_ta_role
=
Role
.
objects
.
get_or_create
(
name
=
"Community TA"
,
course_id
=
course_id
)[
0
]
student_role
=
Role
.
objects
.
get_or_create
(
name
=
"Student"
,
course_id
=
course_id
)[
0
]
for
per
in
[
"vote"
,
"update_thread"
,
"follow_thread"
,
"unfollow_thread"
,
"update_comment"
,
"create_sub_comment"
,
"unvote"
,
"create_thread"
,
"follow_commentable"
,
"unfollow_commentable"
,
"create_comment"
,
]:
student_role
.
add_permission
(
per
)
for
per
in
[
"edit_content"
,
"delete_thread"
,
"openclose_thread"
,
"endorse_comment"
,
"delete_comment"
,
"see_all_cohorts"
]:
moderator_role
.
add_permission
(
per
)
for
per
in
[
"manage_moderator"
]:
administrator_role
.
add_permission
(
per
)
moderator_role
.
inherit_permissions
(
student_role
)
# For now, Community TA == Moderator, except for the styling.
community_ta_role
.
inherit_permissions
(
moderator_role
)
administrator_role
.
inherit_permissions
(
moderator_role
)
seed_permissions_roles
(
course_id
)
lms/djangoapps/django_comment_client/management/commands/show_permissions.py
View file @
a8084628
from
django.core.management.base
import
BaseCommand
,
CommandError
from
django_comment_common.models
import
Permission
,
Role
from
django.contrib.auth.models
import
User
...
...
lms/djangoapps/django_comment_client/models.py
View file @
a8084628
import
logging
from
django.db
import
models
from
django.contrib.auth.models
import
User
from
django.dispatch
import
receiver
from
django.db.models.signals
import
post_save
from
student.models
import
CourseEnrollment
from
courseware.courses
import
get_course_by_id
FORUM_ROLE_ADMINISTRATOR
=
'Administrator'
FORUM_ROLE_MODERATOR
=
'Moderator'
FORUM_ROLE_COMMUNITY_TA
=
'Community TA'
FORUM_ROLE_STUDENT
=
'Student'
@receiver
(
post_save
,
sender
=
CourseEnrollment
)
def
assign_default_role
(
sender
,
instance
,
**
kwargs
):
if
instance
.
user
.
is_staff
:
role
=
Role
.
objects
.
get_or_create
(
course_id
=
instance
.
course_id
,
name
=
"Moderator"
)[
0
]
else
:
role
=
Role
.
objects
.
get_or_create
(
course_id
=
instance
.
course_id
,
name
=
"Student"
)[
0
]
logging
.
info
(
"assign_default_role: adding
%
s as
%
s"
%
(
instance
.
user
,
role
))
instance
.
user
.
roles
.
add
(
role
)
class
Role
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
30
,
null
=
False
,
blank
=
False
)
users
=
models
.
ManyToManyField
(
User
,
related_name
=
"roles"
)
course_id
=
models
.
CharField
(
max_length
=
255
,
blank
=
True
,
db_index
=
True
)
def
__unicode__
(
self
):
return
self
.
name
+
" for "
+
(
self
.
course_id
if
self
.
course_id
else
"all courses"
)
def
inherit_permissions
(
self
,
role
):
# TODO the name of this method is a little bit confusing,
# since it's one-off and doesn't handle inheritance later
if
role
.
course_id
and
role
.
course_id
!=
self
.
course_id
:
logging
.
warning
(
"
%
s cannot inherit permissions from
%
s due to course_id inconsistency"
,
self
,
role
)
for
per
in
role
.
permissions
.
all
():
self
.
add_permission
(
per
)
def
add_permission
(
self
,
permission
):
self
.
permissions
.
add
(
Permission
.
objects
.
get_or_create
(
name
=
permission
)[
0
])
def
has_permission
(
self
,
permission
):
course
=
get_course_by_id
(
self
.
course_id
)
if
self
.
name
==
FORUM_ROLE_STUDENT
and
\
(
permission
.
startswith
(
'edit'
)
or
permission
.
startswith
(
'update'
)
or
permission
.
startswith
(
'create'
))
and
\
(
not
course
.
forum_posts_allowed
):
return
False
return
self
.
permissions
.
filter
(
name
=
permission
)
.
exists
()
class
Permission
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
30
,
null
=
False
,
blank
=
False
,
primary_key
=
True
)
roles
=
models
.
ManyToManyField
(
Role
,
related_name
=
"permissions"
)
def
__unicode__
(
self
):
return
self
.
name
# This file is intentionally blank. It has been moved to common/djangoapps/django_comment_common
lms/djangoapps/django_comment_client/permissions.py
View file @
a8084628
from
.models
import
Role
,
Permission
from
django_comment_common
.models
import
Role
,
Permission
from
django.db.models.signals
import
post_save
from
django.dispatch
import
receiver
from
student.models
import
CourseEnrollment
...
...
lms/djangoapps/django_comment_client/tests.py
View file @
a8084628
...
...
@@ -6,7 +6,7 @@ from django.test import TestCase
from
student.models
import
CourseEnrollment
from
django_comment_client.permissions
import
has_permission
from
django_comment_c
lient
.models
import
Role
from
django_comment_c
ommon
.models
import
Role
class
PermissionsTestCase
(
TestCase
):
...
...
lms/djangoapps/django_comment_client/tests/factories.py
View file @
a8084628
from
factory
import
DjangoModelFactory
from
django_comment_c
lient
.models
import
Role
,
Permission
from
django_comment_c
ommon
.models
import
Role
,
Permission
class
RoleFactory
(
DjangoModelFactory
):
...
...
lms/djangoapps/django_comment_client/tests/test_models.py
View file @
a8084628
import
django_comment_c
lient
.models
as
models
import
django_comment_c
ommon
.models
as
models
import
django_comment_client.permissions
as
permissions
from
django.test
import
TestCase
...
...
lms/djangoapps/django_comment_client/tests/test_utils.py
View file @
a8084628
from
django.test
import
TestCase
from
student.tests.factories
import
UserFactory
,
CourseEnrollmentFactory
from
django_comment_common.models
import
Role
,
Permission
from
factories
import
RoleFactory
import
django_comment_client.utils
as
utils
...
...
lms/djangoapps/django_comment_client/utils.py
View file @
a8084628
...
...
@@ -14,7 +14,7 @@ from django.core.urlresolvers import reverse
from
django.db
import
connection
from
django.http
import
HttpResponse
from
django.utils
import
simplejson
from
django_comment_c
lient
.models
import
Role
from
django_comment_c
ommon
.models
import
Role
from
django_comment_client.permissions
import
check_permissions_by_view
from
xmodule.modulestore.exceptions
import
NoPathToItem
...
...
lms/djangoapps/instructor/tests/test_forum_admin.py
View file @
a8084628
...
...
@@ -9,7 +9,7 @@ from django.test.utils import override_settings
from
django.contrib.auth.models
import
Group
from
django.core.urlresolvers
import
reverse
from
django_comment_c
lient
.models
import
Role
,
FORUM_ROLE_ADMINISTRATOR
,
\
from
django_comment_c
ommon
.models
import
Role
,
FORUM_ROLE_ADMINISTRATOR
,
\
FORUM_ROLE_MODERATOR
,
FORUM_ROLE_COMMUNITY_TA
,
FORUM_ROLE_STUDENT
from
django_comment_client.utils
import
has_forum_access
...
...
lms/djangoapps/instructor/views.py
View file @
a8084628
...
...
@@ -27,7 +27,7 @@ from courseware.access import (has_access, get_access_group_name,
course_beta_test_group_name
)
from
courseware.courses
import
get_course_with_access
from
courseware.models
import
StudentModule
from
django_comment_c
lient
.models
import
(
Role
,
from
django_comment_c
ommon
.models
import
(
Role
,
FORUM_ROLE_ADMINISTRATOR
,
FORUM_ROLE_MODERATOR
,
FORUM_ROLE_COMMUNITY_TA
)
...
...
lms/envs/common.py
View file @
a8084628
...
...
@@ -700,8 +700,7 @@ INSTALLED_APPS = (
# Discussion forums
'django_comment_client'
,
# Student notes
'django_comment_common'
,
'notes'
,
)
...
...
rakefiles/tests.rake
View file @
a8084628
...
...
@@ -26,6 +26,16 @@ def run_tests(system, report_dir, test_id=nil, stop_on_failure=true)
end
def
run_acceptance_tests
(
system
,
report_dir
,
harvest_args
)
# HACK: Since now the CMS depends on the existence of some database tables
# that used to be in LMS (Role/Permissions for Forums) we need to make
# sure the acceptance tests create/migrate the database tables
# that are represented in the LMS. We might be able to address this by moving
# out the migrations from lms/django_comment_client, but then we'd have to
# repair all the existing migrations from the upgrade tables in the DB.
if
system
==
:cms
sh
(
django_admin
(
'lms'
,
'acceptance'
,
'syncdb'
,
'--noinput'
))
sh
(
django_admin
(
'lms'
,
'acceptance'
,
'migrate'
,
'--noinput'
))
end
sh
(
django_admin
(
system
,
'acceptance'
,
'syncdb'
,
'--noinput'
))
sh
(
django_admin
(
system
,
'acceptance'
,
'migrate'
,
'--noinput'
))
sh
(
django_admin
(
system
,
'acceptance'
,
'harvest'
,
'--debug-mode'
,
'--tag -skip'
,
harvest_args
))
...
...
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