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
fef004f4
Commit
fef004f4
authored
May 31, 2012
by
Bridger Maxwell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Changed certificate schema to allow for pre-generated certificates.
parent
b05271c9
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
128 additions
and
12 deletions
+128
-12
djangoapps/certificates/migrations/0003_auto__add_field_generatedcertificate_enabled.py
+93
-0
djangoapps/certificates/models.py
+17
-3
djangoapps/certificates/views.py
+7
-3
djangoapps/courseware/views.py
+9
-5
templates/profile.html
+2
-1
No files found.
djangoapps/certificates/migrations/0003_auto__add_field_generatedcertificate_enabled.py
0 → 100644
View file @
fef004f4
# -*- 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 'GeneratedCertificate.enabled'
db
.
add_column
(
'certificates_generatedcertificate'
,
'enabled'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
False
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Deleting field 'GeneratedCertificate.enabled'
db
.
delete_column
(
'certificates_generatedcertificate'
,
'enabled'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'about'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'avatar_type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'n'"
,
'max_length'
:
'1'
}),
'bronze'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'consecutive_days_visit_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'country'
:
(
'django_countries.fields.CountryField'
,
[],
{
'max_length'
:
'2'
,
'blank'
:
'True'
}),
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'date_of_birth'
:
(
'django.db.models.fields.DateField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'display_tag_filter_strategy'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'email_isvalid'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'email_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'null'
:
'True'
}),
'email_tag_filter_strategy'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'1'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'gold'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'gravatar'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ignored_tags'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'interesting_tags'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'last_seen'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'location'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'new_response_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'questions_per_page'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'10'
}),
'real_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'reputation'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'default'
:
'1'
}),
'seen_response_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'show_country'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'silver'
:
(
'django.db.models.fields.SmallIntegerField'
,
[],
{
'default'
:
'0'
}),
'status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'w'"
,
'max_length'
:
'2'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
}),
'website'
:
(
'django.db.models.fields.URLField'
,
[],
{
'max_length'
:
'200'
,
'blank'
:
'True'
})
},
'certificates.generatedcertificate'
:
{
'Meta'
:
{
'object_name'
:
'GeneratedCertificate'
},
'certificate_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
}),
'download_url'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'null'
:
'True'
}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'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'
})
}
}
complete_apps
=
[
'certificates'
]
\ No newline at end of file
djangoapps/certificates/models.py
View file @
fef004f4
...
@@ -3,6 +3,8 @@ from django.db import models
...
@@ -3,6 +3,8 @@ from django.db import models
'''
'''
Certificates are created for a student and an offering of a course.
When a certificate is generated, a unique ID is generated so that
When a certificate is generated, a unique ID is generated so that
the certificate can be verified later. The ID is a UUID4, so that
the certificate can be verified later. The ID is a UUID4, so that
it can't be easily guessed and so that it is unique. Even though
it can't be easily guessed and so that it is unique. Even though
...
@@ -10,7 +12,15 @@ we save these generated certificates (for later verification), we
...
@@ -10,7 +12,15 @@ we save these generated certificates (for later verification), we
also record the UUID so that if we regenerate the certificate it
also record the UUID so that if we regenerate the certificate it
will have the same UUID.
will have the same UUID.
Certificates are created for a student and an offering of a course.
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 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.
'''
'''
...
@@ -18,4 +28,8 @@ class GeneratedCertificate(models.Model):
...
@@ -18,4 +28,8 @@ class GeneratedCertificate(models.Model):
user
=
models
.
ForeignKey
(
User
,
db_index
=
True
)
user
=
models
.
ForeignKey
(
User
,
db_index
=
True
)
certificate_id
=
models
.
CharField
(
max_length
=
32
)
certificate_id
=
models
.
CharField
(
max_length
=
32
)
download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
download_url
=
models
.
CharField
(
max_length
=
128
,
null
=
True
)
\ No newline at end of file
# 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
)
\ No newline at end of file
djangoapps/certificates/views.py
View file @
fef004f4
...
@@ -50,16 +50,20 @@ def certificate_request(request):
...
@@ -50,16 +50,20 @@ def certificate_request(request):
'error'
:
error
}))
'error'
:
error
}))
# T
ODO: This method should be executed as an asynchronous task
# T
his method should only be called if the user has a grade and has requested a certificate
def
generate_certificate
(
user
,
grade
,
destination_email
):
def
generate_certificate
(
user
,
grade
,
destination_email
):
# Make sure to see the comments in models.GeneratedCertificate to read about the valid
# states for a GeneratedCertificate object
generated_certificate
=
None
generated_certificate
=
None
try
:
try
:
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
user
)
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
user
)
except
GeneratedCertificate
.
DoesNotExist
:
except
GeneratedCertificate
.
DoesNotExist
:
generated_certificate
=
GeneratedCertificate
(
user
=
user
,
certificate_id
=
uuid
.
uuid4
()
.
hex
)
generated_certificate
=
GeneratedCertificate
(
user
=
user
,
certificate_id
=
uuid
.
uuid4
()
.
hex
)
generated_certificate
.
save
()
generated_certificate
.
enabled
=
True
generated_certificate
.
save
()
certificate_id
=
generated_certificate
.
certificate_id
certificate_id
=
generated_certificate
.
certificate_id
log
.
debug
(
"Generating certificate for "
+
str
(
user
.
username
)
+
" with ID: "
+
certificate_id
)
log
.
debug
(
"Generating certificate for "
+
str
(
user
.
username
)
+
" with ID: "
+
certificate_id
)
...
...
djangoapps/courseware/views.py
View file @
fef004f4
...
@@ -88,15 +88,19 @@ def profile(request, student_id = None):
...
@@ -88,15 +88,19 @@ def profile(request, student_id = None):
if
settings
.
END_COURSE_ENABLED
:
if
settings
.
END_COURSE_ENABLED
:
took_survey
=
student_took_survey
(
user_info
)
took_survey
=
student_took_survey
(
user_info
)
generated_certificate
=
None
# certificate_requested determines if the student has requested a certificate
certificate_download_url
=
None
certificate_requested
=
False
certificate_requested
=
False
# certificate_download_url determines if the certificate has been generated
certificate_download_url
=
None
if
grade_sheet
[
'grade'
]:
if
grade_sheet
[
'grade'
]:
try
:
try
:
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
student
)
generated_certificate
=
GeneratedCertificate
.
objects
.
get
(
user
=
student
)
certificate_requested
=
True
#If enabled=False, it may have been pre-generated but not yet requested
certificate_download_url
=
generated_certificate
.
download_url
if
generated_certificate
.
enabled
:
certificate_requested
=
True
certificate_download_url
=
generated_certificate
.
download_url
except
GeneratedCertificate
.
DoesNotExist
:
except
GeneratedCertificate
.
DoesNotExist
:
#They haven't submited the request form
#They haven't submited the request form
certificate_requested
=
False
certificate_requested
=
False
...
...
templates/profile.html
View file @
fef004f4
...
@@ -156,6 +156,7 @@ $(function() {
...
@@ -156,6 +156,7 @@ $(function() {
}
}
$
(
"#cert_request"
).
html
(
"<h1>Certificate Request Received</h1><p>A certificate will be sent to the specified email in a short time.</p>"
);
$
(
"#cert_request"
).
html
(
"<h1>Certificate Request Received</h1><p>A certificate will be sent to the specified email in a short time.</p>"
);
$
(
".cert_request_link"
).
text
(
"Certificate is being generated..."
);
}
else
{
}
else
{
$
(
"#cert_request_error"
).
html
(
data
.
error
);
$
(
"#cert_request_error"
).
html
(
data
.
error
);
}
}
...
@@ -216,7 +217,7 @@ $(function() {
...
@@ -216,7 +217,7 @@ $(function() {
%if not certificate_requested:
%if not certificate_requested:
<a
rel=
"leanModal"
class=
"cert_request_link"
href=
"#cert_request"
>
Request Certificate
</a>
<a
rel=
"leanModal"
class=
"cert_request_link"
href=
"#cert_request"
>
Request Certificate
</a>
%elif certificate_download_url:
%elif certificate_download_url:
<a
href=
"${certificate_download_url}"
>
Download Certificate
</a>
<a
href=
"${certificate_download_url}"
target=
"_blank"
>
Download Certificate
</a>
%else:
%else:
<a
href=
"#"
>
Certificate is being generated...
</a>
<a
href=
"#"
>
Certificate is being generated...
</a>
%endif
%endif
...
...
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