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
22ed22d9
Commit
22ed22d9
authored
Oct 30, 2012
by
John Jarvis
Committed by
Carlos Andrés Rocha
Nov 09, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updating the certificate app for testing
Conflicts: lms/djangoapps/certificates/models.py
parent
d636d729
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
129 additions
and
262 deletions
+129
-262
lms/djangoapps/certificates/management/commands/ungenerated_certs.py
+59
-10
lms/djangoapps/certificates/models.py
+46
-113
lms/djangoapps/certificates/views.py
+24
-139
No files found.
lms/djangoapps/certificates/management/commands/ungenerated_certs.py
View file @
22ed22d9
from
django.utils.simplejson
import
dumps
from
django.core.management.base
import
BaseCommand
,
CommandError
from
certificates.models
import
GeneratedCertificate
from
courseware
import
grades
,
courses
from
django.contrib.auth.models
import
User
from
django.test.client
import
RequestFactory
from
profilehooks
import
profile
import
cProfile
from
pprint
import
pprint
from
capa.xqueue_interface
import
XQueueInterface
from
capa.xqueue_interface
import
make_xheader
from
django.conf
import
settings
from
requests.auth
import
HTTPBasicAuth
class
Command
(
BaseCommand
):
help
=
"""
This command finds all GeneratedCertificate objects that do not have a
certificate generated. These come into being when a user requests a
certificate, or when grade_all_students is called (for pre-generating
certificates).
This command finds all users that have not been graded
for a single course.
It returns a json formatted list of users and their user ids
"""
# @profile
def
_grade
(
self
,
student
,
request
,
course
):
grades
.
grade
(
student
,
request
,
course
)
def
handle
(
self
,
*
args
,
**
options
):
users
=
GeneratedCertificate
.
objects
.
filter
(
download_url
=
None
)
user_output
=
[{
'user_id'
:
user
.
user_id
,
'name'
:
user
.
name
}
for
user
in
users
]
self
.
stdout
.
write
(
dumps
(
user_output
)
+
"
\n
"
)
factory
=
RequestFactory
()
course_id
=
'BerkeleyX/CS169.1x/2012_Fall'
course
=
courses
.
get_course_by_id
(
course_id
)
if
settings
.
XQUEUE_INTERFACE
.
get
(
'basic_auth'
)
is
not
None
:
requests_auth
=
HTTPBasicAuth
(
*
settings
.
XQUEUE_INTERFACE
[
'basic_auth'
])
else
:
requests_auth
=
None
xqueue_interface
=
XQueueInterface
(
settings
.
XQUEUE_INTERFACE
[
'url'
],
settings
.
XQUEUE_INTERFACE
[
'django_auth'
],
requests_auth
,
)
header
=
make_xheader
(
'/certificate'
,
'foo'
,
'test-pull'
)
print
"Sending test message to queue"
xqueue_interface
.
send_to_queue
(
header
,
{
'test'
:
'foo'
})
#enrolled_students = User.objects.filter(
# courseenrollment__course_id=course_id).prefetch_related(
# "groups").order_by('username')
#generated_certificates = GeneratedCertificate.objects.filter(
# course_id=course_id)
#request = factory.get('/')
#student = User.objects.get(username='03199618')
#print "total students: {0}".format(len(enrolled_students))
#count = 0
#for student in enrolled_students:
# count += 1
# if count % 1000 == 0:
# print "{0}/{1}".format(count, len(enrolled_students))
# grades.grade(student, request, course)
#for student in enrolled_students:
# g = grades.grade(student, request, course)
# if g['grade'] is not None:
# print str(student)
# pprint(g)
# break
lms/djangoapps/certificates/models.py
View file @
22ed22d9
from
django.conf
import
settings
as
settings
from
django.contrib.auth.models
import
User
from
django.db
import
models
...
...
@@ -14,131 +12,66 @@ we save these generated certificates (for later verification), we
also record the UUID so that if we regenerate the certificate it
will have the same UUID.
If certificates are being generated on the fly, a GeneratedCertificate
should be created with the user, certificate_id, and enabled set
when a student requests a certificate. When the certificate has been
generated, the download_url should be set
.
Certificates are generated in batches by a cron job, when a
certificate is available for download the GeneratedCertificate
table is updated with information that will be displayed
on the course overview page
.
Certificates can also be pre-generated. In this case, the user,
certificate_id, and download_url are all set before the user does
anything. When the user requests the certificate, only enabled
needs to be set to true.
'''
class
GeneratedCertificate
(
models
.
Model
):
user
=
models
.
ForeignKey
(
User
,
db_index
=
True
)
# This is the name at the time of request
name
=
models
.
CharField
(
blank
=
True
,
max_length
=
255
)
certificate_id
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
default
=
None
)
graded_certificate_id
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
default
=
None
)
download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
graded_download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
grade
=
models
.
CharField
(
max_length
=
5
,
null
=
True
)
# enabled should only be true if the student has earned a grade in the course
# The student must have a grade and request a certificate for enabled to be True
enabled
=
models
.
BooleanField
(
default
=
False
)
class
RevokedCertificate
(
models
.
Model
):
"""
This model is for when a GeneratedCertificate must be regenerated. This model
contains all the same fields, to store a record of what the GeneratedCertificate
was before it was revoked (at which time all of it's information can change when
it is regenerated).
GeneratedCertificate may be deleted once they are revoked, and then created again.
For this reason, the only link between a GeneratedCertificate and RevokedCertificate
is that they share the same user.
"""
####-------------------New Fields--------------------####
explanation
=
models
.
TextField
(
blank
=
True
)
####---------Fields from GeneratedCertificate---------####
user
=
models
.
ForeignKey
(
User
,
db_index
=
True
)
# This is the name at the time of request
name
=
models
.
CharField
(
blank
=
True
,
max_length
=
255
)
certificate_id
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
default
=
None
)
graded_certificate_id
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
default
=
None
)
download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
graded_download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
grade
=
models
.
CharField
(
max_length
=
5
,
null
=
True
)
user
=
models
.
ForeignKey
(
User
)
course_id
=
models
.
CharField
(
max_length
=
255
,
default
=
False
)
certificate_id
=
models
.
CharField
(
max_length
=
32
,
default
=
False
)
graded_certificate_id
=
models
.
CharField
(
max_length
=
32
,
default
=
False
)
download_url
=
models
.
CharField
(
max_length
=
128
,
default
=
False
)
graded_download_url
=
models
.
CharField
(
max_length
=
128
,
default
=
False
)
grade
=
models
.
CharField
(
max_length
=
5
,
default
=
False
)
key
=
models
.
CharField
(
max_length
=
32
,
default
=
False
)
# enabled should only be true if the student has earned a passing grade
# in the course.
enabled
=
models
.
BooleanField
(
default
=
False
)
def
revoke_certificate
(
certificate
,
explanation
):
"""
This method takes a GeneratedCertificate. It records its information from the certificate
into a RevokedCertificate, and then marks the certificate as needing regenerating.
When the new certificiate is regenerated it will have new IDs and download URLS.
Once this method has been called, it is safe to delete the certificate, or modify the
certificate's name or grade until it has been generated again.
"""
revoked
=
RevokedCertificate
(
user
=
certificate
.
user
,
name
=
certificate
.
name
,
certificate_id
=
certificate
.
certificate_id
,
graded_certificate_id
=
certificate
.
graded_certificate_id
,
download_url
=
certificate
.
download_url
,
graded_download_url
=
certificate
.
graded_download_url
,
grade
=
certificate
.
grade
,
enabled
=
certificate
.
enabled
)
revoked
.
explanation
=
explanation
certificate
.
certificate_id
=
None
certificate
.
graded_certificate_id
=
None
certificate
.
download_url
=
None
certificate
.
graded_download_url
=
None
certificate
.
save
()
revoked
.
save
()
def
certificate_state_for_student
(
student
,
grade
):
def
certificate_state_for_student
(
student
):
'''
This returns a dictionary with a key for state, and other information.
The state is one of the
following:
This returns a dictionary with a key for state, and other information.
The state is one of the
following:
unavailable - A student is not eligible for a certificate.
requestable - A student is eligible to request a certificate
generating - A student has requested a certificate, but it is not generated yet.
downloadable - The certificate has been requested and is available for download.
unavailable - A student is not eligible for a certificate.
generating - A student has requested a certificate,
but it is not generated yet.
downloadable - The certificate has been requested and is
available for download.
If the state is "downloadable", the dictionary also contains "download_url" and "graded_download_url".
If the state is "downloadable", the dictionary also contains
"download_url" and "graded_download_url".
'''
if
grade
:
#TODO: Remove the following after debugging
if
settings
.
DEBUG_SURVEY
:
return
{
'state'
:
'requestable'
}
try
:
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
student
)
if
generated_certificate
.
enabled
:
if
generated_certificate
.
download_url
:
return
{
'state'
:
'downloadable'
,
'download_url'
:
generated_certificate
.
download_url
,
'graded_download_url'
:
generated_certificate
.
graded_download_url
}
else
:
return
{
'state'
:
'generating'
}
try
:
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
student
)
if
generated_certificate
.
enabled
:
if
generated_certificate
.
download_url
:
return
{
'state'
:
'downloadable'
,
'download_url'
:
generated_certificate
.
download_url
,
'graded_download_url'
:
generated_certificate
.
graded_download_url
}
else
:
# If enabled=False, it may have been pre-generated but not yet requested
# Our output will be the same as if the GeneratedCertificate did not exist
pass
except
GeneratedCertificate
.
DoesNotExist
:
return
{
'state'
:
'generating'
}
else
:
# If enabled=False, there is no certificate available
# Our output will be the same as if the
# GeneratedCertificate did not exist
pass
return
{
'state'
:
'requestable'
}
else
:
# No grade, no certificate. No exceptions
return
{
'state'
:
'unavailable'
}
except
GeneratedCertificate
.
DoesNotExist
:
pass
return
{
'state'
:
'unavailable'
}
lms/djangoapps/certificates/views.py
View file @
22ed22d9
import
json
import
logging
import
uuid
from
django.conf
import
settings
from
django.contrib.auth.decorators
import
login_required
from
django.core.mail
import
send_mail
from
django.http
import
Http404
,
HttpResponse
from
django.shortcuts
import
redirect
import
courseware.grades
as
grades
from
certificates.models
import
GeneratedCertificate
,
certificate_state_for_student
,
revoke_certificate
from
mitxmako.shortcuts
import
render_to_response
,
render_to_string
from
student.models
import
UserProfile
#TODO: Finish migrating these changes from stable
# from student.survey_questions import exit_survey_list_for_student
# from student.views import student_took_survey, record_exit_survey
from
certificates.models
import
GeneratedCertificate
from
pprint
import
pprint
log
=
logging
.
getLogger
(
"mitx.certificates"
)
@login_required
def
certificate_request
(
request
):
''' Attempt to send a certificate. '''
if
not
settings
.
END_COURSE_ENABLED
:
raise
Http404
def
update_certificate
(
request
):
"""
Will update GeneratedCertificate for a new certificate or
modify an existing certificate entry.
"""
if
request
.
method
==
"POST"
:
honor_code_verify
=
request
.
POST
.
get
(
'cert_request_honor_code_verify'
,
'false'
)
name_verify
=
request
.
POST
.
get
(
'cert_request_name_verify'
,
'false'
)
id_verify
=
request
.
POST
.
get
(
'cert_request_id_verify'
,
'false'
)
error
=
''
def
return_error
(
error
):
return
HttpResponse
(
json
.
dumps
({
'success'
:
False
,
'error'
:
error
}))
if
honor_code_verify
!=
'true'
:
error
+=
'Please verify that you have followed the honor code to receive a certificate. '
if
name_verify
!=
'true'
:
error
+=
'Please verify that your name is correct to receive a certificate. '
if
id_verify
!=
'true'
:
error
+=
'Please certify that you understand the unique ID on the certificate. '
if
len
(
error
)
>
0
:
return
return_error
(
error
)
survey_response
=
record_exit_survey
(
request
,
internal_request
=
True
)
if
not
survey_response
[
'success'
]:
return
return_error
(
survey_response
[
'error'
])
grade
=
None
student_gradesheet
=
grades
.
grade
(
request
.
user
,
request
,
course
)
grade
=
student_gradesheet
[
'grade'
]
if
not
grade
:
return
return_error
(
'You have not earned a grade in this course. '
)
generate_certificate
(
request
.
user
,
grade
)
return
HttpResponse
(
json
.
dumps
({
'success'
:
True
}))
else
:
#This is not a POST, we should render the page with the form
student_gradesheet
=
grades
.
grade
(
request
.
user
,
request
,
course
)
certificate_state
=
certificate_state_for_student
(
request
.
user
,
grade_sheet
[
'grade'
])
if
certificate_state
[
'state'
]
!=
"requestable"
:
return
redirect
(
"/profile"
)
user_info
=
UserProfile
.
objects
.
get
(
user
=
request
.
user
)
took_survey
=
student_took_survey
(
user_info
)
if
settings
.
DEBUG_SURVEY
:
took_survey
=
False
survey_list
=
[]
if
not
took_survey
:
survey_list
=
exit_survey_list_for_student
(
request
.
user
)
context
=
{
'certificate_state'
:
certificate_state
,
'took_survey'
:
took_survey
,
'survey_list'
:
survey_list
,
'name'
:
user_info
.
name
}
return
render_to_response
(
'cert_request.html'
,
context
)
# This method should only be called if the user has a grade and has requested a certificate
def
generate_certificate
(
user
,
grade
):
# Make sure to see the comments in models.GeneratedCertificate to read about the valid
# states for a GeneratedCertificate object
if
grade
and
user
.
is_active
:
generated_certificate
=
None
try
:
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
user
)
except
GeneratedCertificate
.
DoesNotExist
:
generated_certificate
=
GeneratedCertificate
(
user
=
user
)
generated_certificate
.
enabled
=
True
if
generated_certificate
.
graded_download_url
and
(
generated_certificate
.
grade
!=
grade
):
log
.
critical
(
u"A graded certificate has been pre-generated with the grade "
"of {gen_grade} but requested by user id {userid} with grade "
"{req_grade}! The download URLs were {graded_dl_url} and "
"{ungraded_dl_url}"
.
format
(
gen_grade
=
generated_certificate
.
grade
,
req_grade
=
grade
,
graded_dl_url
=
generated_certificate
.
graded_download_url
,
ungraded_dl_url
=
generated_certificate
.
download_url
,
userid
=
user
.
id
))
revoke_certificate
(
generated_certificate
,
"The grade on this certificate may be inaccurate."
)
user_name
=
UserProfile
.
objects
.
get
(
user
=
user
)
.
name
if
generated_certificate
.
download_url
and
(
generated_certificate
.
name
!=
user_name
):
log
.
critical
(
u"A Certificate has been pre-generated with the name of "
"{gen_name} but current name is {user_name} (user id is "
"{userid})! The download URLs were {graded_dl_url} and "
"{ungraded_dl_url}"
.
format
(
gen_name
=
generated_certificate
.
name
.
encode
(
'utf-8'
),
user_name
=
user_name
.
encode
(
'utf-8'
),
graded_dl_url
=
generated_certificate
.
graded_download_url
,
ungraded_dl_url
=
generated_certificate
.
download_url
,
userid
=
user
.
id
))
revoke_certificate
(
generated_certificate
,
"The name on this certificate may be inaccurate."
)
generated_certificate
.
grade
=
grade
generated_certificate
.
name
=
user_name
generated_certificate
.
save
()
certificate_id
=
generated_certificate
.
certificate_id
log
.
debug
(
"Generating certificate for "
+
str
(
user
.
username
)
+
" with ID: "
+
str
(
certificate_id
))
# TODO: If the certificate was pre-generated, send the email that it is ready to download
if
certificate_state_for_student
(
user
,
grade
)[
'state'
]
==
"downloadable"
:
subject
=
render_to_string
(
'emails/certificate_ready_subject.txt'
,
{})
subject
=
''
.
join
(
subject
.
splitlines
())
message
=
render_to_string
(
'emails/certificate_ready.txt'
,
{})
res
=
send_mail
(
subject
,
message
,
settings
.
DEFAULT_FROM_EMAIL
,
[
user
.
email
,
])
else
:
log
.
warning
(
"Asked to generate a certificate for student "
+
str
(
user
.
username
)
+
" but with a grade of "
+
str
(
grade
)
+
" and active status "
+
str
(
user
.
is_active
))
pprint
(
request
)
# user = request.POST.get('user')
# try:
# generated_certificate = GeneratedCertificate.objects.get(
# key=key)
# except GeneratedCertificate.DoesNotExist:
# generated_certificate = GeneratedCertificate(user=user)
#
# enabled = request.POST.get('enabled')
# enabled = True if enabled == 'True' else False
# generated_certificate.grade = request.POST.get('grade')
# generated_certificate.download_url = request.POST.get('download_url')
# generated_certificate.graded_download_url = request.POST.get(
# 'graded_download_url')
# generated_certificate.course_id = request.POST.get('course_id')
# generated_certificate.enabled = enabled
# generated_certificate.save()
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