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
200493a5
Commit
200493a5
authored
Jan 06, 2013
by
ichuang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
instructor dashboard upgrade - add enrollment management
parent
e97469ae
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
568 additions
and
23 deletions
+568
-23
common/djangoapps/student/migrations/0021_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_.py
+156
-0
common/djangoapps/student/migrations/0021_remove_askbot.py.old
+157
-0
common/djangoapps/student/models.py
+18
-0
lms/djangoapps/instructor/views.py
+185
-20
lms/envs/dev.py
+4
-0
lms/templates/courseware/instructor_dashboard.html
+48
-3
No files found.
common/djangoapps/student/migrations/0021_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_.py
0 → 100644
View file @
200493a5
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'CourseEnrollmentAllowed'
db
.
create_table
(
'student_courseenrollmentallowed'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'email'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
,
db_index
=
True
)),
(
'course_id'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
,
db_index
=
True
)),
(
'created'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
,
blank
=
True
)),
))
db
.
send_create_signal
(
'student'
,
[
'CourseEnrollmentAllowed'
])
# Adding unique constraint on 'CourseEnrollmentAllowed', fields ['email', 'course_id']
db
.
create_unique
(
'student_courseenrollmentallowed'
,
[
'email'
,
'course_id'
])
def
backwards
(
self
,
orm
):
# Removing unique constraint on 'CourseEnrollmentAllowed', fields ['email', 'course_id']
db
.
delete_unique
(
'student_courseenrollmentallowed'
,
[
'email'
,
'course_id'
])
# Deleting model 'CourseEnrollmentAllowed'
db
.
delete_table
(
'student_courseenrollmentallowed'
)
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'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'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'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'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'
})
},
'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'
})
},
'student.courseenrollment'
:
{
'Meta'
:
{
'unique_together'
:
"(('user', 'course_id'),)"
,
'object_name'
:
'CourseEnrollment'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.courseenrollmentallowed'
:
{
'Meta'
:
{
'unique_together'
:
"(('email', 'course_id'),)"
,
'object_name'
:
'CourseEnrollmentAllowed'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'email'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
})
},
'student.pendingemailchange'
:
{
'Meta'
:
{
'object_name'
:
'PendingEmailChange'
},
'activation_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'new_email'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.pendingnamechange'
:
{
'Meta'
:
{
'object_name'
:
'PendingNameChange'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'new_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'rationale'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'1024'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.registration'
:
{
'Meta'
:
{
'object_name'
:
'Registration'
,
'db_table'
:
"'auth_registration'"
},
'activation_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.testcenteruser'
:
{
'Meta'
:
{
'object_name'
:
'TestCenterUser'
},
'address_1'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
'address_2'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
,
'blank'
:
'True'
}),
'address_3'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
,
'blank'
:
'True'
}),
'candidate_id'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'True'
}),
'city'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'client_candidate_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'db_index'
:
'True'
}),
'company_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'blank'
:
'True'
}),
'country'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'3'
,
'db_index'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'extension'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'8'
,
'blank'
:
'True'
}),
'fax'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'35'
,
'blank'
:
'True'
}),
'fax_country_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'3'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'db_index'
:
'True'
}),
'middle_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'phone'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'35'
}),
'phone_country_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'3'
,
'db_index'
:
'True'
}),
'postal_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'16'
,
'blank'
:
'True'
}),
'salutation'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'blank'
:
'True'
}),
'state'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'20'
,
'blank'
:
'True'
}),
'suffix'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'updated_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'default'
:
'None'
,
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
}),
'user_updated_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'db_index'
:
'True'
})
},
'student.userprofile'
:
{
'Meta'
:
{
'object_name'
:
'UserProfile'
,
'db_table'
:
"'auth_userprofile'"
},
'courseware'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'course.xml'"
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'gender'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'6'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'goals'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'language'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'level_of_education'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'6'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'location'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'mailing_address'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'meta'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'related_name'
:
"'profile'"
,
'unique'
:
'True'
,
'to'
:
"orm['auth.User']"
}),
'year_of_birth'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'db_index'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
'student.usertestgroup'
:
{
'Meta'
:
{
'object_name'
:
'UserTestGroup'
},
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'users'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'db_index'
:
'True'
,
'symmetrical'
:
'False'
})
}
}
complete_apps
=
[
'student'
]
\ No newline at end of file
common/djangoapps/student/migrations/0021_remove_askbot.py.old
0 → 100644
View file @
200493a5
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
ASKBOT_AUTH_USER_COLUMNS = (
'website',
'about',
'gold',
'email_isvalid',
'real_name',
'location',
'reputation',
'gravatar',
'bronze',
'last_seen',
'silver',
'questions_per_page',
'new_response_count',
'seen_response_count',
)
class Migration(SchemaMigration):
def forwards(self, orm):
"Kill the askbot"
# For MySQL, we're batching the alters together for performance reasons
if db.backend_name == 'mysql':
drops = ["drop `{0}`".format(col) for col in ASKBOT_AUTH_USER_COLUMNS]
statement = "alter table `auth_user` {0};".format(", ".join(drops))
db.execute(statement)
else:
for column in ASKBOT_AUTH_USER_COLUMNS:
db.delete_column('auth_user', column)
def backwards(self, orm):
raise RuntimeError("Cannot reverse this migration: there's no going back to Askbot.")
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'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': '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'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'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'})
},
'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'})
},
'student.courseenrollment': {
'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'student.pendingemailchange': {
'Meta': {'object_name': 'PendingEmailChange'},
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.pendingnamechange': {
'Meta': {'object_name': 'PendingNameChange'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.registration': {
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.testcenteruser': {
'Meta': {'object_name': 'TestCenterUser'},
'address_1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'address_2': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'address_3': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'candidate_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'db_index': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'client_candidate_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'company_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '3', 'db_index': 'True'}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
'extension': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '8', 'blank': 'True'}),
'fax': ('django.db.models.fields.CharField', [], {'max_length': '35', 'blank': 'True'}),
'fax_country_code': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'middle_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '35'}),
'phone_country_code': ('django.db.models.fields.CharField', [], {'max_length': '3', 'db_index': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'blank': 'True'}),
'salutation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'state': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '20', 'blank': 'True'}),
'suffix': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['auth.User']", 'unique': 'True'}),
'user_updated_at': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'})
},
'student.userprofile': {
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
},
'student.usertestgroup': {
'Meta': {'object_name': 'UserTestGroup'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
}
}
complete_apps = ['student']
common/djangoapps/student/models.py
View file @
200493a5
...
...
@@ -262,6 +262,24 @@ class CourseEnrollment(models.Model):
return
"[CourseEnrollment]
%
s:
%
s (
%
s)"
%
(
self
.
user
,
self
.
course_id
,
self
.
created
)
class
CourseEnrollmentAllowed
(
models
.
Model
):
"""
Table of users (specified by email address strings) who are allowed to enroll in a specified course.
The user may or may not (yet) exist. Enrollment by users listed in this table is allowed
even if the enrollment time window is past.
"""
email
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
class
Meta
:
unique_together
=
((
'email'
,
'course_id'
),
)
def
__unicode__
(
self
):
return
"[CourseEnrollmentAllowed]
%
s:
%
s (
%
s)"
%
(
self
.
email
,
self
.
course_id
,
self
.
created
)
@receiver
(
post_save
,
sender
=
CourseEnrollment
)
def
assign_default_role
(
sender
,
instance
,
**
kwargs
):
if
instance
.
user
.
is_staff
:
...
...
lms/djangoapps/instructor/views.py
View file @
200493a5
...
...
@@ -2,8 +2,10 @@
from
collections
import
defaultdict
import
csv
import
json
import
logging
import
os
import
requests
import
urllib
from
django.conf
import
settings
...
...
@@ -20,7 +22,7 @@ from courseware.courses import get_course_with_access
from
django_comment_client.models
import
Role
,
FORUM_ROLE_ADMINISTRATOR
,
FORUM_ROLE_MODERATOR
,
FORUM_ROLE_COMMUNITY_TA
from
django_comment_client.utils
import
has_forum_access
from
psychometrics
import
psychoanalyze
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
,
CourseEnrollmentAllowed
from
xmodule.course_module
import
CourseDescriptor
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.django
import
modulestore
...
...
@@ -125,7 +127,7 @@ def instructor_dashboard(request, course_id):
except
Exception
as
err
:
msg
+=
'<br/><p>Error: {0}</p>'
.
format
(
escape
(
err
))
if
action
==
'Dump list of enrolled students'
:
if
action
==
'Dump list of enrolled students'
or
action
==
'List enrolled students'
:
log
.
debug
(
action
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
False
)
datatable
[
'title'
]
=
'List of students enrolled in {0}'
.
format
(
course_id
)
...
...
@@ -258,6 +260,70 @@ def instructor_dashboard(request, course_id):
{},
page
=
'idashboard'
)
#----------------------------------------
# enrollment
elif
action
==
'List students who may enroll but may not have yet signed up'
:
ceaset
=
CourseEnrollmentAllowed
.
objects
.
filter
(
course_id
=
course_id
)
datatable
=
{
'header'
:
[
'StudentEmail'
]}
datatable
[
'data'
]
=
[[
x
.
email
]
for
x
in
ceaset
]
datatable
[
'title'
]
=
action
elif
action
==
'Enroll student'
:
student
=
request
.
POST
.
get
(
'enstudent'
,
''
)
datatable
=
{}
try
:
nce
=
CourseEnrollment
(
user
=
User
.
objects
.
get
(
email
=
student
),
course_id
=
course_id
)
nce
.
save
()
msg
+=
"Enrolled student with email '
%
s'"
%
student
except
Exception
as
err
:
msg
+=
"Error! Failed to enroll student with email '
%
s'
\n
"
%
student
msg
+=
str
(
err
)
+
'
\n
'
elif
action
==
'Un-enroll student'
:
student
=
request
.
POST
.
get
(
'enstudent'
,
''
)
datatable
=
{}
try
:
nce
=
CourseEnrollment
.
objects
.
get
(
user
=
User
.
objects
.
get
(
email
=
student
),
course_id
=
course_id
)
nce
.
delete
()
msg
+=
"Un-enrolled student with email '
%
s'"
%
student
except
Exception
as
err
:
msg
+=
"Error! Failed to un-enroll student with email '
%
s'
\n
"
%
student
msg
+=
str
(
err
)
+
'
\n
'
elif
action
==
'Un-enroll ALL students'
:
ret
=
_do_enroll_students
(
course
,
course_id
,
''
,
overload
=
True
)
datatable
=
ret
[
'datatable'
]
elif
action
==
'Enroll multiple students'
:
students
=
request
.
POST
.
get
(
'enroll_multiple'
,
''
)
ret
=
_do_enroll_students
(
course
,
course_id
,
students
)
datatable
=
ret
[
'datatable'
]
elif
action
==
'List sections available in remote gradebook'
:
msg2
,
datatable
=
_do_remote_gradebook
(
course
,
'get-sections'
)
msg
+=
msg2
elif
action
in
[
'List students in section in remote gradebook'
,
'Overload enrollment list using remote gradebook'
,
'Merge enrollment list with remote gradebook'
]:
section
=
request
.
POST
.
get
(
'gradebook_section'
,
''
)
msg2
,
datatable
=
_do_remote_gradebook
(
course
,
'get-membership'
,
dict
(
section
=
section
)
)
msg
+=
msg2
if
not
'List'
in
action
:
students
=
','
.
join
([
x
[
'email'
]
for
x
in
datatable
[
'retdata'
]])
overload
=
'Overload'
in
action
ret
=
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
overload
)
datatable
=
ret
[
'datatable'
]
#----------------------------------------
# psychometrics
elif
action
==
'Generate Histogram and IRT Plot'
:
...
...
@@ -270,9 +336,9 @@ def instructor_dashboard(request, course_id):
problems
=
psychoanalyze
.
problems_with_psychometric_data
(
course_id
)
#----------------------------------------
# context for rendering
context
=
{
'course'
:
course
,
'staff_access'
:
True
,
'admin_access'
:
request
.
user
.
is_staff
,
...
...
@@ -285,16 +351,65 @@ def instructor_dashboard(request, course_id):
'plots'
:
plots
,
# psychometrics
'course_errors'
:
modulestore
()
.
get_item_errors
(
course
.
location
),
'djangopid'
:
os
.
getpid
(),
'mitx_version'
:
getattr
(
settings
,
'MITX_VERSION_STRING'
,
''
)
}
return
render_to_response
(
'courseware/instructor_dashboard.html'
,
context
)
def
_do_remote_gradebook
(
course
,
action
,
args
=
None
):
'''
Perform remote gradebook action. Returns msg, datatable.
'''
rg
=
course
.
metadata
.
get
(
'remote_gradebook'
,
''
)
if
not
rg
:
msg
=
"No remote gradebook defined in course metadata"
return
msg
,
{}
rgurl
=
settings
.
MITX_FEATURES
.
get
(
'REMOTE_GRADEBOOK_URL'
,
''
)
if
not
rgurl
:
msg
=
"No remote gradebook url defined in settings.MITX_FEATURES"
return
msg
,
{}
rgname
=
rg
.
get
(
'name'
,
''
)
if
not
rgname
:
msg
=
"No gradebook name defined in course remote_gradebook metadata"
return
msg
,
{}
if
args
is
None
:
args
=
{}
data
=
dict
(
submit
=
action
,
gradebook
=
rgname
)
data
.
update
(
args
)
try
:
resp
=
requests
.
post
(
rgurl
,
data
=
data
,
verify
=
False
)
retdict
=
json
.
loads
(
resp
.
content
)
except
Exception
as
err
:
msg
=
"Failed to communicate with gradebook server at
%
s<br/>"
%
rgurl
msg
+=
"Error:
%
s"
%
err
msg
+=
"<br/>resp=
%
s"
%
resp
.
content
msg
+=
"<br/>data=
%
s"
%
data
return
msg
,
{}
msg
=
'<pre>
%
s</pre>'
%
retdict
[
'msg'
]
.
replace
(
'
\n
'
,
'<br/>'
)
retdata
=
retdict
[
'data'
]
if
retdata
:
datatable
=
{
'header'
:
retdata
[
0
]
.
keys
()}
datatable
[
'data'
]
=
[
x
.
values
()
for
x
in
retdata
]
datatable
[
'title'
]
=
'Remote gradebook response for
%
s'
%
action
datatable
[
'retdata'
]
=
retdata
else
:
datatable
=
{}
return
msg
,
datatable
def
_list_course_forum_members
(
course_id
,
rolename
,
datatable
):
'''
Fills in datatable with forum membership information, for a given role,
so that it will be displayed on instructor dashboard.
course_ID =
course's ID string
course_ID =
the ID string for a course
rolename = one of "Administrator", "Moderator", "Community TA"
Returns message status string to append to displayed message, if role is unknown.
...
...
@@ -455,6 +570,68 @@ def grade_summary(request, course_id):
return
render_to_response
(
'courseware/grade_summary.html'
,
context
)
def
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
False
):
"""Do the actual work of enrolling multiple students, presented as a string
of emails separated by commas or returns"""
ns
=
[
x
.
split
(
'
\n
'
)
for
x
in
students
.
split
(
','
)]
new_students
=
[
item
for
sublist
in
ns
for
item
in
sublist
]
new_students
=
[
str
(
s
.
strip
())
for
s
in
new_students
]
new_students_lc
=
[
x
.
lower
()
for
x
in
new_students
]
if
''
in
new_students
:
new_students
.
remove
(
''
)
status
=
dict
([
x
,
'unprocessed'
]
for
x
in
new_students
)
if
overload
:
# delete all but staff
todelete
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course_id
)
for
ce
in
todelete
:
if
not
has_access
(
ce
.
user
,
course
,
'staff'
)
and
ce
.
user
.
email
.
lower
()
not
in
new_students_lc
:
status
[
ce
.
user
.
email
]
=
'deleted'
ce
.
delete
()
else
:
status
[
ce
.
user
.
email
]
=
'is staff'
ceaset
=
CourseEnrollmentAllowed
.
objects
.
filter
(
course_id
=
course_id
)
for
cea
in
ceaset
:
status
[
cea
.
email
]
=
'removed from pending enrollment list'
ceaset
.
delete
()
for
student
in
new_students
:
try
:
user
=
User
.
objects
.
get
(
email
=
student
)
except
User
.
DoesNotExist
:
# user not signed up yet, put in pending enrollment allowed table
if
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
student
,
course_id
=
course_id
):
status
[
student
]
=
'user does not exist, enrollment already allowed, pending'
continue
cea
=
CourseEnrollmentAllowed
(
email
=
student
,
course_id
=
course_id
)
cea
.
save
()
status
[
student
]
=
'user does not exist, enrollment allowed, pending'
continue
if
CourseEnrollment
.
objects
.
filter
(
user
=
user
,
course_id
=
course_id
):
status
[
student
]
=
'already enrolled'
continue
try
:
nce
=
CourseEnrollment
(
user
=
user
,
course_id
=
course_id
)
nce
.
save
()
status
[
student
]
=
'added'
except
:
status
[
student
]
=
'rejected'
datatable
=
{
'header'
:
[
'StudentEmail'
,
'action'
]}
datatable
[
'data'
]
=
[[
x
,
status
[
x
]]
for
x
in
status
]
datatable
[
'title'
]
=
'Enrollment of students'
def
sf
(
stat
):
return
[
x
for
x
in
status
if
status
[
x
]
==
stat
]
data
=
dict
(
added
=
sf
(
'added'
),
rejected
=
sf
(
'rejected'
)
+
sf
(
'exists'
),
deleted
=
sf
(
'deleted'
),
datatable
=
datatable
)
return
data
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
def
enroll_students
(
request
,
course_id
):
...
...
@@ -473,22 +650,10 @@ def enroll_students(request, course_id):
course
=
get_course_with_access
(
request
.
user
,
course_id
,
'staff'
)
existing_students
=
[
ce
.
user
.
email
for
ce
in
CourseEnrollment
.
objects
.
filter
(
course_id
=
course_id
)]
if
'new_students'
in
request
.
POST
:
new_students
=
request
.
POST
[
'new_students'
]
.
split
(
'
\n
'
)
else
:
new_students
=
[]
new_students
=
[
s
.
strip
()
for
s
in
new_students
]
added_students
=
[]
rejected_students
=
[]
for
student
in
new_students
:
try
:
nce
=
CourseEnrollment
(
user
=
User
.
objects
.
get
(
email
=
student
),
course_id
=
course_id
)
nce
.
save
()
added_students
.
append
(
student
)
except
:
rejected_students
.
append
(
student
)
new_students
=
request
.
POST
.
get
(
'new_students'
)
ret
=
_do_enroll_students
(
course
,
course_id
,
new_students
)
added_students
=
ret
[
'added'
]
rejected_students
=
ret
[
'rejected'
]
return
render_to_response
(
"enroll_students.html"
,
{
'course'
:
course_id
,
'existing_students'
:
existing_students
,
...
...
lms/envs/dev.py
View file @
200493a5
...
...
@@ -102,6 +102,10 @@ SUBDOMAIN_BRANDING = {
COMMENTS_SERVICE_KEY
=
"PUT_YOUR_API_KEY_HERE"
################################# mitx revision string #####################
MITX_VERSION_STRING
=
os
.
popen
(
'cd
%
s; git describe'
%
REPO_ROOT
)
.
read
()
.
strip
()
################################# Staff grading config #####################
STAFF_GRADING_INTERFACE
=
{
...
...
lms/templates/courseware/instructor_dashboard.html
View file @
200493a5
...
...
@@ -57,10 +57,13 @@ function goto( mode)
<a
href=
"#"
onclick=
"goto('Psychometrics');"
class=
"${modeflag.get('Psychometrics')}"
>
Psychometrics
</a>
|
%endif
<a
href=
"#"
onclick=
"goto('Admin');"
class=
"${modeflag.get('Admin')}"
>
Admin
</a>
|
<a
href=
"#"
onclick=
"goto('Forum Admin');"
class=
"${modeflag.get('Forum Admin')}"
>
Forum Admin
</a>
]
<a
href=
"#"
onclick=
"goto('Forum Admin');"
class=
"${modeflag.get('Forum Admin')}"
>
Forum Admin
</a>
|
<a
href=
"#"
onclick=
"goto('Enrollment');"
class=
"${modeflag.get('Enrollment')}"
>
Enrollment
</a>
]
</h2>
<div
style=
"text-align:right"
id=
"djangopid"
>
${djangopid}
</div>
<div
style=
"text-align:right"
><span
id=
"djangopid"
>
${djangopid}
</span>
|
<span
id=
"mitxver"
>
${mitx_version}
</span></div>
<form
name=
"idashform"
method=
"POST"
>
<input
type=
"hidden"
name=
"csrfmiddlewaretoken"
value=
"${ csrf_token }"
>
...
...
@@ -163,10 +166,52 @@ function goto( mode)
%endif
%endif
##-----------------------------------------------------------------------------
%if modeflag.get('Enrollment'):
<hr
width=
"40%"
style=
"align:left"
>
<p>
<input
type=
"submit"
name=
"action"
value=
"List enrolled students"
>
<input
type=
"submit"
name=
"action"
value=
"List students who may enroll but may not have yet signed up"
>
<p>
Student Email:
<input
type=
"text"
name=
"enstudent"
>
<input
type=
"submit"
name=
"action"
value=
"Un-enroll student"
>
<input
type=
"submit"
name=
"action"
value=
"Enroll student"
>
<input
type=
"submit"
name=
"action"
value=
"Un-enroll ALL students"
>
<hr
width=
"40%"
style=
"align:left"
>
%if settings.MITX_FEATURES.get('REMOTE_GRADEBOOK_URL','') and instructor_access:
<
%
rg =
course.metadata.get('remote_gradebook',{})
%
>
<p>
Pull enrollment from remote gradebook
</p>
<ul>
<li>
Gradebook name:
<input
type=
"text"
name=
"gradebook_name"
size=
40
value=
"${rg.get('name','')}"
></li>
<li>
Section:
<input
type=
"text"
name=
"gradebook_section"
size=
40
value=
"${rg.get('section','')}"
></li>
</ul>
<input
type=
"submit"
name=
"action"
value=
"List sections available in remote gradebook"
>
<input
type=
"submit"
name=
"action"
value=
"List students in section in remote gradebook"
>
<input
type=
"submit"
name=
"action"
value=
"Overload enrollment list using remote gradebook"
>
<input
type=
"submit"
name=
"action"
value=
"Merge enrollment list with remote gradebook"
>
<hr
width=
"40%"
style=
"align:left"
>
%endif
<p>
Add students: enter emails, separated by returns or commas;
</p>
<textarea
rows=
"6"
cols=
"70"
name=
"enroll_multiple"
></textarea>
<input
type=
"submit"
name=
"action"
value=
"Enroll multiple students"
>
%endif
##-----------------------------------------------------------------------------
</form>
##-----------------------------------------------------------------------------
%if modeflag.get('Psychometrics') is None:
##-----------------------------------------------------------------------------
%if datatable and modeflag.get('Psychometrics') is None:
<br/>
<br/>
...
...
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