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
0b4e03e8
Commit
0b4e03e8
authored
Jun 10, 2013
by
dcadams
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #66 from edx/feature-dcadams-usermanagement
Feature user-management autoenroll
parents
1c348a94
7d961bae
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
485 additions
and
118 deletions
+485
-118
common/djangoapps/student/migrations/0025_auto__add_field_courseenrollmentallowed_auto_enroll.py
+174
-0
common/djangoapps/student/models.py
+1
-0
common/djangoapps/student/views.py
+20
-16
lms/djangoapps/instructor/tests/test_enrollment.py
+178
-0
lms/djangoapps/instructor/views.py
+106
-95
lms/templates/courseware/instructor_dashboard.html
+6
-5
lms/urls.py
+0
-2
No files found.
common/djangoapps/student/migrations/0025_auto__add_field_courseenrollmentallowed_auto_enroll.py
0 → 100644
View file @
0b4e03e8
# -*- 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 field 'CourseEnrollmentAllowed.auto_enroll'
db
.
add_column
(
'student_courseenrollmentallowed'
,
'auto_enroll'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
False
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Deleting field 'CourseEnrollmentAllowed.auto_enroll'
db
.
delete_column
(
'student_courseenrollmentallowed'
,
'auto_enroll'
)
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'
},
'auto_enroll'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'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.testcenterregistration'
:
{
'Meta'
:
{
'object_name'
:
'TestCenterRegistration'
},
'accommodation_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'blank'
:
'True'
}),
'accommodation_request'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'1024'
,
'blank'
:
'True'
}),
'authorization_id'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'True'
}),
'client_authorization_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'20'
,
'db_index'
:
'True'
}),
'confirmed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'True'
}),
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'db_index'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'eligibility_appointment_date_first'
:
(
'django.db.models.fields.DateField'
,
[],
{
'db_index'
:
'True'
}),
'eligibility_appointment_date_last'
:
(
'django.db.models.fields.DateField'
,
[],
{
'db_index'
:
'True'
}),
'exam_series_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'15'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'processed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'True'
}),
'testcenter_user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'default'
:
'None'
,
'to'
:
"orm['student.TestCenterUser']"
}),
'updated_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'upload_error_message'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'512'
,
'blank'
:
'True'
}),
'upload_status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'20'
,
'blank'
:
'True'
}),
'uploaded_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'True'
}),
'user_updated_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'db_index'
:
'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'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'50'
,
'db_index'
:
'True'
}),
'company_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'50'
,
'blank'
:
'True'
}),
'confirmed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'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'
}),
'processed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'db_index'
:
'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'
}),
'upload_error_message'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'512'
,
'blank'
:
'True'
}),
'upload_status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'20'
,
'blank'
:
'True'
}),
'uploaded_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'db_index'
:
'True'
,
'null'
:
'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'"
},
'allow_certificate'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'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/models.py
View file @
0b4e03e8
...
@@ -662,6 +662,7 @@ class CourseEnrollmentAllowed(models.Model):
...
@@ -662,6 +662,7 @@ class CourseEnrollmentAllowed(models.Model):
"""
"""
email
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
email
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
auto_enroll
=
models
.
BooleanField
(
default
=
0
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
...
...
common/djangoapps/student/views.py
View file @
0b4e03e8
...
@@ -32,7 +32,7 @@ from student.models import (Registration, UserProfile, TestCenterUser, TestCente
...
@@ -32,7 +32,7 @@ from student.models import (Registration, UserProfile, TestCenterUser, TestCente
TestCenterRegistration
,
TestCenterRegistrationForm
,
TestCenterRegistration
,
TestCenterRegistrationForm
,
PendingNameChange
,
PendingEmailChange
,
PendingNameChange
,
PendingEmailChange
,
CourseEnrollment
,
unique_id_for_user
,
CourseEnrollment
,
unique_id_for_user
,
get_testcenter_registration
)
get_testcenter_registration
,
CourseEnrollmentAllowed
)
from
certificates.models
import
CertificateStatuses
,
certificate_status_for_student
from
certificates.models
import
CertificateStatuses
,
certificate_status_for_student
...
@@ -264,7 +264,6 @@ def dashboard(request):
...
@@ -264,7 +264,6 @@ def dashboard(request):
if
not
user
.
is_active
:
if
not
user
.
is_active
:
message
=
render_to_string
(
'registration/activate_account_notice.html'
,
{
'email'
:
user
.
email
})
message
=
render_to_string
(
'registration/activate_account_notice.html'
,
{
'email'
:
user
.
email
})
# Global staff can see what courses errored on their dashboard
# Global staff can see what courses errored on their dashboard
staff_access
=
False
staff_access
=
False
errored_courses
=
{}
errored_courses
=
{}
...
@@ -355,7 +354,7 @@ def change_enrollment(request):
...
@@ -355,7 +354,7 @@ def change_enrollment(request):
course
=
course_from_id
(
course_id
)
course
=
course_from_id
(
course_id
)
except
ItemNotFoundError
:
except
ItemNotFoundError
:
log
.
warning
(
"User {0} tried to enroll in non-existent course {1}"
log
.
warning
(
"User {0} tried to enroll in non-existent course {1}"
.
format
(
user
.
username
,
course_id
))
.
format
(
user
.
username
,
course_id
))
return
HttpResponseBadRequest
(
"Course id is invalid"
)
return
HttpResponseBadRequest
(
"Course id is invalid"
)
if
not
has_access
(
user
,
course
,
'enroll'
):
if
not
has_access
(
user
,
course
,
'enroll'
):
...
@@ -363,9 +362,9 @@ def change_enrollment(request):
...
@@ -363,9 +362,9 @@ def change_enrollment(request):
org
,
course_num
,
run
=
course_id
.
split
(
"/"
)
org
,
course_num
,
run
=
course_id
.
split
(
"/"
)
statsd
.
increment
(
"common.student.enrollment"
,
statsd
.
increment
(
"common.student.enrollment"
,
tags
=
[
"org:{0}"
.
format
(
org
),
tags
=
[
"org:{0}"
.
format
(
org
),
"course:{0}"
.
format
(
course_num
),
"course:{0}"
.
format
(
course_num
),
"run:{0}"
.
format
(
run
)])
"run:{0}"
.
format
(
run
)])
try
:
try
:
enrollment
,
created
=
CourseEnrollment
.
objects
.
get_or_create
(
user
=
user
,
course_id
=
course
.
id
)
enrollment
,
created
=
CourseEnrollment
.
objects
.
get_or_create
(
user
=
user
,
course_id
=
course
.
id
)
...
@@ -382,9 +381,9 @@ def change_enrollment(request):
...
@@ -382,9 +381,9 @@ def change_enrollment(request):
org
,
course_num
,
run
=
course_id
.
split
(
"/"
)
org
,
course_num
,
run
=
course_id
.
split
(
"/"
)
statsd
.
increment
(
"common.student.unenrollment"
,
statsd
.
increment
(
"common.student.unenrollment"
,
tags
=
[
"org:{0}"
.
format
(
org
),
tags
=
[
"org:{0}"
.
format
(
org
),
"course:{0}"
.
format
(
course_num
),
"course:{0}"
.
format
(
course_num
),
"run:{0}"
.
format
(
run
)])
"run:{0}"
.
format
(
run
)])
return
HttpResponse
()
return
HttpResponse
()
except
CourseEnrollment
.
DoesNotExist
:
except
CourseEnrollment
.
DoesNotExist
:
...
@@ -454,7 +453,6 @@ def login_user(request, error=""):
...
@@ -454,7 +453,6 @@ def login_user(request, error=""):
expires_time
=
time
.
time
()
+
max_age
expires_time
=
time
.
time
()
+
max_age
expires
=
cookie_date
(
expires_time
)
expires
=
cookie_date
(
expires_time
)
response
.
set_cookie
(
settings
.
EDXMKTG_COOKIE_NAME
,
response
.
set_cookie
(
settings
.
EDXMKTG_COOKIE_NAME
,
'true'
,
max_age
=
max_age
,
'true'
,
max_age
=
max_age
,
expires
=
expires
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
expires
=
expires
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
...
@@ -515,8 +513,8 @@ def _do_create_account(post_vars):
...
@@ -515,8 +513,8 @@ def _do_create_account(post_vars):
Note: this function is also used for creating test users.
Note: this function is also used for creating test users.
"""
"""
user
=
User
(
username
=
post_vars
[
'username'
],
user
=
User
(
username
=
post_vars
[
'username'
],
email
=
post_vars
[
'email'
],
email
=
post_vars
[
'email'
],
is_active
=
False
)
is_active
=
False
)
user
.
set_password
(
post_vars
[
'password'
])
user
.
set_password
(
post_vars
[
'password'
])
registration
=
Registration
()
registration
=
Registration
()
# TODO: Rearrange so that if part of the process fails, the whole process fails.
# TODO: Rearrange so that if part of the process fails, the whole process fails.
...
@@ -698,7 +696,6 @@ def create_account(request, post_override=None):
...
@@ -698,7 +696,6 @@ def create_account(request, post_override=None):
expires_time
=
time
.
time
()
+
max_age
expires_time
=
time
.
time
()
+
max_age
expires
=
cookie_date
(
expires_time
)
expires
=
cookie_date
(
expires_time
)
response
.
set_cookie
(
settings
.
EDXMKTG_COOKIE_NAME
,
response
.
set_cookie
(
settings
.
EDXMKTG_COOKIE_NAME
,
'true'
,
max_age
=
max_age
,
'true'
,
max_age
=
max_age
,
expires
=
expires
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
expires
=
expires
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
...
@@ -708,7 +705,6 @@ def create_account(request, post_override=None):
...
@@ -708,7 +705,6 @@ def create_account(request, post_override=None):
return
response
return
response
def
exam_registration_info
(
user
,
course
):
def
exam_registration_info
(
user
,
course
):
""" Returns a Registration object if the user is currently registered for a current
""" Returns a Registration object if the user is currently registered for a current
exam of the course. Returns None if the user is not registered, or if there is no
exam of the course. Returns None if the user is not registered, or if there is no
...
@@ -849,7 +845,6 @@ def create_exam_registration(request, post_override=None):
...
@@ -849,7 +845,6 @@ def create_exam_registration(request, post_override=None):
response_data
[
'non_field_errors'
]
=
form
.
non_field_errors
()
response_data
[
'non_field_errors'
]
=
form
.
non_field_errors
()
return
HttpResponse
(
json
.
dumps
(
response_data
),
mimetype
=
"application/json"
)
return
HttpResponse
(
json
.
dumps
(
response_data
),
mimetype
=
"application/json"
)
# only do the following if there is accommodation text to send,
# only do the following if there is accommodation text to send,
# and a destination to which to send it.
# and a destination to which to send it.
# TODO: still need to create the accommodation email templates
# TODO: still need to create the accommodation email templates
...
@@ -872,7 +867,6 @@ def create_exam_registration(request, post_override=None):
...
@@ -872,7 +867,6 @@ def create_exam_registration(request, post_override=None):
# response_data['non_field_errors'] = [ 'Could not send accommodation e-mail.', ]
# response_data['non_field_errors'] = [ 'Could not send accommodation e-mail.', ]
# return HttpResponse(json.dumps(response_data), mimetype="application/json")
# return HttpResponse(json.dumps(response_data), mimetype="application/json")
js
=
{
'success'
:
True
}
js
=
{
'success'
:
True
}
return
HttpResponse
(
json
.
dumps
(
js
),
mimetype
=
"application/json"
)
return
HttpResponse
(
json
.
dumps
(
js
),
mimetype
=
"application/json"
)
...
@@ -916,6 +910,16 @@ def activate_account(request, key):
...
@@ -916,6 +910,16 @@ def activate_account(request, key):
if
not
r
[
0
]
.
user
.
is_active
:
if
not
r
[
0
]
.
user
.
is_active
:
r
[
0
]
.
activate
()
r
[
0
]
.
activate
()
already_active
=
False
already_active
=
False
#Enroll student in any pending courses he/she may have if auto_enroll flag is set
student
=
User
.
objects
.
filter
(
id
=
r
[
0
]
.
user_id
)
if
student
:
ceas
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
student
[
0
]
.
email
)
for
cea
in
ceas
:
if
cea
.
auto_enroll
:
course_id
=
cea
.
course_id
enrollment
,
created
=
CourseEnrollment
.
objects
.
get_or_create
(
user_id
=
student
[
0
]
.
id
,
course_id
=
course_id
)
resp
=
render_to_response
(
"registration/activation_complete.html"
,
{
'user_logged_in'
:
user_logged_in
,
'already_active'
:
already_active
})
resp
=
render_to_response
(
"registration/activation_complete.html"
,
{
'user_logged_in'
:
user_logged_in
,
'already_active'
:
already_active
})
return
resp
return
resp
if
len
(
r
)
==
0
:
if
len
(
r
)
==
0
:
...
...
lms/djangoapps/instructor/tests/test_enrollment.py
0 → 100644
View file @
0b4e03e8
'''
Unit tests for enrollment methods in views.py
'''
from
django.test.utils
import
override_settings
from
django.contrib.auth.models
import
Group
,
User
from
django.core.urlresolvers
import
reverse
from
courseware.access
import
_course_staff_group_name
from
courseware.tests.tests
import
LoginEnrollmentTestCase
,
TEST_DATA_XML_MODULESTORE
,
get_user
from
xmodule.modulestore.django
import
modulestore
import
xmodule.modulestore.django
from
student.models
import
CourseEnrollment
,
CourseEnrollmentAllowed
from
instructor.views
import
get_and_clean_student_list
@override_settings
(
MODULESTORE
=
TEST_DATA_XML_MODULESTORE
)
class
TestInstructorEnrollsStudent
(
LoginEnrollmentTestCase
):
'''
Check Enrollment/Unenrollment with/without auto-enrollment on activation
'''
def
setUp
(
self
):
self
.
full
=
modulestore
()
.
get_course
(
"edX/full/6.002_Spring_2012"
)
self
.
toy
=
modulestore
()
.
get_course
(
"edX/toy/2012_Fall"
)
#Create instructor and student accounts
self
.
instructor
=
'instructor1@test.com'
self
.
student1
=
'student1@test.com'
self
.
student2
=
'student2@test.com'
self
.
password
=
'foo'
self
.
create_account
(
'it1'
,
self
.
instructor
,
self
.
password
)
self
.
create_account
(
'st1'
,
self
.
student1
,
self
.
password
)
self
.
create_account
(
'st2'
,
self
.
student2
,
self
.
password
)
self
.
activate_user
(
self
.
instructor
)
self
.
activate_user
(
self
.
student1
)
self
.
activate_user
(
self
.
student2
)
def
make_instructor
(
course
):
group_name
=
_course_staff_group_name
(
course
.
location
)
g
=
Group
.
objects
.
create
(
name
=
group_name
)
g
.
user_set
.
add
(
get_user
(
self
.
instructor
))
make_instructor
(
self
.
toy
)
#Enroll Students
self
.
logout
()
self
.
login
(
self
.
student1
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
self
.
logout
()
self
.
login
(
self
.
student2
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
#Enroll Instructor
self
.
logout
()
self
.
login
(
self
.
instructor
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
def
test_unenrollment
(
self
):
'''
Do un-enrollment test
'''
course
=
self
.
toy
url
=
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
course
.
id
})
response
=
self
.
client
.
post
(
url
,
{
'action'
:
'Unenroll multiple students'
,
'multiple_students'
:
'student1@test.com, student2@test.com'
})
#Check the page output
self
.
assertContains
(
response
,
'<td>student1@test.com</td>'
)
self
.
assertContains
(
response
,
'<td>student2@test.com</td>'
)
self
.
assertContains
(
response
,
'<td>un-enrolled</td>'
)
#Check the enrollment table
user
=
User
.
objects
.
get
(
email
=
'student1@test.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
0
,
len
(
ce
))
user
=
User
.
objects
.
get
(
email
=
'student2@test.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
0
,
len
(
ce
))
def
test_enrollment_new_student_autoenroll_on
(
self
):
'''
Do auto-enroll on test
'''
#Run the Enroll students command
course
=
self
.
toy
url
=
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
course
.
id
})
response
=
self
.
client
.
post
(
url
,
{
'action'
:
'Enroll multiple students'
,
'multiple_students'
:
'test1_1@student.com, test1_2@student.com'
,
'auto_enroll'
:
'on'
})
#Check the page output
self
.
assertContains
(
response
,
'<td>test1_1@student.com</td>'
)
self
.
assertContains
(
response
,
'<td>test1_2@student.com</td>'
)
self
.
assertContains
(
response
,
'<td>user does not exist, enrollment allowed, pending with auto enrollment on</td>'
)
#Check the enrollmentallowed db entries
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
'test1_1@student.com'
,
course_id
=
course
.
id
)
self
.
assertEqual
(
1
,
cea
[
0
]
.
auto_enroll
)
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
'test1_2@student.com'
,
course_id
=
course
.
id
)
self
.
assertEqual
(
1
,
cea
[
0
]
.
auto_enroll
)
#Check there is no enrollment db entry other than for the setup instructor and students
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
)
self
.
assertEqual
(
3
,
len
(
ce
))
#Create and activate student accounts with same email
self
.
student1
=
'test1_1@student.com'
self
.
password
=
'bar'
self
.
create_account
(
's1_1'
,
self
.
student1
,
self
.
password
)
self
.
activate_user
(
self
.
student1
)
self
.
student2
=
'test1_2@student.com'
self
.
create_account
(
's1_2'
,
self
.
student2
,
self
.
password
)
self
.
activate_user
(
self
.
student2
)
#Check students are enrolled
user
=
User
.
objects
.
get
(
email
=
'test1_1@student.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
1
,
len
(
ce
))
user
=
User
.
objects
.
get
(
email
=
'test1_2@student.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
1
,
len
(
ce
))
def
test_enrollmemt_new_student_autoenroll_off
(
self
):
'''
Do auto-enroll off test
'''
#Run the Enroll students command
course
=
self
.
toy
url
=
reverse
(
'instructor_dashboard'
,
kwargs
=
{
'course_id'
:
course
.
id
})
response
=
self
.
client
.
post
(
url
,
{
'action'
:
'Enroll multiple students'
,
'multiple_students'
:
'test2_1@student.com, test2_2@student.com'
})
#Check the page output
self
.
assertContains
(
response
,
'<td>test2_1@student.com</td>'
)
self
.
assertContains
(
response
,
'<td>test2_2@student.com</td>'
)
self
.
assertContains
(
response
,
'<td>user does not exist, enrollment allowed, pending with auto enrollment off</td>'
)
#Check the enrollmentallowed db entries
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
'test2_1@student.com'
,
course_id
=
course
.
id
)
self
.
assertEqual
(
0
,
cea
[
0
]
.
auto_enroll
)
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
'test2_2@student.com'
,
course_id
=
course
.
id
)
self
.
assertEqual
(
0
,
cea
[
0
]
.
auto_enroll
)
#Check there is no enrollment db entry other than for the setup instructor and students
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
)
self
.
assertEqual
(
3
,
len
(
ce
))
#Create and activate student accounts with same email
self
.
student
=
'test2_1@student.com'
self
.
password
=
'bar'
self
.
create_account
(
's2_1'
,
self
.
student
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
self
.
student
=
'test2_2@student.com'
self
.
create_account
(
's2_2'
,
self
.
student
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
#Check students are not enrolled
user
=
User
.
objects
.
get
(
email
=
'test2_1@student.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
0
,
len
(
ce
))
user
=
User
.
objects
.
get
(
email
=
'test2_2@student.com'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
course_id
=
course
.
id
,
user
=
user
)
self
.
assertEqual
(
0
,
len
(
ce
))
def
test_get_and_clean_student_list
(
self
):
'''
Clean user input test
'''
string
=
"abc@test.com, def@test.com ghi@test.com
\n
\n
jkl@test.com "
cleaned_string
,
cleaned_string_lc
=
get_and_clean_student_list
(
string
)
self
.
assertEqual
(
cleaned_string
,
[
'abc@test.com'
,
'def@test.com'
,
'ghi@test.com'
,
'jkl@test.com'
])
lms/djangoapps/instructor/views.py
View file @
0b4e03e8
...
@@ -227,13 +227,13 @@ def instructor_dashboard(request, course_id):
...
@@ -227,13 +227,13 @@ def instructor_dashboard(request, course_id):
if
student_to_reset
is
not
None
:
if
student_to_reset
is
not
None
:
# find the module in question
# find the module in question
if
'/'
not
in
problem_to_reset
:
# allow state of modules other than problem to be reset
if
'/'
not
in
problem_to_reset
:
# allow state of modules other than problem to be reset
problem_to_reset
=
"problem/"
+
problem_to_reset
# but problem is the default
problem_to_reset
=
"problem/"
+
problem_to_reset
# but problem is the default
try
:
try
:
(
org
,
course_name
,
_
)
=
course_id
.
split
(
"/"
)
(
org
,
course_name
,
_
)
=
course_id
.
split
(
"/"
)
module_state_key
=
"i4x://"
+
org
+
"/"
+
course_name
+
"/"
+
problem_to_reset
module_state_key
=
"i4x://"
+
org
+
"/"
+
course_name
+
"/"
+
problem_to_reset
module_to_reset
=
StudentModule
.
objects
.
get
(
student_id
=
student_to_reset
.
id
,
module_to_reset
=
StudentModule
.
objects
.
get
(
student_id
=
student_to_reset
.
id
,
course_id
=
course_id
,
course_id
=
course_id
,
module_state_key
=
module_state_key
)
module_state_key
=
module_state_key
)
msg
+=
"Found module to reset. "
msg
+=
"Found module to reset. "
except
Exception
:
except
Exception
:
msg
+=
"<font color='red'>Couldn't find module with that urlname. </font>"
msg
+=
"<font color='red'>Couldn't find module with that urlname. </font>"
...
@@ -257,19 +257,18 @@ def instructor_dashboard(request, course_id):
...
@@ -257,19 +257,18 @@ def instructor_dashboard(request, course_id):
module_to_reset
.
state
=
json
.
dumps
(
problem_state
)
module_to_reset
.
state
=
json
.
dumps
(
problem_state
)
module_to_reset
.
save
()
module_to_reset
.
save
()
track
.
views
.
server_track
(
request
,
track
.
views
.
server_track
(
request
,
'{instructor} reset attempts from {old_attempts} to 0 for {student} on problem {problem} in {course}'
.
format
(
'{instructor} reset attempts from {old_attempts} to 0 for {student} on problem {problem} in {course}'
.
format
(
old_attempts
=
old_number_of_attempts
,
old_attempts
=
old_number_of_attempts
,
student
=
student_to_reset
,
student
=
student_to_reset
,
problem
=
module_to_reset
.
module_state_key
,
problem
=
module_to_reset
.
module_state_key
,
instructor
=
request
.
user
,
instructor
=
request
.
user
,
course
=
course_id
),
course
=
course_id
),
{},
{},
page
=
'idashboard'
)
page
=
'idashboard'
)
msg
+=
"<font color='green'>Module state successfully reset!</font>"
msg
+=
"<font color='green'>Module state successfully reset!</font>"
except
:
except
:
msg
+=
"<font color='red'>Couldn't reset module state. </font>"
msg
+=
"<font color='red'>Couldn't reset module state. </font>"
elif
"Get link to student's progress page"
in
action
:
elif
"Get link to student's progress page"
in
action
:
unique_student_identifier
=
request
.
POST
.
get
(
'unique_student_identifier'
,
''
)
unique_student_identifier
=
request
.
POST
.
get
(
'unique_student_identifier'
,
''
)
try
:
try
:
...
@@ -279,12 +278,12 @@ def instructor_dashboard(request, course_id):
...
@@ -279,12 +278,12 @@ def instructor_dashboard(request, course_id):
student_to_reset
=
User
.
objects
.
get
(
username
=
unique_student_identifier
)
student_to_reset
=
User
.
objects
.
get
(
username
=
unique_student_identifier
)
progress_url
=
reverse
(
'student_progress'
,
kwargs
=
{
'course_id'
:
course_id
,
'student_id'
:
student_to_reset
.
id
})
progress_url
=
reverse
(
'student_progress'
,
kwargs
=
{
'course_id'
:
course_id
,
'student_id'
:
student_to_reset
.
id
})
track
.
views
.
server_track
(
request
,
track
.
views
.
server_track
(
request
,
'{instructor} requested progress page for {student} in {course}'
.
format
(
'{instructor} requested progress page for {student} in {course}'
.
format
(
student
=
student_to_reset
,
student
=
student_to_reset
,
instructor
=
request
.
user
,
instructor
=
request
.
user
,
course
=
course_id
),
course
=
course_id
),
{},
{},
page
=
'idashboard'
)
page
=
'idashboard'
)
msg
+=
"<a href='{0}' target='_blank'> Progress page for username: {1} with email address: {2}</a>."
.
format
(
progress_url
,
student_to_reset
.
username
,
student_to_reset
.
email
)
msg
+=
"<a href='{0}' target='_blank'> Progress page for username: {1} with email address: {2}</a>."
.
format
(
progress_url
,
student_to_reset
.
username
,
student_to_reset
.
email
)
except
:
except
:
msg
+=
"<font color='red'>Couldn't find student with that username. </font>"
msg
+=
"<font color='red'>Couldn't find student with that username. </font>"
...
@@ -312,6 +311,7 @@ def instructor_dashboard(request, course_id):
...
@@ -312,6 +311,7 @@ def instructor_dashboard(request, course_id):
msg2
,
rg_stud_data
=
_do_remote_gradebook
(
request
.
user
,
course
,
'get-membership'
)
msg2
,
rg_stud_data
=
_do_remote_gradebook
(
request
.
user
,
course
,
'get-membership'
)
datatable
=
{
'header'
:
[
'Student email'
,
'Match?'
]}
datatable
=
{
'header'
:
[
'Student email'
,
'Match?'
]}
rg_students
=
[
x
[
'email'
]
for
x
in
rg_stud_data
[
'retdata'
]]
rg_students
=
[
x
[
'email'
]
for
x
in
rg_stud_data
[
'retdata'
]]
def
domatch
(
x
):
def
domatch
(
x
):
return
'yes'
if
x
.
email
in
rg_students
else
'No'
return
'yes'
if
x
.
email
in
rg_students
else
'No'
datatable
[
'data'
]
=
[[
x
.
email
,
domatch
(
x
)]
for
x
in
stud_data
[
'students'
]]
datatable
[
'data'
]
=
[[
x
.
email
,
domatch
(
x
)]
for
x
in
stud_data
[
'students'
]]
...
@@ -347,7 +347,6 @@ def instructor_dashboard(request, course_id):
...
@@ -347,7 +347,6 @@ def instructor_dashboard(request, course_id):
msg2
,
_
=
_do_remote_gradebook
(
request
.
user
,
course
,
'post-grades'
,
files
=
files
)
msg2
,
_
=
_do_remote_gradebook
(
request
.
user
,
course
,
'post-grades'
,
files
=
files
)
msg
+=
msg2
msg
+=
msg2
#----------------------------------------
#----------------------------------------
# Admin
# Admin
...
@@ -413,6 +412,7 @@ def instructor_dashboard(request, course_id):
...
@@ -413,6 +412,7 @@ def instructor_dashboard(request, course_id):
profkeys
=
[
'name'
,
'language'
,
'location'
,
'year_of_birth'
,
'gender'
,
'level_of_education'
,
profkeys
=
[
'name'
,
'language'
,
'location'
,
'year_of_birth'
,
'gender'
,
'level_of_education'
,
'mailing_address'
,
'goals'
]
'mailing_address'
,
'goals'
]
datatable
=
{
'header'
:
[
'username'
,
'email'
]
+
profkeys
}
datatable
=
{
'header'
:
[
'username'
,
'email'
]
+
profkeys
}
def
getdat
(
u
):
def
getdat
(
u
):
p
=
u
.
profile
p
=
u
.
profile
return
[
u
.
username
,
u
.
email
]
+
[
getattr
(
p
,
x
,
''
)
for
x
in
profkeys
]
return
[
u
.
username
,
u
.
email
]
+
[
getattr
(
p
,
x
,
''
)
for
x
in
profkeys
]
...
@@ -421,9 +421,8 @@ def instructor_dashboard(request, course_id):
...
@@ -421,9 +421,8 @@ def instructor_dashboard(request, course_id):
datatable
[
'title'
]
=
'Student profile data for course
%
s'
%
course_id
datatable
[
'title'
]
=
'Student profile data for course
%
s'
%
course_id
return
return_csv
(
'profiledata_
%
s.csv'
%
course_id
,
datatable
)
return
return_csv
(
'profiledata_
%
s.csv'
%
course_id
,
datatable
)
elif
'Download CSV of all responses to problem'
in
action
:
elif
'Download CSV of all responses to problem'
in
action
:
problem_to_dump
=
request
.
POST
.
get
(
'problem_to_dump'
,
''
)
problem_to_dump
=
request
.
POST
.
get
(
'problem_to_dump'
,
''
)
if
problem_to_dump
[
-
4
:]
==
".xml"
:
if
problem_to_dump
[
-
4
:]
==
".xml"
:
problem_to_dump
=
problem_to_dump
[:
-
4
]
problem_to_dump
=
problem_to_dump
[:
-
4
]
...
@@ -441,7 +440,7 @@ def instructor_dashboard(request, course_id):
...
@@ -441,7 +440,7 @@ def instructor_dashboard(request, course_id):
if
smdat
:
if
smdat
:
datatable
=
{
'header'
:
[
'username'
,
'state'
]}
datatable
=
{
'header'
:
[
'username'
,
'state'
]}
datatable
[
'data'
]
=
[
[
x
.
student
.
username
,
x
.
state
]
for
x
in
smdat
]
datatable
[
'data'
]
=
[
[
x
.
student
.
username
,
x
.
state
]
for
x
in
smdat
]
datatable
[
'title'
]
=
'Student state for problem
%
s'
%
problem_to_dump
datatable
[
'title'
]
=
'Student state for problem
%
s'
%
problem_to_dump
return
return_csv
(
'student_state_from_
%
s.csv'
%
problem_to_dump
,
datatable
)
return
return_csv
(
'student_state_from_
%
s.csv'
%
problem_to_dump
,
datatable
)
...
@@ -478,7 +477,6 @@ def instructor_dashboard(request, course_id):
...
@@ -478,7 +477,6 @@ def instructor_dashboard(request, course_id):
msg
+=
_list_course_forum_members
(
course_id
,
rolename
,
datatable
)
msg
+=
_list_course_forum_members
(
course_id
,
rolename
,
datatable
)
track
.
views
.
server_track
(
request
,
'list-{0}'
.
format
(
rolename
),
{},
page
=
'idashboard'
)
track
.
views
.
server_track
(
request
,
'list-{0}'
.
format
(
rolename
),
{},
page
=
'idashboard'
)
elif
action
==
'Remove forum admin'
:
elif
action
==
'Remove forum admin'
:
uname
=
request
.
POST
[
'forumadmin'
]
uname
=
request
.
POST
[
'forumadmin'
]
msg
+=
_update_forum_role_membership
(
uname
,
course
,
FORUM_ROLE_ADMINISTRATOR
,
FORUM_ROLE_REMOVE
)
msg
+=
_update_forum_role_membership
(
uname
,
course
,
FORUM_ROLE_ADMINISTRATOR
,
FORUM_ROLE_REMOVE
)
...
@@ -536,35 +534,17 @@ def instructor_dashboard(request, course_id):
...
@@ -536,35 +534,17 @@ def instructor_dashboard(request, course_id):
datatable
[
'data'
]
=
[[
x
.
email
]
for
x
in
ceaset
]
datatable
[
'data'
]
=
[[
x
.
email
]
for
x
in
ceaset
]
datatable
[
'title'
]
=
action
datatable
[
'title'
]
=
action
elif
action
==
'Enroll
student
'
:
elif
action
==
'Enroll
multiple students
'
:
student
=
request
.
POST
.
get
(
'enstudent'
,
''
)
students
=
request
.
POST
.
get
(
'multiple_students'
,
''
)
ret
=
_do_enroll_students
(
course
,
course_id
,
student
)
auto_enroll
=
bool
(
request
.
POST
.
get
(
'auto_enroll'
))
ret
=
_do_enroll_students
(
course
,
course_id
,
students
,
auto_enroll
=
auto_enroll
)
datatable
=
ret
[
'datatable'
]
datatable
=
ret
[
'datatable'
]
elif
action
==
'Un-enroll student'
:
elif
action
==
'Unenroll multiple students'
:
student
=
request
.
POST
.
get
(
'enstudent'
,
''
)
datatable
=
{}
isok
=
False
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
course_id
=
course_id
,
email
=
student
)
if
cea
:
cea
.
delete
()
msg
+=
"Un-enrolled student with email '
%
s'"
%
student
isok
=
True
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
:
if
not
isok
:
msg
+=
"Error! Failed to un-enroll student with email '
%
s'
\n
"
%
student
msg
+=
str
(
err
)
+
'
\n
'
elif
action
==
'Enroll multiple students'
:
students
=
request
.
POST
.
get
(
'
enroll_multiple
'
,
''
)
students
=
request
.
POST
.
get
(
'
multiple_students
'
,
''
)
ret
=
_do_
enroll_students
(
course
,
course_id
,
students
)
ret
=
_do_
unenroll_students
(
course_id
,
students
)
datatable
=
ret
[
'datatable'
]
datatable
=
ret
[
'datatable'
]
elif
action
==
'List sections available in remote gradebook'
:
elif
action
==
'List sections available in remote gradebook'
:
...
@@ -586,7 +566,6 @@ def instructor_dashboard(request, course_id):
...
@@ -586,7 +566,6 @@ def instructor_dashboard(request, course_id):
ret
=
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
overload
)
ret
=
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
overload
)
datatable
=
ret
[
'datatable'
]
datatable
=
ret
[
'datatable'
]
#----------------------------------------
#----------------------------------------
# psychometrics
# psychometrics
...
@@ -606,9 +585,9 @@ def instructor_dashboard(request, course_id):
...
@@ -606,9 +585,9 @@ def instructor_dashboard(request, course_id):
logs and swallows errors.
logs and swallows errors.
"""
"""
url
=
settings
.
ANALYTICS_SERVER_URL
+
\
url
=
settings
.
ANALYTICS_SERVER_URL
+
\
"get?aname={}&course_id={}&apikey={}"
.
format
(
analytics_name
,
"get?aname={}&course_id={}&apikey={}"
.
format
(
analytics_name
,
course_id
,
course_id
,
settings
.
ANALYTICS_API_KEY
)
settings
.
ANALYTICS_API_KEY
)
try
:
try
:
res
=
requests
.
get
(
url
)
res
=
requests
.
get
(
url
)
except
Exception
:
except
Exception
:
...
@@ -667,7 +646,7 @@ def instructor_dashboard(request, course_id):
...
@@ -667,7 +646,7 @@ def instructor_dashboard(request, course_id):
'cohorts_ajax_url'
:
reverse
(
'cohorts'
,
kwargs
=
{
'course_id'
:
course_id
}),
'cohorts_ajax_url'
:
reverse
(
'cohorts'
,
kwargs
=
{
'course_id'
:
course_id
}),
'analytics_results'
:
analytics_results
,
'analytics_results'
:
analytics_results
,
}
}
return
render_to_response
(
'courseware/instructor_dashboard.html'
,
context
)
return
render_to_response
(
'courseware/instructor_dashboard.html'
,
context
)
...
@@ -830,7 +809,7 @@ def _add_or_remove_user_group(request, username_or_email, group, group_title, ev
...
@@ -830,7 +809,7 @@ def _add_or_remove_user_group(request, username_or_email, group, group_title, ev
action
=
"Added"
if
do_add
else
"Removed"
action
=
"Added"
if
do_add
else
"Removed"
prep
=
"to"
if
do_add
else
"from"
prep
=
"to"
if
do_add
else
"from"
msg
=
'<font color="green">{action} {0} {prep} {1} group = {2}</font>'
.
format
(
user
,
group_title
,
group
.
name
,
msg
=
'<font color="green">{action} {0} {prep} {1} group = {2}</font>'
.
format
(
user
,
group_title
,
group
.
name
,
action
=
action
,
prep
=
prep
)
action
=
action
,
prep
=
prep
)
if
do_add
:
if
do_add
:
user
.
groups
.
add
(
group
)
user
.
groups
.
add
(
group
)
else
:
else
:
...
@@ -956,7 +935,7 @@ def gradebook(request, course_id):
...
@@ -956,7 +935,7 @@ def gradebook(request, course_id):
'grade_summary'
:
student_grades
(
student
,
request
,
course
),
'grade_summary'
:
student_grades
(
student
,
request
,
course
),
'realname'
:
student
.
profile
.
name
,
'realname'
:
student
.
profile
.
name
,
}
}
for
student
in
enrolled_students
]
for
student
in
enrolled_students
]
return
render_to_response
(
'courseware/gradebook.html'
,
{
return
render_to_response
(
'courseware/gradebook.html'
,
{
'students'
:
student_info
,
'students'
:
student_info
,
...
@@ -982,17 +961,11 @@ def grade_summary(request, course_id):
...
@@ -982,17 +961,11 @@ def grade_summary(request, course_id):
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# enrollment
# enrollment
def
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
False
):
def
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
False
,
auto_enroll
=
False
):
"""Do the actual work of enrolling multiple students, presented as a string
"""Do the actual work of enrolling multiple students, presented as a string
of emails separated by commas or returns"""
of emails separated by commas or returns"""
new_students
=
split_by_comma_and_whitespace
(
students
)
new_students
,
new_students_lc
=
get_and_clean_student_list
(
students
)
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
)
status
=
dict
([
x
,
'unprocessed'
]
for
x
in
new_students
)
if
overload
:
# delete all but staff
if
overload
:
# delete all but staff
...
@@ -1012,27 +985,35 @@ def _do_enroll_students(course, course_id, students, overload=False):
...
@@ -1012,27 +985,35 @@ def _do_enroll_students(course, course_id, students, overload=False):
try
:
try
:
user
=
User
.
objects
.
get
(
email
=
student
)
user
=
User
.
objects
.
get
(
email
=
student
)
except
User
.
DoesNotExist
:
except
User
.
DoesNotExist
:
# user not signed up yet, put in pending enrollment allowed table
if
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
student
,
course_id
=
course_id
):
#User not signed up yet, put in pending enrollment allowed table
status
[
student
]
=
'user does not exist, enrollment already allowed, pending'
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
student
,
course_id
=
course_id
)
#If enrollmentallowed already exists, update auto_enroll flag to however it was set in UI
#Will be 0 or 1 records as there is a unique key on email + course_id
if
cea
:
cea
[
0
]
.
auto_enroll
=
auto_enroll
cea
[
0
]
.
save
()
status
[
student
]
=
'user does not exist, enrollment already allowed, pending with auto enrollment '
\
+
(
'on'
if
auto_enroll
else
'off'
)
continue
continue
cea
=
CourseEnrollmentAllowed
(
email
=
student
,
course_id
=
course_id
)
cea
=
CourseEnrollmentAllowed
(
email
=
student
,
course_id
=
course_id
,
auto_enroll
=
auto_enroll
)
cea
.
save
()
cea
.
save
()
status
[
student
]
=
'user does not exist, enrollment allowed, pending
'
status
[
student
]
=
'user does not exist, enrollment allowed, pending
with auto enrollment '
+
(
'on'
if
auto_enroll
else
'off'
)
continue
continue
if
CourseEnrollment
.
objects
.
filter
(
user
=
user
,
course_id
=
course_id
):
if
CourseEnrollment
.
objects
.
filter
(
user
=
user
,
course_id
=
course_id
):
status
[
student
]
=
'already enrolled'
status
[
student
]
=
'already enrolled'
continue
continue
try
:
try
:
n
ce
=
CourseEnrollment
(
user
=
user
,
course_id
=
course_id
)
ce
=
CourseEnrollment
(
user
=
user
,
course_id
=
course_id
)
n
ce
.
save
()
ce
.
save
()
status
[
student
]
=
'added'
status
[
student
]
=
'added'
except
:
except
:
status
[
student
]
=
'rejected'
status
[
student
]
=
'rejected'
datatable
=
{
'header'
:
[
'StudentEmail'
,
'action'
]}
datatable
=
{
'header'
:
[
'StudentEmail'
,
'action'
]}
datatable
[
'data'
]
=
[[
x
,
status
[
x
]]
for
x
in
s
tatus
]
datatable
[
'data'
]
=
[[
x
,
status
[
x
]]
for
x
in
s
orted
(
status
)
]
datatable
[
'title'
]
=
'Enrollment of students'
datatable
[
'title'
]
=
'Enrollment of students'
def
sf
(
stat
):
def
sf
(
stat
):
...
@@ -1044,39 +1025,69 @@ def _do_enroll_students(course, course_id, students, overload=False):
...
@@ -1044,39 +1025,69 @@ def _do_enroll_students(course, course_id, students, overload=False):
return
data
return
data
@ensure_csrf_cookie
#Unenrollment
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
def
_do_unenroll_students
(
course_id
,
students
):
def
enroll_students
(
request
,
course_id
):
"""Do the actual work of un-enrolling multiple students, presented as a string
"""Allows a staff member to enroll students in a course.
of emails separated by commas or returns"""
This is a short-term hack for Berkeley courses launching fall
old_students
,
old_students_lc
=
get_and_clean_student_list
(
students
)
2012. In the long term, we would like functionality like this, but
status
=
dict
([
x
,
'unprocessed'
]
for
x
in
old_students
)
we would like both the instructor and the student to agree. Right
now, this allows any instructor to add students to their course,
which we do not want.
It is poorly written and poorly tested, but it's designed to be
for
student
in
old_students
:
stripped out.
"""
course
=
get_course_with_access
(
request
.
user
,
course_id
,
'staff'
)
isok
=
False
existing_students
=
[
ce
.
user
.
email
for
ce
in
CourseEnrollment
.
objects
.
filter
(
course_id
=
course_id
)]
cea
=
CourseEnrollmentAllowed
.
objects
.
filter
(
course_id
=
course_id
,
email
=
student
)
#Will be 0 or 1 records as there is a unique key on email + course_id
if
cea
:
cea
[
0
]
.
delete
()
status
[
student
]
=
"un-enrolled"
isok
=
True
try
:
user
=
User
.
objects
.
get
(
email
=
student
)
except
User
.
DoesNotExist
:
continue
new_students
=
request
.
POST
.
get
(
'new_students'
)
ce
=
CourseEnrollment
.
objects
.
filter
(
user
=
user
,
course_id
=
course_id
)
ret
=
_do_enroll_students
(
course
,
course_id
,
new_students
)
#Will be 0 or 1 records as there is a unique key on user + course_id
added_students
=
ret
[
'added'
]
if
ce
:
rejected_students
=
ret
[
'rejected'
]
try
:
ce
[
0
]
.
delete
()
status
[
student
]
=
"un-enrolled"
except
Exception
as
err
:
if
not
isok
:
status
[
student
]
=
"Error! Failed to un-enroll"
datatable
=
{
'header'
:
[
'StudentEmail'
,
'action'
]}
datatable
[
'data'
]
=
[[
x
,
status
[
x
]]
for
x
in
sorted
(
status
)]
datatable
[
'title'
]
=
'Un-enrollment of students'
data
=
dict
(
datatable
=
datatable
)
return
data
return
render_to_response
(
"enroll_students.html"
,
{
'course'
:
course_id
,
'existing_students'
:
existing_students
,
'added_students'
:
added_students
,
'rejected_students'
:
rejected_students
,
'debug'
:
new_students
})
def
get_and_clean_student_list
(
students
):
"""
Separate out individual student email from the comma, or space separated string.
In:
students: string coming from the input text area
Return:
students: list of cleaned student emails
students_lc: list of lower case cleaned student emails
"""
students
=
split_by_comma_and_whitespace
(
students
)
students
=
[
str
(
s
.
strip
())
for
s
in
students
]
students
=
[
s
for
s
in
students
if
s
!=
''
]
students_lc
=
[
x
.
lower
()
for
x
in
students
]
return
students
,
students_lc
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# answer distribution
# answer distribution
def
get_answers_distribution
(
request
,
course_id
):
def
get_answers_distribution
(
request
,
course_id
):
"""
"""
Get the distribution of answers for all graded problems in the course.
Get the distribution of answers for all graded problems in the course.
...
@@ -1168,5 +1179,5 @@ def dump_grading_context(course):
...
@@ -1168,5 +1179,5 @@ def dump_grading_context(course):
msg
+=
"
%
s (format=
%
s, Assignment=
%
s
%
s)
\n
"
%
(
s
.
display_name
,
format
,
aname
,
notes
)
msg
+=
"
%
s (format=
%
s, Assignment=
%
s
%
s)
\n
"
%
(
s
.
display_name
,
format
,
aname
,
notes
)
msg
+=
"all descriptors:
\n
"
msg
+=
"all descriptors:
\n
"
msg
+=
"length=
%
d
\n
"
%
len
(
gc
[
'all_descriptors'
])
msg
+=
"length=
%
d
\n
"
%
len
(
gc
[
'all_descriptors'
])
msg
=
'<pre>
%
s</pre>'
%
msg
.
replace
(
'<'
,
'<'
)
msg
=
'<pre>
%
s</pre>'
%
msg
.
replace
(
'<'
,
'<'
)
return
msg
return
msg
lms/templates/courseware/instructor_dashboard.html
View file @
0b4e03e8
...
@@ -296,9 +296,6 @@ function goto( mode)
...
@@ -296,9 +296,6 @@ function goto( mode)
<p>
<p>
<input
type=
"submit"
name=
"action"
value=
"List enrolled students"
>
<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"
>
<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"
>
<hr
width=
"40%"
style=
"align:left"
>
<hr
width=
"40%"
style=
"align:left"
>
%if settings.MITX_FEATURES.get('REMOTE_GRADEBOOK_URL','') and instructor_access:
%if settings.MITX_FEATURES.get('REMOTE_GRADEBOOK_URL','') and instructor_access:
...
@@ -320,9 +317,13 @@ function goto( mode)
...
@@ -320,9 +317,13 @@ function goto( mode)
%endif
%endif
<p>
Add students: enter emails, separated by new lines or commas;
</p>
<p>
Enroll or un-enroll one or many students: enter emails, separated by new lines or commas;
</p>
<textarea
rows=
"6"
cols=
"70"
name=
"enroll_multiple"
></textarea>
<textarea
rows=
"6"
cols=
"70"
name=
"multiple_students"
></textarea>
<p>
<input
type=
"checkbox"
name=
"auto_enroll"
>
Auto-enroll students when they activate
<input
type=
"submit"
name=
"action"
value=
"Enroll multiple students"
>
<input
type=
"submit"
name=
"action"
value=
"Enroll multiple students"
>
<p>
<input
type=
"submit"
name=
"action"
value=
"Unenroll multiple students"
>
%endif
%endif
...
...
lms/urls.py
View file @
0b4e03e8
...
@@ -267,8 +267,6 @@ if settings.COURSEWARE_ENABLED:
...
@@ -267,8 +267,6 @@ if settings.COURSEWARE_ENABLED:
'instructor.views.gradebook'
,
name
=
'gradebook'
),
'instructor.views.gradebook'
,
name
=
'gradebook'
),
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/grade_summary$'
,
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/grade_summary$'
,
'instructor.views.grade_summary'
,
name
=
'grade_summary'
),
'instructor.views.grade_summary'
,
name
=
'grade_summary'
),
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/enroll_students$'
,
'instructor.views.enroll_students'
,
name
=
'enroll_students'
),
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading$'
,
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading$'
,
'open_ended_grading.views.staff_grading'
,
name
=
'staff_grading'
),
'open_ended_grading.views.staff_grading'
,
name
=
'staff_grading'
),
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/get_next$'
,
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/get_next$'
,
...
...
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